image.monkey2 13 KB

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