texture.monkey2 7.9 KB

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