pixmap.bmx 15 KB

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