pixmap.bmx 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587
  1. Strict
  2. Rem
  3. bbdoc: Graphics/Pixmaps
  4. End Rem
  5. Module BRL.Pixmap
  6. ModuleInfo "Version: 1.07"
  7. ModuleInfo "Author: Mark Sibly"
  8. ModuleInfo "License: zlib/libpng"
  9. ModuleInfo "Copyright: Blitz Research Ltd"
  10. ModuleInfo "Modserver: BRL"
  11. ModuleInfo "History: 1.07 Release"
  12. ModuleInfo "History: Added ClearPixels"
  13. ModuleInfo "History: 1.06 Release"
  14. ModuleInfo "History: Added new GL compatible pixel formats"
  15. ModuleInfo "History: 1.05 Release"
  16. ModuleInfo "History: Added _source:Object field"
  17. ModuleInfo "History: Removed AddPixmapLoader function"
  18. Import BRL.Math
  19. Import BRL.Stream
  20. Import "pixel.bmx"
  21. Rem
  22. bbdoc: The Pixmap type
  23. end rem
  24. Type TPixmap
  25. Method _pad()
  26. End Method
  27. Rem
  28. bbdoc: A byte pointer to the pixmap's pixels
  29. end rem
  30. Field pixels:Byte Ptr
  31. Rem
  32. bbdoc: The width, in pixels, of the pixmap
  33. end rem
  34. Field width
  35. Rem
  36. bbdoc: The height, in pixels, of the pixmap
  37. end rem
  38. Field height
  39. Rem
  40. bbdoc: The pitch, in bytes, of the pixmap
  41. end rem
  42. Field pitch
  43. Rem
  44. bbdoc: The pixel format of the pixmap
  45. end rem
  46. Field format
  47. Rem
  48. bbdoc: The capacity, in bytes, of the pixmap, or -1 for a static pixmap
  49. end rem
  50. Field capacity
  51. 'Hack to provide robust PixmapWindow functionality
  52. Field _source:Object
  53. Method Delete()
  54. If capacity>=0
  55. MemFree pixels
  56. EndIf
  57. End Method
  58. Rem
  59. bbdoc: Get memory address of a pixel
  60. returns: A byte pointer to the pixel at coordinates @x, @y
  61. End Rem
  62. Method PixelPtr:Byte Ptr( x,y )
  63. Return pixels+y*pitch+x*BytesPerPixel[format]
  64. End Method
  65. Rem
  66. bbdoc: Create a virtual window into a pixmap
  67. returns: A static pixmap that references the specified rectangle.
  68. End Rem
  69. Method Window:TPixmap( x,y,width,height )
  70. Assert..
  71. x>=0 And width>=0 And x+width<=Self.width And..
  72. y>=0 And height>=0 And y+height<=Self.height Else "Pixmap coordinates out of bounds"
  73. Local t:TPixmap=CreateStatic( PixelPtr(x,y),width,height,pitch,format )
  74. t._source=Self
  75. Return t
  76. End Method
  77. Rem
  78. bbdoc: Duplicate a pixmap
  79. returns: A new TPixmap object.
  80. end rem
  81. Method Copy:TPixmap()
  82. Local pixmap:TPixmap=Create( width,height,format )
  83. For Local y=0 Until height
  84. CopyPixels Self.PixelPtr(0,y),pixmap.PixelPtr(0,y),format,width
  85. Next
  86. Return pixmap
  87. End Method
  88. Rem
  89. bbdoc: Paste a pixmap
  90. end rem
  91. Method Paste( source:TPixmap,x,y )
  92. For Local h=0 Until source.height
  93. ConvertPixels source.PixelPtr(0,h),source.format,Self.PixelPtr(x,y+h),Self.format,source.width
  94. Next
  95. End Method
  96. Rem
  97. bbdoc: Convert a pixmap
  98. returns: A new TPixmap object in the specified format
  99. end rem
  100. Method Convert:TPixmap( format )
  101. Local pixmap:TPixmap=Create( width,height,format )
  102. For Local y=0 Until height
  103. ConvertPixels Self.PixelPtr(0,y),Self.format,pixmap.PixelPtr(0,y),pixmap.format,pixmap.width
  104. Next
  105. Return pixmap
  106. End Method
  107. Rem
  108. bbdoc: Read a pixel from a pixmap
  109. returns: The pixel at the specified coordinates packed into an integer
  110. end rem
  111. Method ReadPixel( x,y )
  112. Assert x>=0 And x<width And y>=0 And y<height Else "Pixmap coordinates out of bounds"
  113. Local p:Byte Ptr=PixelPtr(x,y)
  114. Select format
  115. Case PF_A8
  116. Return p[0] Shl 24 | $00ffffff
  117. Case PF_I8
  118. Return $ff000000 | p[0] Shl 16 | p[0] Shl 8 | p[0]
  119. Case PF_RGB888
  120. Return $ff000000 | p[0] Shl 16 | p[1] Shl 8 | p[2]
  121. Case PF_BGR888
  122. Return $ff000000 | p[2] Shl 16 | p[1] Shl 8 | p[0]
  123. Case PF_RGBA8888
  124. Return p[0] Shl 16 | p[1] Shl 8 | p[2] | p[3] Shl 24
  125. Case PF_BGRA8888
  126. Return p[2] Shl 16 | p[1] Shl 8 | p[0] | p[3] Shl 24
  127. End Select
  128. End Method
  129. Rem
  130. bbdoc: Write a pixel to a pixmap
  131. end rem
  132. Method WritePixel( x,y,argb )
  133. Assert x>=0 And x<width And y>=0 And y<height Else "Pixmap coordinates out of bounds"
  134. Local p:Byte Ptr=PixelPtr(x,y)
  135. Select format
  136. Case PF_A8
  137. p[0]=argb Shr 24
  138. Case PF_I8
  139. p[0]=( (argb Shr 16 & $ff)+(argb Shr 8 & $ff)+(argb & $ff) )/3
  140. Case PF_RGB888
  141. p[0]=argb Shr 16 ; p[1]=argb Shr 8 ; p[2]=argb
  142. Case PF_BGR888
  143. p[0]=argb ; p[1]=argb Shr 8 ; p[2]=argb Shr 16
  144. Case PF_RGBA8888
  145. p[0]=argb Shr 16 ; p[1]=argb Shr 8 ; p[2]=argb ; p[3]=argb Shr 24
  146. Case PF_BGRA8888
  147. p[0]=argb ; p[1]=argb Shr 8 ; p[2]=argb Shr 16 ; p[3]=argb Shr 24
  148. End Select
  149. End Method
  150. Rem
  151. bbdoc: Create a pixmap
  152. returns: A new TPixmap object
  153. end rem
  154. Function Create:TPixmap( width,height,format,align=4 )
  155. Local pitch=width*BytesPerPixel[format]
  156. pitch=(pitch+(align-1))/align*align
  157. Local capacity:Size_T=pitch*height
  158. Local pixmap:TPixmap=New TPixmap
  159. pixmap.pixels=MemAlloc( capacity )
  160. pixmap.width=width
  161. pixmap.height=height
  162. pixmap.pitch=pitch
  163. pixmap.format=format
  164. pixmap.capacity=capacity
  165. Return pixmap
  166. End Function
  167. Rem
  168. bbdoc: Create a static pixmap
  169. returns: A new TPixmap object
  170. end rem
  171. Function CreateStatic:TPixmap( pixels:Byte Ptr,width,height,pitch,format )
  172. Local pixmap:TPixmap=New TPixmap
  173. pixmap.pixels=pixels
  174. pixmap.width=width
  175. pixmap.height=height
  176. pixmap.pitch=pitch
  177. pixmap.format=format
  178. pixmap.capacity=-1
  179. Return pixmap
  180. End Function
  181. Rem
  182. bbdoc: Clear a pixmap
  183. End Rem
  184. Method ClearPixels( argb )
  185. If Not argb And width*BytesPerPixel[format]=pitch
  186. MemClear pixels,Size_T(pitch*height)
  187. Return
  188. EndIf
  189. For Local y=0 Until height
  190. Local p:Byte Ptr=PixelPtr(0,y)
  191. If Not argb
  192. MemClear p,Size_T(width*BytesPerPixel[format])
  193. Continue
  194. EndIf
  195. Select format
  196. Case PF_A8
  197. For Local x=0 Until width
  198. p[x]=argb Shr 24
  199. Next
  200. Case PF_I8
  201. For Local x=0 Until width
  202. p[x]=( (argb Shr 16 & $ff)+(argb Shr 8 & $ff)+(argb & $ff) )/3
  203. Next
  204. Case PF_RGB888
  205. For Local x=0 Until width*3 Step 3
  206. p[x]=argb Shr 16 ; p[x+1]=argb Shr 8 ; p[x+2]=argb
  207. Next
  208. Case PF_BGR888
  209. For Local x=0 Until width*3 Step 3
  210. p[x]=argb ; p[x+1]=argb Shr 8 ; p[x+2]=argb Shr 16
  211. Next
  212. Case PF_RGBA8888
  213. For Local x=0 Until width*4 Step 4
  214. p[x]=argb Shr 16 ; p[x+1]=argb Shr 8 ; p[x+2]=argb ; p[x+3]=argb Shr 24
  215. Next
  216. Case PF_BGRA8888
  217. For Local x=0 Until width*4 Step 4
  218. p[x]=argb ; p[x+1]=argb Shr 8 ; p[x+2]=argb Shr 16 ; p[x+3]=argb Shr 24
  219. Next
  220. End Select
  221. Next
  222. End Method
  223. End Type
  224. Private
  225. Global pixmap_loaders:TPixmapLoader
  226. Public
  227. Rem
  228. bbdoc: Abstract base type for pixmap loaders
  229. about:
  230. To create a new pixmap loader, you should extend TPixmapLoader and implement the #LoadPixmap method.
  231. To install your pixmap loader, simply create an instance of it using #New</font>.
  232. End Rem
  233. Type TPixmapLoader
  234. Field _succ:TPixmapLoader
  235. Method New()
  236. _succ=pixmap_loaders
  237. pixmap_loaders=Self
  238. End Method
  239. Rem
  240. bbdoc: Load a pixmap
  241. about: This method must be implemented by extending types.
  242. end rem
  243. Method LoadPixmap:TPixmap( stream:TStream ) Abstract
  244. End Type
  245. Rem
  246. bbdoc: Create a pixmap
  247. returns: A new pixmap object of the specified @width and @height
  248. about:
  249. @format should be one of the following:
  250. [ @Format | @Description
  251. * PF_A8 | 8 bit alpha
  252. * PF_I8 | 8 bit intensity
  253. * PF_RGB888 | 24 bit big endian RGB
  254. * PF_BGR888 | 24 bit little endian RGB
  255. * PF_RGBA8888 | 32 bit big endian RGB with alpha
  256. * PF_BGRA8888 | 32 bit little endian RGB with alpha
  257. ]
  258. Note that the newly created pixmap will contain random data. #ClearPixels can
  259. be used to set all pixels to a known value prior to use.
  260. End Rem
  261. Function CreatePixmap:TPixmap( width,height,format,align_bytes=4 )
  262. Return TPixmap.Create( width,height,format,align_bytes )
  263. End Function
  264. Rem
  265. bbdoc: Create a pixmap with existing pixel data
  266. returns: A new pixmap object that references an existing block of memory
  267. about:
  268. The memory referenced by a static pixmap is not released when the pixmap is deleted.
  269. See #CreatePixmap for valid pixmap formats.
  270. End Rem
  271. Function CreateStaticPixmap:TPixmap( pixels:Byte Ptr,width,height,pitch,format )
  272. Return TPixmap.CreateStatic( pixels,width,height,pitch,format )
  273. End Function
  274. Rem
  275. bbdoc: Copy a pixmap
  276. returns: A new pixmap object
  277. end rem
  278. Function CopyPixmap:TPixmap( pixmap:TPixmap )
  279. Return pixmap.Copy()
  280. End Function
  281. Rem
  282. bbdoc: Convert pixel format of a pixmap
  283. returns: A new pixmap object with the specified pixel format
  284. about:
  285. See #CreatePixmap for valid pixmap formats.
  286. end rem
  287. Function ConvertPixmap:TPixmap( pixmap:TPixmap,format )
  288. Return pixmap.Convert( format )
  289. End Function
  290. Rem
  291. bbdoc: Get pixmap width
  292. returns: The width, in pixels, of @pixmap
  293. end rem
  294. Function PixmapWidth( pixmap:TPixmap )
  295. Return pixmap.width
  296. End Function
  297. Rem
  298. bbdoc: Get pixmap width
  299. returns: The height, in pixels, of @pixmap
  300. end rem
  301. Function PixmapHeight( pixmap:TPixmap )
  302. Return pixmap.height
  303. End Function
  304. Rem
  305. bbdoc: Get pixmap pitch
  306. returns: The pitch, in bytes, of @pixmap
  307. about:
  308. Pitch refers to the difference, in bytes, between the start of one row of pixels and the start of the next row.
  309. end rem
  310. Function PixmapPitch( pixmap:TPixmap )
  311. Return pixmap.pitch
  312. End Function
  313. Rem
  314. bbdoc: Get pixmap format
  315. returns: The format of the pixels stored in @pixmap
  316. about:
  317. See #CreatePixmap for supported formats.
  318. End Rem
  319. Function PixmapFormat( pixmap:TPixmap )
  320. Return pixmap.format
  321. End Function
  322. Rem
  323. bbdoc: Get pixmap pixels
  324. returns: A byte pointer to the pixels stored in @pixmap
  325. end rem
  326. Function PixmapPixelPtr:Byte Ptr( pixmap:TPixmap,x=0,y=0 )
  327. Return pixmap.PixelPtr( x,y )
  328. End Function
  329. Rem
  330. bbdoc: Create a pixmap window
  331. returns: A new pixmap object
  332. about: #PixmapWindow creates a 'virtual' window into @pixmap.
  333. end rem
  334. Function PixmapWindow:TPixmap( pixmap:TPixmap,x,y,width,height )
  335. Return pixmap.Window( x,y,width,height )
  336. End Function
  337. Rem
  338. bbdoc: Mask a pixmap
  339. returns: A new pixmap object
  340. about: @MaskPixmap builds a new pixmap with alpha components set to '0' wherever the pixel colors
  341. in the original @pixmap match @mask_red, @mask_green and @mask_blue. @mask_red, @mask_green and @mask_blue
  342. should be in the range 0 to 255.
  343. end rem
  344. Function MaskPixmap:TPixmap( pixmap:TPixmap,mask_red,mask_green,mask_blue ) NoDebug
  345. Local tmp:TPixmap=pixmap
  346. If tmp.format<>PF_RGBA8888 tmp=tmp.Convert( PF_RGBA8888 )
  347. Local out:TPixmap=CreatePixmap( tmp.width,tmp.height,PF_RGBA8888 )
  348. For Local y=0 Until pixmap.height
  349. Local t:Byte Ptr=tmp.PixelPtr( 0,y )
  350. Local o:Byte Ptr=out.PixelPtr( 0,y )
  351. For Local x=0 Until pixmap.width
  352. If t[0]<>mask_red Or t[1]<>mask_green Or t[2]<>mask_blue
  353. o[0]=t[0]
  354. o[1]=t[1]
  355. o[2]=t[2]
  356. o[3]=255
  357. Else
  358. Local r,g,b,n
  359. For Local ty=y-1 To y+1
  360. Local t:Byte Ptr=tmp.pixelptr( x-1,ty )
  361. For Local tx=x-1 To x+1
  362. If tx>=0 And tx<tmp.width And ty>=0 And ty<tmp.height
  363. If t[0]<>mask_red Or t[1]<>mask_green Or t[2]<>mask_blue
  364. r:+t[0]
  365. g:+t[1]
  366. b:+t[2]
  367. n:+1
  368. EndIf
  369. EndIf
  370. t:+4
  371. Next
  372. Next
  373. If n
  374. o[0]=r/n
  375. o[1]=g/n
  376. o[2]=b/n
  377. Else
  378. o[0]=0't[0]
  379. o[1]=0't[1]
  380. o[2]=0't[2]
  381. EndIf
  382. o[3]=0
  383. EndIf
  384. t:+4
  385. o:+4
  386. Next
  387. Next
  388. Return out
  389. End Function
  390. Rem
  391. bbdoc: Flip a pixmap horizontally
  392. returns: A new pixmap object
  393. end rem
  394. Function XFlipPixmap:TPixmap( pixmap:TPixmap ) NoDebug
  395. Local out:TPixmap=CreatePixmap( pixmap.width,pixmap.height,pixmap.format )
  396. For Local x=0 Until pixmap.width
  397. out.Paste pixmap.Window(pixmap.width-x-1,0,1,pixmap.height),x,0
  398. Next
  399. Return out
  400. End Function
  401. Rem
  402. bbdoc: Flip a pixmap vertically
  403. returns: A new pixmap object
  404. end rem
  405. Function YFlipPixmap:TPixmap( pixmap:TPixmap ) NoDebug
  406. Local out:TPixmap=CreatePixmap( pixmap.width,pixmap.height,pixmap.format )
  407. For Local y=0 Until pixmap.height
  408. out.paste pixmap.Window(0,pixmap.height-y-1,pixmap.width,1),0,y
  409. Next
  410. Return out
  411. End Function
  412. Rem
  413. bbdoc: Resize a pixmap
  414. returns: A new pixmap object of the specified @width and @height
  415. end rem
  416. Function ResizePixmap:TPixmap( pixmap:TPixmap,width,height ) NoDebug
  417. Local in_pixmap:TPixmap=pixmap
  418. If in_pixmap.format<>PF_STDFORMAT in_pixmap=pixmap.Convert( PF_STDFORMAT )
  419. Local tmp:Byte[width*4]
  420. Local x_sc#=Float(in_pixmap.width)/width
  421. Local y_sc#=Float(in_pixmap.height)/height
  422. Local out_pixmap:TPixmap=CreatePixmap( width,height,pixmap.format )
  423. For Local y=0 Until height
  424. Local ty#=(y+.5)*y_sc-.5
  425. Local iy#=Floor(ty),fy#=ty-iy
  426. Local in_pitch=in_pixmap.pitch
  427. If iy<0
  428. iy=0;fy=0;in_pitch=0
  429. Else If iy>=in_pixmap.height-1
  430. iy=in_pixmap.height-1;fy=0;in_pitch=0
  431. EndIf
  432. Local src:Byte Ptr=in_pixmap.PixelPtr(0,Int(iy)),dst:Byte Ptr=tmp
  433. For Local x=0 Until width
  434. Local tx#=(x+.5)*x_sc-.5
  435. Local ix#=Floor(tx),fx#=tx-ix
  436. Local in_off=4
  437. If ix<0
  438. ix=0;fx=0;in_off=0
  439. Else If ix>=in_pixmap.width-1
  440. ix=in_pixmap.width-1;fx=0;in_off=0
  441. EndIf
  442. Local p:Byte Ptr=src+Int(ix)*4
  443. For Local n=0 Until 4
  444. Local v0#=p[n],v1#=p[n+in_off]
  445. Local v2#=p[n+in_pitch],v3#=p[n+in_pitch+in_off]
  446. Local va#=(v1-v0)*fx+v0,vb#=(v3-v2)*fx+v2,vt#=(vb-va)*fy+va
  447. dst[n]=vt
  448. Next
  449. dst:+4
  450. Next
  451. ConvertPixels tmp,PF_STDFORMAT,out_pixmap.Pixelptr(0,y),out_pixmap.format,width
  452. Next
  453. Return out_pixmap
  454. End Function
  455. Rem
  456. bbdoc: Load a pixmap
  457. returns: A pixmap object
  458. end rem
  459. Function LoadPixmap:TPixmap( url:Object )
  460. Local stream:TStream=ReadStream( url )
  461. If Not stream Return
  462. Local pos=stream.Pos()
  463. If pos=-1
  464. stream.Close
  465. Return
  466. EndIf
  467. Local pixmap:TPixmap
  468. Local loader:TPixmapLoader=pixmap_loaders
  469. While loader
  470. stream.Seek pos
  471. Try
  472. pixmap=loader.LoadPixmap( stream )
  473. Catch ex:TStreamException
  474. End Try
  475. If pixmap Exit
  476. loader=loader._succ
  477. Wend
  478. stream.Close
  479. Return pixmap
  480. End Function
  481. Rem
  482. bbdoc: Read a pixel from a pixmap
  483. returns: A 32 bit pixel value
  484. about:
  485. The returned 32 bit value contains the following components:
  486. [ bits 24-31 | pixel alpha
  487. * bits 16-23 | pixel red
  488. * bits 8-15 | pixel green
  489. * bits 0-7 | pixel blue
  490. ]
  491. End Rem
  492. Function ReadPixel( pixmap:TPixmap,x,y )
  493. Return pixmap.ReadPixel( x,y )
  494. End Function
  495. Rem
  496. bbdoc: Write a pixel to a pixmap
  497. about:
  498. The 32 bit @argb value contains the following components:
  499. [ bits 24-31 | pixel alpha
  500. * bits 16-23 | pixel red
  501. * bits 8-15 | pixel green
  502. * bits 0-7 | pixel blue
  503. ]
  504. End Rem
  505. Function WritePixel( pixmap:TPixmap,x,y,argb )
  506. pixmap.WritePixel x,y,argb
  507. End Function
  508. Rem
  509. bbdoc: Clear a pixmap
  510. about:
  511. Sets all pixels in a pixmap to a 32 bit pixel value.
  512. The 32 bit @argb value contains the following components:
  513. [ bits 24-31 | pixel alpha
  514. * bits 16-23 | pixel red
  515. * bits 8-15 | pixel green
  516. * bits 0-7 | pixel blue
  517. ]
  518. End Rem
  519. Function ClearPixels( pixmap:TPixmap,argb=0 )
  520. pixmap.ClearPixels argb
  521. End Function