image.monkey2 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. Namespace mojo.graphics
  2. Using std.resource
  3. #rem monkeydoc The Image class.
  4. An image is a rectangular array of pixels that can be drawn using one of the [[Canvas.DrawImage]] methods.
  5. You can load an image from a file using one of the [[Load]], [[LoadBump]] or [[LoadLight]] functions.
  6. #end
  7. Class Image Extends Resource
  8. #rem monkeydoc Creates a new Image.
  9. New( pixmap,... ) Creates an image from an existing pixmap.
  10. New( width,height,... ) Creates an image that can be rendered to using a canvas.
  11. New( image,... ) Creates an image from within an 'atlas' image.
  12. Note: `textureFlags` should be null for static images or TextureFlags.Dynamic for dynamic images.
  13. @param pixmap Source image.
  14. @param textureFlags Image texture flags.
  15. @param shader Image shader.
  16. @param image Source pixmap.
  17. @param rect Source rect.
  18. @param x,y,width,height Source rect
  19. @param width,height Image size.
  20. #end
  21. Method New( pixmap:Pixmap,textureFlags:TextureFlags=Null,shader:Shader=Null )
  22. Local texture:=New Texture( pixmap,textureFlags )
  23. Init( texture,texture.Rect,shader )
  24. AddDependancy( texture )
  25. End
  26. Method New( width:Int,height:Int,textureFlags:TextureFlags=Null,shader:Shader=Null )
  27. Local texture:=New Texture( width,height,PixelFormat.RGBA32,textureFlags )
  28. Init( texture,texture.Rect,shader )
  29. AddDependancy( texture )
  30. End
  31. Method New( image:Image )
  32. Init( image._textures[0],image._rect,image._shader )
  33. image.AddDependancy( Self )
  34. For Local i:=1 Until 4
  35. SetTexture( i,image.GetTexture( i ) )
  36. Next
  37. BlendMode=image.BlendMode
  38. TextureFilter=image.TextureFilter
  39. LightDepth=image.LightDepth
  40. Handle=image.Handle
  41. Scale=image.Scale
  42. Color=image.Color
  43. End
  44. Method New( image:Image,rect:Recti )
  45. Init( image._textures[0],rect+image._rect.Origin,image._shader )
  46. image.AddDependancy( Self )
  47. For Local i:=1 Until 4
  48. SetTexture( i,image.GetTexture( i ) )
  49. Next
  50. BlendMode=image.BlendMode
  51. TextureFilter=image.TextureFilter
  52. LightDepth=image.LightDepth
  53. Handle=image.Handle
  54. Scale=image.Scale
  55. Color=image.Color
  56. End
  57. Method New( image:Image,x:Int,y:Int,width:Int,height:Int )
  58. Self.New( image,New Recti( x,y,x+width,y+height ) )
  59. End
  60. #rem monkeydoc @hidden
  61. #end
  62. Method New( texture:Texture,shader:Shader=Null )
  63. Init( texture,texture.Rect,shader )
  64. End
  65. #rem monkeydoc @hidden
  66. #end
  67. Method New( texture:Texture,rect:Recti,shader:Shader=Null )
  68. Init( texture,rect,shader )
  69. End
  70. #rem monkeydoc The image's primary texture.
  71. #end
  72. Property Texture:Texture()
  73. Return _textures[0]
  74. Setter( texture:Texture )
  75. SetTexture( 0,texture )
  76. End
  77. #rem monkeydoc The image's texture rect.
  78. Describes the rect the image occupies within its primary texture.
  79. #end
  80. Property Rect:Recti()
  81. Return _rect
  82. End
  83. #rem monkeydoc The image handle.
  84. Image handle values are fractional, where 0,0 is the top-left of the image and 1,1 is the bottom-right.
  85. #end
  86. Property Handle:Vec2f()
  87. Return _handle
  88. Setter( handle:Vec2f )
  89. _handle=handle
  90. UpdateVertices()
  91. End
  92. #rem monkeydoc The image scale.
  93. The scale property provides a simple way to 'pre-scale' an image.
  94. For images with a constant scale, Scaling an image this way is faster than using one of the 'scale' parameters of [[Canvas.DrawImage]].
  95. #end
  96. Property Scale:Vec2f()
  97. Return _scale
  98. Setter( scale:Vec2f )
  99. _scale=scale
  100. UpdateVertices()
  101. End
  102. #rem monkeydoc The image blend mode.
  103. The blend mode used to draw the image.
  104. If set to BlendMode.None, the canvas blend mode is used instead.
  105. Defaults to BlendMode.None.
  106. #end
  107. Property BlendMode:BlendMode()
  108. Return _blendMode
  109. Setter( blendMode:BlendMode )
  110. _blendMode=blendMode
  111. End
  112. #rem monkeydoc The image texture filter.
  113. The texture flags used to draw the image.
  114. If set to TextureFilter.None, the canvas texture filter is used instead.
  115. Defaults to TextureFilter.None
  116. #end
  117. Property TextureFilter:TextureFilter()
  118. Return _textureFilter
  119. Setter( filter:TextureFilter )
  120. _textureFilter=filter
  121. End
  122. #rem monkeydoc The image color.
  123. The color used to draw the image.
  124. Image color is multiplied by canvas color to achieve the final rendering color.
  125. Defaults to white.
  126. #end
  127. Property Color:Color()
  128. Return _color
  129. Setter( color:Color )
  130. _color=color
  131. _material.SetVector( "mx2_ImageColor",_color )
  132. End
  133. #rem monkeydoc The image light depth.
  134. #end
  135. Property LightDepth:Float()
  136. Return _lightDepth
  137. Setter( depth:Float )
  138. _lightDepth=depth
  139. _material.SetScalar( "mx2_LightDepth",_lightDepth )
  140. End
  141. #rem monkeydoc Shadow caster attached to image.
  142. #end
  143. Property ShadowCaster:ShadowCaster()
  144. Return _shadowCaster
  145. Setter( shadowCaster:ShadowCaster )
  146. _shadowCaster=shadowCaster
  147. End
  148. #rem monkeydoc The image bounds.
  149. The bounds rect represents the actual image vertices used when the image is drawn.
  150. Image bounds are affected by [[Scale]] and [[Handle]], and can be used for simple collision detection.
  151. #end
  152. Property Bounds:Rectf()
  153. Return _bounds
  154. End
  155. #rem monkeydoc Image bounds width.
  156. #end
  157. Property Width:Float()
  158. Return _bounds.Width
  159. End
  160. #rem monkeydoc Image bounds height.
  161. #end
  162. Property Height:Float()
  163. Return _bounds.Height
  164. End
  165. #rem monkeydoc Image bounds radius.
  166. #end
  167. Property Radius:Float()
  168. Return _radius
  169. End
  170. #rem monkeydoc Image shader.
  171. #end
  172. Property Shader:Shader()
  173. Return _shader
  174. End
  175. #rem monkeydoc Image material.
  176. #end
  177. Property Material:UniformBlock()
  178. Return _material
  179. End
  180. #rem monkeydoc @hidden Image vertices.
  181. #end
  182. Property Vertices:Rectf()
  183. Return _vertices
  184. End
  185. #rem monkeydoc @hidden Image texture coorinates.
  186. #end
  187. Property TexCoords:Rectf()
  188. Return _texCoords
  189. End
  190. #rem monkeydoc @hidden Sets an image texture.
  191. #end
  192. Method SetTexture( index:Int,texture:Texture )
  193. _textures[index]=texture
  194. _material.SetTexture( "mx2_ImageTexture"+index,texture )
  195. End
  196. #rem monkeydoc @hidden gets an image texture.
  197. #end
  198. Method GetTexture:Texture( index:Int )
  199. Return _textures[index]
  200. End
  201. #rem monkeydoc Loads an image from file.
  202. #end
  203. Function Load:Image( path:String,shader:Shader=Null )
  204. Local pixmap:=Pixmap.Load( path,Null,True )
  205. If Not pixmap Return Null
  206. If Not shader shader=mojo.graphics.Shader.GetShader( "sprite" )
  207. Local image:=New Image( pixmap,Null,shader )
  208. image.OnDiscarded+=Lambda()
  209. pixmap.Discard()
  210. End
  211. Return image
  212. End
  213. #rem monkeydoc Loads a bump image from file(s).
  214. `diffuse`, `normal` and `specular` are filepaths of the diffuse, normal and specular image files respectively.
  215. `specular` can be null, in which case `specularScale` is used for the specular component. Otherwise, `specularScale` is used to modulate the red component of the specular texture.
  216. #end
  217. Function LoadBump:Image( diffuse:String,normal:String,specular:String,specularScale:Float=1,flipNormalY:Bool=True,shader:Shader=Null )
  218. Local texture1:=graphics.Texture.LoadNormal( normal,Null,specular,specularScale,flipNormalY )
  219. If Not texture1 Return Null
  220. Local texture0:=graphics.Texture.Load( diffuse,Null )
  221. If Not texture0
  222. Local pdiff:=New Pixmap( texture1.Width,texture1.Height,PixelFormat.I8 )
  223. pdiff.Clear( std.graphics.Color.White )
  224. texture0=New graphics.Texture( pdiff,Null )
  225. Endif
  226. If Not shader shader=graphics.Shader.GetShader( "bump" )
  227. Local image:=New Image( texture0,texture0.Rect,shader )
  228. image.SetTexture( 1,texture1 )
  229. image.OnDiscarded+=Lambda()
  230. If texture0 texture0.Discard()
  231. If texture1 texture1.Discard()
  232. End
  233. Return image
  234. End
  235. #rem monkeydoc Loads a light image from file.
  236. #end
  237. Function LoadLight:Image( path:String,shader:Shader=Null )
  238. Local pixmap:=Pixmap.Load( path )
  239. If Not pixmap Return Null
  240. If Not shader shader=mojo.graphics.Shader.GetShader( "light" )
  241. Select pixmap.Format
  242. Case PixelFormat.IA16,PixelFormat.RGBA32
  243. pixmap.PremultiplyAlpha()
  244. Case PixelFormat.A8
  245. Local tpixmap:=pixmap
  246. pixmap=pixmap.Convert( PixelFormat.IA16 )
  247. tpixmap.Discard()
  248. 'Copy A->I
  249. For Local y:=0 Until pixmap.Height
  250. Local p:=pixmap.PixelPtr( 0,y )
  251. For Local x:=0 Until pixmap.Width
  252. p[0]=p[1]
  253. p+=2
  254. Next
  255. Next
  256. Case PixelFormat.I8
  257. Local tpixmap:=pixmap
  258. pixmap=pixmap.Convert( PixelFormat.IA16 )
  259. tpixmap.Discard()
  260. 'Copy I->A
  261. For Local y:=0 Until pixmap.Height
  262. Local p:=pixmap.PixelPtr( 0,y )
  263. For Local x:=0 Until pixmap.Width
  264. p[1]=p[0]
  265. p+=2
  266. Next
  267. Next
  268. Case PixelFormat.RGB24
  269. Local tpixmap:=pixmap
  270. pixmap=pixmap.Convert( PixelFormat.RGBA32 )
  271. tpixmap.Discard()
  272. 'Copy Max(R,G,B)->A
  273. For Local y:=0 Until pixmap.Height
  274. Local p:=pixmap.PixelPtr( 0,y )
  275. For Local x:=0 Until pixmap.Width
  276. p[3]=Max( Max( p[0],p[1] ),p[2] )
  277. p+=4
  278. Next
  279. Next
  280. End
  281. Local texture:=New Texture( pixmap,Null )
  282. Local image:=New Image( texture,shader )
  283. image.OnDiscarded+=Lambda()
  284. pixmap.Discard()
  285. End
  286. Return image
  287. End
  288. Private
  289. Field _shader:Shader
  290. Field _material:UniformBlock
  291. Field _textures:=New Texture[4]
  292. Field _blendMode:BlendMode
  293. Field _textureFilter:TextureFilter
  294. Field _color:Color
  295. Field _lightDepth:Float
  296. Field _shadowCaster:ShadowCaster
  297. Field _rect:Recti
  298. Field _handle:Vec2f
  299. Field _scale:Vec2f
  300. Field _vertices:Rectf
  301. Field _texCoords:Rectf
  302. Field _bounds:Rectf
  303. Field _radius:Float
  304. Method Init( texture:Texture,rect:Recti,shader:Shader )
  305. If Not shader shader=Shader.GetShader( "sprite" )
  306. _rect=rect
  307. _shader=shader
  308. _material=New UniformBlock
  309. AddDependancy( _material )
  310. SetTexture( 0,texture )
  311. BlendMode=BlendMode.None
  312. TextureFilter=TextureFilter.None
  313. Color=Color.White
  314. LightDepth=100
  315. Handle=New Vec2f( 0 )
  316. Scale=New Vec2f( 1 )
  317. UpdateVertices()
  318. UpdateTexCoords()
  319. End
  320. Method UpdateVertices()
  321. _vertices.min.x=Float(_rect.Width)*(0-_handle.x)*_scale.x
  322. _vertices.min.y=Float(_rect.Height)*(0-_handle.y)*_scale.y
  323. _vertices.max.x=Float(_rect.Width)*(1-_handle.x)*_scale.x
  324. _vertices.max.y=Float(_rect.Height)*(1-_handle.y)*_scale.y
  325. _bounds.min.x=Min( _vertices.min.x,_vertices.max.x )
  326. _bounds.max.x=Max( _vertices.min.x,_vertices.max.x )
  327. _bounds.min.y=Min( _vertices.min.y,_vertices.max.y )
  328. _bounds.max.y=Max( _vertices.min.y,_vertices.max.y )
  329. _radius=_bounds.min.x*_bounds.min.x+_bounds.min.y*_bounds.min.y
  330. _radius=Max( _radius,_bounds.max.x*_bounds.max.x+_bounds.min.y*_bounds.min.y )
  331. _radius=Max( _radius,_bounds.max.x*_bounds.max.x+_bounds.max.y*_bounds.max.y )
  332. _radius=Max( _radius,_bounds.min.x*_bounds.min.x+_bounds.max.y*_bounds.max.y )
  333. _radius=Sqrt( _radius )
  334. End
  335. Method UpdateTexCoords()
  336. _texCoords.min.x=Float(_rect.min.x)/_textures[0].Width
  337. _texCoords.min.y=Float(_rect.min.y)/_textures[0].Height
  338. _texCoords.max.x=Float(_rect.max.x)/_textures[0].Width
  339. _texCoords.max.y=Float(_rect.max.y)/_textures[0].Height
  340. End
  341. End
  342. Class ResourceManager Extension
  343. Method OpenImage:Image( path:String,shader:Shader=Null )
  344. Local slug:="Image:name="+StripDir( StripExt( path ) )+"&shader="+(shader ? shader.Name Else "null")
  345. Local image:=Cast<Image>( OpenResource( slug ) )
  346. If image Return image
  347. Local texture:=OpenTexture( path,Null )
  348. If texture image=New Image( texture,shader )
  349. AddResource( slug,image )
  350. Return image
  351. End
  352. End