texture.monkey2 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. Namespace mojo.graphics
  2. Using std.resource
  3. #rem monkeydoc Texture flags.
  4. | TextureFlags | Description
  5. |:--------------|:-----------
  6. | Dynamic | Texture is frequently updated. This flag should be set if the texture contents are regularly updated and don't need to be preserved.
  7. #end
  8. Enum TextureFlags
  9. WrapS= $0001 'wrap works, but hidden for now...
  10. WrapT= $0002
  11. Unmanaged= $0004
  12. DisableMipmap= $0008
  13. RenderTarget= $0010
  14. WrapST= WrapS|WrapT
  15. Dynamic= Unmanaged|RenderTarget|DisableMipmap
  16. End
  17. #rem monkeydoc Texture filters.
  18. | TextureFlags | Description
  19. |:--------------|:-----------
  20. | Nearest | Textures are not filtered.
  21. | Linear | Textures are filtered when magnified.
  22. | Mipmap | Textures are filtered when magnified and minified.
  23. #end
  24. Enum TextureFilter
  25. None=0
  26. Nearest=1
  27. Linear
  28. Mipmap
  29. End
  30. #rem monkeydoc @hidden
  31. #end
  32. Class Texture Extends Resource
  33. Method New( pixmap:Pixmap,flags:TextureFlags )
  34. #If Not __DESKTOP_TARGET__
  35. Local tw:=Log2( pixmap.Width ),th:=Log2( pixmap.Height )
  36. If tw<>Round( tw ) Or th<>Round( th ) flags|=TextureFlags.DisableMipmap
  37. #Endif
  38. _rect=New Recti( 0,0,pixmap.Width,pixmap.Height )
  39. _format=pixmap.Format
  40. _flags=flags
  41. _filter=Null
  42. If _flags & TextureFlags.Unmanaged
  43. PastePixmap( pixmap,0,0 )
  44. Else
  45. AddDependancy( pixmap )
  46. _managed=pixmap
  47. Endif
  48. End
  49. Method New( width:Int,height:Int,format:PixelFormat,flags:TextureFlags )
  50. #If Not __DESKTOP_TARGET__
  51. Local tw:=Log2( width ),th:=Log2( height )
  52. If tw<>Round( tw ) Or th<>Round( th ) flags|=TextureFlags.DisableMipmap
  53. #Endif
  54. _rect=New Recti( 0,0,width,height )
  55. _format=format
  56. _flags=flags
  57. _filter=Null
  58. If Not (_flags & TextureFlags.Unmanaged)
  59. _managed=New Pixmap( width,height,format )
  60. _managed.Clear( Color.Magenta )
  61. AddDependancy( _managed )
  62. Endif
  63. End
  64. Property Rect:Recti()
  65. Return _rect
  66. End
  67. Property Width:Int()
  68. Return _rect.Width
  69. End
  70. Property Height:Int()
  71. Return _rect.Height
  72. End
  73. Property Format:PixelFormat()
  74. Return _format
  75. End
  76. Method PastePixmap( pixmap:Pixmap,x:Int,y:Int )
  77. If _managed
  78. _managed.Paste( pixmap,x,y )
  79. _dirty|=Dirty.TexImage|Dirty.Mipmaps
  80. Else
  81. glPushTexture2d( GLTexture )
  82. glPixelStorei( GL_UNPACK_ALIGNMENT,1 )
  83. If pixmap.Pitch=pixmap.Width*pixmap.Depth
  84. glTexSubImage2D( GL_TEXTURE_2D,0,x,y,pixmap.Width,pixmap.Height,glFormat( _format ),GL_UNSIGNED_BYTE,pixmap.Data )
  85. Else
  86. For Local iy:=0 Until pixmap.Height
  87. glTexSubImage2D( GL_TEXTURE_2D,0,x,y+iy,pixmap.Width,1,glFormat( _format ),GL_UNSIGNED_BYTE,pixmap.PixelPtr( 0,iy ) )
  88. Next
  89. Endif
  90. glPopTexture2d()
  91. _dirty|=Dirty.Mipmaps
  92. Endif
  93. End
  94. Function Load:Texture( path:String,flags:TextureFlags )
  95. Local pixmap:=Pixmap.Load( path,,True )
  96. If Not pixmap Return Null
  97. Local texture:=New Texture( pixmap,flags )
  98. texture.OnDiscarded+=Lambda()
  99. pixmap.Discard()
  100. End
  101. Return texture
  102. End
  103. Function LoadNormal:Texture( path:String,textureFlags:TextureFlags,specular:String,specularScale:Float=1,flipNormalY:Bool=True )
  104. path=RealPath( path )
  105. specular=specular ? RealPath( specular ) Else ""
  106. Local pnorm:=Pixmap.Load( path,,False )
  107. If Not pnorm Return Null
  108. Local pspec:=Pixmap.Load( specular )
  109. Local yxor:=flipNormalY ? $ff00 Else 0
  110. If pspec And pspec.Width=pnorm.Width And pspec.Height=pnorm.Height
  111. For Local y:=0 Until pnorm.Height
  112. For Local x:=0 Until pnorm.Width
  113. Local n:=pnorm.GetPixelARGB( x,y ) ~ yxor
  114. Local s:=(pspec.GetPixelARGB( x,y ) Shr 16) & $ff
  115. n=n & $ffffff00 | Clamp( Int( specularScale * s ),0,255 )
  116. pnorm.SetPixelARGB( x,y,n )
  117. Next
  118. Next
  119. Else
  120. Local g:=Clamp( Int( specularScale * 255.0 ),1,255 )
  121. For Local y:=0 Until pnorm.Height
  122. For Local x:=0 Until pnorm.Width
  123. Local n:=pnorm.GetPixelARGB( x,y ) ~ yxor
  124. n=n & $ffffff00 | g
  125. pnorm.SetPixelARGB( x,y,n )
  126. Next
  127. Next
  128. Endif
  129. If pspec pspec.Discard()
  130. Local texture:=New Texture( pnorm,Null )
  131. Return texture
  132. End
  133. Function ColorTexture:Texture( color:Color )
  134. Local texture:=_colorTextures[color]
  135. If Not texture
  136. Local pixmap:=New Pixmap( 1,1 )
  137. pixmap.Clear( color )
  138. texture=New Texture( pixmap,Null )
  139. _colorTextures[color]=texture
  140. Endif
  141. Return texture
  142. End
  143. #rem monkeydoc @hidden
  144. #end
  145. Property GLTexture:GLuint()
  146. If _texSeq=glGraphicsSeq And Not _dirty Return _glTexture
  147. If _discarded Return 0
  148. If _texSeq=glGraphicsSeq
  149. glPushTexture2d( _glTexture )
  150. Else
  151. _texSeq=glGraphicsSeq
  152. _dirty=Dirty.All
  153. glGenTextures( 1,Varptr _glTexture )
  154. glPushTexture2d( _glTexture )
  155. If _flags & TextureFlags.WrapS
  156. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT )
  157. Else
  158. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE )
  159. Endif
  160. If _flags & TextureFlags.WrapT
  161. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT )
  162. Else
  163. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE )
  164. Endif
  165. Endif
  166. If _dirty & Dirty.Filter
  167. 'mag filter
  168. If _filter=TextureFilter.Mipmap Or _filter=TextureFilter.Linear
  169. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR )
  170. Else
  171. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
  172. Endif
  173. 'min filter
  174. If _filter=TextureFilter.Mipmap
  175. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR )
  176. Else If _filter=TextureFilter.Linear
  177. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR )
  178. Else
  179. glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST )
  180. Endif
  181. Endif
  182. If _dirty & Dirty.TexImage
  183. glTexImage2D( GL_TEXTURE_2D,0,glFormat( _format ),Width,Height,0,glFormat( _format ),GL_UNSIGNED_BYTE,Null )
  184. If _managed
  185. glPixelStorei( GL_UNPACK_ALIGNMENT,1 )
  186. If _managed.Pitch=_managed.Width*_managed.Depth
  187. glTexSubImage2D( GL_TEXTURE_2D,0,0,0,_managed.Width,_managed.Height,glFormat( _format ),GL_UNSIGNED_BYTE,_managed.Data )
  188. Else
  189. For Local iy:=0 Until Height
  190. glTexSubImage2D( GL_TEXTURE_2D,0,0,iy,Width,1,glFormat( _format ),GL_UNSIGNED_BYTE,_managed.PixelPtr( 0,iy ) )
  191. Next
  192. Endif
  193. glFlush() 'macos nvidia bug!
  194. Else
  195. Local tmp:=New Pixmap( Width,1,Format )
  196. tmp.Clear( Color.Red )
  197. For Local iy:=0 Until Height
  198. glTexSubImage2D( GL_TEXTURE_2D,0,0,iy,Width,1,glFormat( _format ),GL_UNSIGNED_BYTE,tmp.Data )
  199. Next
  200. glFlush() 'macos nvidia bug!
  201. tmp.Discard()
  202. Endif
  203. Endif
  204. If _dirty & Dirty.Mipmaps
  205. If _filter=TextureFilter.Mipmap
  206. glGenerateMipmap( GL_TEXTURE_2D )
  207. _mipsDirty&=~Dirty.Mipmaps
  208. Else
  209. _mipsDirty|=Dirty.Mipmaps 'mipmap still dirty!
  210. Endif
  211. End
  212. _dirty=Null
  213. glPopTexture2d()
  214. Return _glTexture
  215. End
  216. #rem monkeydoc @hidden
  217. #end
  218. Property GLFramebuffer:GLuint()
  219. If _discarded Return 0
  220. If _fbSeq=glGraphicsSeq Return _glFramebuffer
  221. glGenFramebuffers( 1,Varptr _glFramebuffer )
  222. glPushFramebuffer( _glFramebuffer )
  223. glBindFramebuffer( GL_FRAMEBUFFER,_glFramebuffer )
  224. glFramebufferTexture2D( GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,GLTexture,0 )
  225. If glCheckFramebufferStatus( GL_FRAMEBUFFER )<>GL_FRAMEBUFFER_COMPLETE RuntimeError( "Incomplete framebuffer" )
  226. glPopFramebuffer()
  227. _fbSeq=glGraphicsSeq
  228. Return _glFramebuffer
  229. End
  230. #rem monkeydoc @hidden
  231. #end
  232. Method Bind( unit:Int,filter:TextureFilter )
  233. If _discarded Print "Binding discarded texture!"
  234. If _boundSeq<>glGraphicsSeq
  235. _boundSeq=glGraphicsSeq
  236. For Local i:=0 Until 8
  237. _bound[i]=0
  238. Next
  239. Endif
  240. If filter<>_filter
  241. If filter=TextureFilter.Mipmap And (_flags & TextureFlags.DisableMipmap) filter=TextureFilter.Linear
  242. If filter<>_filter
  243. If filter=TextureFilter.Mipmap _dirty|=_mipsDirty
  244. _dirty|=Dirty.Filter
  245. _filter=filter
  246. Endif
  247. Endif
  248. Local gltex:=GLTexture
  249. If gltex=_bound[unit] Return
  250. _bound[unit]=gltex
  251. glActiveTexture( GL_TEXTURE0+unit )
  252. glBindTexture( GL_TEXTURE_2D,gltex )
  253. End
  254. #rem monkeydoc @hidden
  255. #end
  256. Method Modified( r:Recti )
  257. If _managed
  258. glPixelStorei( GL_PACK_ALIGNMENT,1 )
  259. glReadPixels( r.X,r.Y,r.Width,r.Height,GL_RGBA,GL_UNSIGNED_BYTE,_managed.PixelPtr( r.X,r.Y ) )
  260. Endif
  261. _dirty|=Dirty.Mipmaps
  262. End
  263. Protected
  264. #rem monkeydoc @hidden
  265. #end
  266. Method OnDiscard() Override
  267. If _texSeq=glGraphicsSeq
  268. For Local i:=0 Until 8
  269. If _bound[i]=_glTexture _bound[i]=0
  270. Next
  271. glDeleteTextures( 1,Varptr _glTexture )
  272. Endif
  273. If _fbSeq=glGraphicsSeq
  274. glDeleteFramebuffers( 1,Varptr _glFramebuffer )
  275. Endif
  276. _texSeq=0
  277. _fbSeq=0
  278. _glTexture=0
  279. _glFramebuffer=0
  280. _discarded=True
  281. End
  282. Private
  283. Enum Dirty
  284. Filter= 1
  285. TexImage= 2
  286. Mipmaps= 4
  287. All= 7
  288. End
  289. Global _boundSeq:Int
  290. Global _bound:=New GLuint[8]
  291. Field _rect:Recti
  292. Field _format:PixelFormat
  293. Field _flags:TextureFlags
  294. Field _managed:Pixmap
  295. Field _discarded:Bool
  296. Field _texSeq:Int
  297. Field _dirty:Dirty
  298. Field _mipsDirty:Dirty
  299. Field _filter:TextureFilter
  300. Field _glTexture:GLuint
  301. Field _fbSeq:Int
  302. Field _glFramebuffer:GLuint
  303. Global _colorTextures:Map<Color,Texture>
  304. End
  305. Class ResourceManager Extension
  306. Method OpenTexture:Texture( path:String,flags:TextureFlags=Null )
  307. Local slug:="Texture:name="+StripDir( StripExt( path ) )+"&flags="+Int( flags )
  308. Local texture:=Cast<Texture>( OpenResource( slug ) )
  309. If texture Return texture
  310. Local pixmap:=OpenPixmap( path,Null,True )
  311. If pixmap texture=New Texture( pixmap,flags )
  312. AddResource( slug,texture )
  313. Return texture
  314. End
  315. End