image.monkey2 12 KB

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