pixmap.monkey2 12 KB

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