pixmap.monkey2 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478
  1. Namespace std.graphics
  2. Using std.resource
  3. #rem monkeydoc Pixmaps allow you to store and manipulate rectangular blocks of pixel data.
  4. A pixmap contains a block of memory used to store a rectangular array of pixels.
  5. #end
  6. Class Pixmap Extends Resource
  7. #rem monkeydoc Creates a new pixmap.
  8. When you have finished with the pixmap, you should call its inherited [[Resource.Discard]] method.
  9. @param width The width of the pixmap in pixels.
  10. @param height The height of the pixmap in pixels.
  11. @param format The pixmap format.
  12. @param data A pointer to the pixmap data.
  13. @param pitch The pitch of the data.
  14. #end
  15. Method New( width:Int,height:Int,format:PixelFormat=PixelFormat.RGBA32 )
  16. ' Print "New pixmap1, width="+width+", height="+height
  17. Local depth:=PixelFormatDepth( format )
  18. Local pitch:=width*depth
  19. Local data:=Cast<UByte Ptr>( libc.malloc( pitch*height ) )
  20. _width=width
  21. _height=height
  22. _format=format
  23. _depth=depth
  24. _data=data
  25. _pitch=pitch
  26. OnDiscarded+=Lambda()
  27. libc.free( _data )
  28. _data=Null
  29. End
  30. End
  31. Method New( width:Int,height:Int,format:PixelFormat,data:UByte Ptr,pitch:Int )
  32. ' Print "New pixmap2, width="+width+", height="+height
  33. Local depth:=PixelFormatDepth( format )
  34. _width=width
  35. _height=height
  36. _format=format
  37. _depth=depth
  38. _data=data
  39. _pitch=pitch
  40. End
  41. #rem monkeydoc The pixmap width.
  42. #end
  43. Property Width:Int()
  44. Return _width
  45. End
  46. #rem monkeydoc The pixmap height.
  47. #end
  48. Property Height:Int()
  49. Return _height
  50. End
  51. #rem monkeydoc The pixmap format.
  52. #end
  53. Property Format:PixelFormat()
  54. Return _format
  55. End
  56. #rem monkeydoc The pixmap depth.
  57. The number of bytes per pixel.
  58. #end
  59. Property Depth:Int()
  60. Return _depth
  61. End
  62. #rem monkeydoc True if pixmap format includes alpha.
  63. #end
  64. Property HasAlpha:Bool()
  65. Select _format
  66. Case PixelFormat.A8,PixelFormat.IA16,PixelFormat.RGBA32
  67. Return True
  68. End
  69. Return False
  70. End
  71. #rem monkeydoc The raw pixmap data.
  72. #end
  73. Property Data:UByte Ptr()
  74. Return _data
  75. End
  76. #rem monkeydoc The pixmap pitch.
  77. This is the number of bytes between one row of pixels in the pixmap and the next.
  78. #end
  79. Property Pitch:Int()
  80. Return _pitch
  81. End
  82. #rem monkeydoc Gets a pointer to a pixel in the pixmap.
  83. @param x the x coordinate of the pixel.
  84. @param y the y coordinate of the pixel.
  85. @return the address of the pixel at `x`, `y`.
  86. #end
  87. Method PixelPtr:UByte Ptr( x:Int,y:Int )
  88. Return _data + y*_pitch + x*_depth
  89. End
  90. #rem monkeydoc Sets a pixel to a color.
  91. Sets the pixel at `x`, `y` to `pixel`.
  92. In debug builds, a runtime error will occur if the pixel coordinates lie outside of the pixmap area.
  93. @param x The x coordinate of the pixel.
  94. @param y The y coordinate of the pixel.
  95. @param color The color to set the pixel to.
  96. #end
  97. Method SetPixel( x:Int,y:Int,color:Color )
  98. DebugAssert( x>=0 And y>=0 And x<_width And y<_height )
  99. Local p:=PixelPtr( x,y )
  100. Select _format
  101. Case Format.A8
  102. p[0]=color.a * 255
  103. Case Format.I8
  104. p[0]=color.r * 255
  105. Case Format.IA16
  106. p[0]=color.r * 255
  107. p[1]=color.a * 255
  108. Case Format.RGB24
  109. p[0]=color.r * 255
  110. p[1]=color.g * 255
  111. p[2]=color.b * 255
  112. Case Format.RGBA32
  113. p[0]=color.r * 255
  114. p[1]=color.g * 255
  115. p[2]=color.b * 255
  116. p[3]=color.a * 255
  117. Default
  118. Assert( False )
  119. End
  120. End
  121. #rem monkeydoc Gets the color of a pixel.
  122. Gets the pixel at `x`, `y` and returns it in ARGB format.
  123. In debug builds, a runtime error will occur if the pixel coordinates lie outside of the pixmap area.
  124. @param x The x coordinate of the pixel.
  125. @param y The y coordinate of the pixel.
  126. @return The color of the pixel at `x`, `y`.
  127. #end
  128. Method GetPixel:Color( x:Int,y:Int )
  129. DebugAssert( x>=0 And y>=0 And x<_width And y<_height )
  130. Local p:=PixelPtr( x,y )
  131. Select _format
  132. Case Format.A8
  133. Return New Color( 0,0,0,p[0]/255.0 )
  134. Case Format.I8
  135. Local i:=p[0]/255.0
  136. Return New Color( i,i,i,1 )
  137. Case Format.IA16
  138. Local i:=p[0]/255.0
  139. Return New Color( i,i,i,p[1]/255.0 )
  140. Case Format.RGB24
  141. Return New Color( p[0]/255.0,p[1]/255.0,p[2]/255.0,1 )
  142. Case Format.RGBA32
  143. Return New Color( p[0]/255.0,p[1]/255.0,p[2]/255.0,p[3]/255.0 )
  144. Default
  145. Assert( False )
  146. End
  147. Return Color.None
  148. End
  149. #rem monkeydoc Sets a pixel to an ARGB color.
  150. Sets the pixel at `x`, `y` to `pixel`.
  151. In debug builds, a runtime error will occur if the pixel coordinates lie outside of the pixmap area.
  152. @param x The x coordinate of the pixel.
  153. @param y The y coordinate of the pixel.
  154. @param color The pixel to set in ARGB format.
  155. #end
  156. Method SetPixelARGB( x:Int,y:Int,color:UInt )
  157. DebugAssert( x>=0 And y>=0 And x<_width And y<_height )
  158. Local p:=PixelPtr( x,y )
  159. Select _format
  160. Case Format.A8
  161. p[0]=color Shr 24
  162. Case Format.I8
  163. p[0]=color Shr 16
  164. Case Format.IA16
  165. p[0]=color Shr 24
  166. p[1]=color Shr 16
  167. Case Format.RGB24
  168. p[0]=color Shr 16
  169. p[1]=color Shr 8
  170. p[2]=color
  171. Case Format.RGBA32
  172. p[0]=color Shr 16
  173. p[1]=color Shr 8
  174. p[2]=color
  175. p[3]=color Shr 24
  176. Default
  177. Assert( False )
  178. End
  179. End
  180. #rem monkeydoc Gets the ARGB color of a pixel.
  181. Get the pixel at `x`, `y` and returns it in ARGB format.
  182. @param x the x coordinate of the pixel.
  183. @param y the y coordinate of the pixel.
  184. @return the pixel at `x`, `y` in ARGB format.
  185. #end
  186. Method GetPixelARGB:UInt( x:Int,y:Int )
  187. DebugAssert( x>=0 And y>=0 And x<_width And y<_height )
  188. Local p:=PixelPtr( x,y )
  189. Select _format
  190. Case Format.A8
  191. Return p[0] Shl 24
  192. Case Format.I8
  193. Local i:=p[0]
  194. Return UByte($ff) Shl 24 | i Shl 16 | i Shl 8 | i
  195. Case Format.IA16
  196. Local i:=p[1]
  197. Return p[0] Shl 24 | i Shl 16 | i Shl 8 | i
  198. Case Format.RGB24
  199. Return UByte($ff) Shl 24 | p[0] Shl 16 | p[1] Shl 8 | p[2]
  200. Case Format.RGBA32
  201. Return p[3] Shl 24 | p[0] Shl 16 | p[1] Shl 8 | p[2]
  202. Default
  203. Assert( False )
  204. End
  205. Return 0
  206. End
  207. 'Optimize!
  208. '
  209. #rem monkeydoc Clears the pixmap to a given color.
  210. @param color The color to clear the pixmap to.
  211. #end
  212. Method Clear( color:Color )
  213. For Local y:=0 Until _height
  214. For Local x:=0 Until _width
  215. SetPixel( x,y,color )
  216. Next
  217. Next
  218. End
  219. #rem monkeydoc Clears the pixmap to an ARGB color.
  220. @param color ARGB color to clear the pixmap to.
  221. #end
  222. Method ClearARGB( color:UInt )
  223. For Local y:=0 Until _height
  224. For Local x:=0 Until _width
  225. SetPixelARGB( x,y,color )
  226. Next
  227. next
  228. End
  229. #rem monkeydoc Creates a copy of the pixmap.
  230. @return A new pixmap.
  231. #end
  232. Method Copy:Pixmap()
  233. Local pitch:=Width * Depth
  234. Local data:=Cast<UByte Ptr>( libc.malloc( pitch * Height ) )
  235. For Local y:=0 Until Height
  236. memcpy( data+y*pitch,PixelPtr( 0,y ),pitch )
  237. Next
  238. Return New Pixmap( Width,Height,Format,data,pitch )
  239. End
  240. #rem monkeydoc Paste a pixmap to the pixmap.
  241. In debug builds, a runtime error will occur if the operation would write to pixels outside of the pixmap.
  242. Note: No alpha blending is performed - pixels in the pixmap are simply overwritten.
  243. @param pixmap The pixmap to paste.
  244. @param x The x coordinate.
  245. @param y The y coordinate.
  246. #end
  247. Method Paste( pixmap:Pixmap,x:Int,y:Int )
  248. DebugAssert( x>=0 And x+pixmap._width<=_width And y>=0 And y+pixmap._height<=_height )
  249. For Local ty:=0 Until pixmap._height
  250. For Local tx:=0 Until pixmap._width
  251. SetPixel( x+tx,y+ty,pixmap.GetPixel( tx,ty ) )
  252. Next
  253. Next
  254. End
  255. 'Optimize!
  256. '
  257. #rem monkeydoc Converts the pixmap to a different format.
  258. @param format The pixel format to convert the pixmap to.
  259. @return A new pixmap.
  260. #end
  261. Method Convert:Pixmap( format:PixelFormat )
  262. Local t:=New Pixmap( _width,_height,format )
  263. For Local y:=0 Until _height
  264. For Local x:=0 Until _width
  265. t.SetPixel( x,y,GetPixel( x,y ) )
  266. Next
  267. Next
  268. Return t
  269. End
  270. 'Optimize!
  271. '
  272. #rem monkeydoc Premultiply pixmap r,g,b components by alpha.
  273. #end
  274. Method PremultiplyAlpha()
  275. Select _format
  276. Case PixelFormat.IA16,PixelFormat.RGBA32
  277. For Local y:=0 Until _height
  278. For Local x:=0 Until _width
  279. Local color:=GetPixel( x,y )
  280. color.r*=color.a
  281. color.g*=color.a
  282. color.b*=color.a
  283. SetPixel( x,y,color )
  284. Next
  285. Next
  286. End
  287. End
  288. #rem monkeydoc Flips the pixmap on the Y axis.
  289. #end
  290. Method FlipY()
  291. Local sz:=Width*Depth
  292. Local tmp:=New UByte[sz]
  293. For Local y:=0 Until Height/2
  294. Local p1:=PixelPtr( 0,y )
  295. Local p2:=PixelPtr( 0,Height-1-y )
  296. libc.memcpy( tmp.Data,p1,sz )
  297. libc.memcpy( p1,p2,sz )
  298. libc.memcpy( p2,tmp.Data,sz )
  299. Next
  300. End
  301. #rem monkeydoc Returns a rectangular window into the pixmap.
  302. In debug builds, a runtime error will occur if the rectangle lies outside of the pixmap area.
  303. @param x The x coordinate of the top left of the rectangle.
  304. @param y The y coordinate of the top left of the rectangle.
  305. @param width The width of the rectangle.
  306. @param height The height of the rectangle.
  307. #end
  308. Method Window:Pixmap( x:Int,y:Int,width:Int,height:Int )
  309. DebugAssert( x>=0 And y>=0 And width>=0 And height>=0 And x+width<=_width And y+height<=_height )
  310. Local pixmap:=New Pixmap( width,height,_format,PixelPtr( x,y ),_pitch )
  311. AddDependancy( pixmap )
  312. Return pixmap
  313. End
  314. #rem monkeydoc Saves the pixmap to a file.
  315. The only save format currently suppoted is PNG.
  316. #End
  317. Method Save:Bool( path:String )
  318. Return SavePixmap( Self,path )
  319. End
  320. #rem monkeydoc Loads a pixmap from a file.
  321. @param path The file path.
  322. @param format The format to load the pixmap in.
  323. @return Null if the file could not be opened, or contained invalid image data.
  324. #end
  325. Function Load:Pixmap( path:String,format:PixelFormat=Null,pmAlpha:Bool=False )
  326. Local pixmap:=pixmaploader.LoadPixmap( path,format )
  327. If Not pixmap And Not ExtractRootDir( path ) pixmap=pixmaploader.LoadPixmap( "image::"+path,format )
  328. If pixmap And pmAlpha pixmap.PremultiplyAlpha()
  329. Return pixmap
  330. End
  331. Private
  332. Field _width:Int
  333. Field _height:Int
  334. Field _format:PixelFormat
  335. Field _depth:Int
  336. Field _data:UByte Ptr
  337. Field _pitch:Int
  338. End
  339. Class ResourceManager Extension
  340. Method OpenPixmap:Pixmap( path:String,format:PixelFormat=Null,pmAlpha:Bool=False )
  341. Local slug:="Pixmap:name="+StripDir( StripExt( path ) )+"&format="+Int( format )+"&pmAlpha="+Int( pmAlpha )
  342. Local pixmap:=Cast<Pixmap>( OpenResource( slug ) )
  343. If pixmap Return pixmap
  344. pixmap=Pixmap.Load( path,format,pmAlpha )
  345. AddResource( slug,pixmap )
  346. Return pixmap
  347. End
  348. End