pixmap.monkey2 12 KB

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