glmax2d.bmx 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610
  1. Strict
  2. Rem
  3. bbdoc: Graphics/OpenGL Max2D
  4. about:
  5. The OpenGL Max2D module provides an OpenGL driver for #Max2D.
  6. End Rem
  7. Module BRL.GLMax2D
  8. ModuleInfo "Version: 1.13"
  9. ModuleInfo "Author: Mark Sibly"
  10. ModuleInfo "License: zlib/libpng"
  11. ModuleInfo "Copyright: Blitz Research Ltd"
  12. ModuleInfo "Modserver: BRL"
  13. ModuleInfo "History: 1.13 Release"
  14. ModuleInfo "History: Cleaned up SetGraphics"
  15. ModuleInfo "History: 1.12 Release"
  16. ModuleInfo "History: Fixed filtered image min filters"
  17. ModuleInfo "History: 1.11 Release"
  18. ModuleInfo "History: Fixed texture delete logic"
  19. ModuleInfo "History: 1.10 Release"
  20. ModuleInfo "History: Add SetColor/SetClsColor clamping"
  21. ModuleInfo "History: 1.09 Release"
  22. ModuleInfo "History: Fixed DrawPixmap using current blend mode - now always uses SOLIDBLEND"
  23. ModuleInfo "History: 1.08 Release"
  24. ModuleInfo "History: Added MIPMAPPEDIMAGE support"
  25. ModuleInfo "History: 1.07 Release"
  26. ModuleInfo "History: Now default driver for MacOS/Linux only (D3D7 for windows)"
  27. ModuleInfo "History: 1.06 Release"
  28. ModuleInfo "History: Ripped out a bunch of dead code"
  29. ModuleInfo "History: 1.05 Release"
  30. ModuleInfo "History: Added checks to prevent invalid textures deletes"
  31. ?Not opengles And Not nx And Not raspberrypi And Not haiku
  32. Import BRL.Max2D
  33. Import BRL.GLGraphics
  34. Import BRL.Threads
  35. Private
  36. Global _driver:TGLMax2DDriver
  37. 'Naughty!
  38. Const GL_BGR=$80E0
  39. Const GL_BGRA=$80E1
  40. Const GL_CLAMP_TO_EDGE=$812F
  41. Const GL_CLAMP_TO_BORDER=$812D
  42. Global ix#,iy#,jx#,jy#
  43. Global color4ub:Byte[4]
  44. Global state_blend
  45. Global state_boundtex
  46. Global state_texenabled
  47. Function BindTex( name )
  48. If name=state_boundtex Return
  49. glBindTexture GL_TEXTURE_2D,name
  50. state_boundtex=name
  51. End Function
  52. Function EnableTex( name )
  53. BindTex name
  54. If state_texenabled Return
  55. glEnable GL_TEXTURE_2D
  56. state_texenabled=True
  57. End Function
  58. Function DisableTex()
  59. If Not state_texenabled Return
  60. glDisable GL_TEXTURE_2D
  61. state_texenabled=False
  62. End Function
  63. Function Pow2Size( n )
  64. Local t=1
  65. While t<n
  66. t:*2
  67. Wend
  68. Return t
  69. End Function
  70. Global dead_texs:TDynamicArray = New TDynamicArray(32),dead_tex_seq
  71. Extern
  72. Function bbAtomicAdd:Int( target:Int Ptr,value:Int )="int bbAtomicAdd( int *,int )!"
  73. End Extern
  74. 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
  75. Function DeleteTex( name,seq )
  76. If seq<>dead_tex_seq Return
  77. dead_texs.AddLast(name)
  78. End Function
  79. Function CreateTex( width,height,flags,pixmap:TPixmap )
  80. If pixmap.dds_fmt<>0 Return pixmap.tex_name ' if dds texture already exists
  81. 'alloc new tex
  82. Local name
  83. glGenTextures 1,Varptr name
  84. 'flush dead texs
  85. If dead_tex_seq=GraphicsSeq
  86. Local n:Int = dead_texs.RemoveLast()
  87. While n <> $FFFFFFFF
  88. glDeleteTextures 1, Varptr n
  89. n = dead_texs.RemoveLast()
  90. Wend
  91. EndIf
  92. dead_tex_seq=GraphicsSeq
  93. 'bind new tex
  94. BindTex name
  95. 'set texture parameters
  96. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE
  97. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE
  98. If flags & FILTEREDIMAGE
  99. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
  100. If flags & MIPMAPPEDIMAGE
  101. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR
  102. Else
  103. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
  104. EndIf
  105. Else
  106. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
  107. If flags & MIPMAPPEDIMAGE
  108. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST
  109. Else
  110. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
  111. EndIf
  112. EndIf
  113. Local mip_level
  114. Repeat
  115. glTexImage2D GL_TEXTURE_2D,mip_level,GL_RGBA8,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
  116. If Not (flags & MIPMAPPEDIMAGE) Exit
  117. If width=1 And height=1 Exit
  118. If width>1 width:/2
  119. If height>1 height:/2
  120. mip_level:+1
  121. Forever
  122. Return name
  123. End Function
  124. Function UploadTex( pixmap:TPixmap,flags )
  125. Local mip_level
  126. If pixmap.dds_fmt<>0 Return ' if dds texture already exists
  127. Repeat
  128. glPixelStorei GL_UNPACK_ROW_LENGTH,pixmap.pitch/BytesPerPixel[pixmap.format]
  129. glTexSubImage2D GL_TEXTURE_2D,mip_level,0,0,pixmap.width,pixmap.height,GL_RGBA,GL_UNSIGNED_BYTE,pixmap.pixels
  130. If Not (flags & MIPMAPPEDIMAGE) Exit
  131. If pixmap.width>1 And pixmap.height>1
  132. pixmap=ResizePixmap( pixmap,pixmap.width/2,pixmap.height/2 )
  133. Else If pixmap.width>1
  134. pixmap=ResizePixmap( pixmap,pixmap.width/2,pixmap.height )
  135. Else If pixmap.height>1
  136. pixmap=ResizePixmap( pixmap,pixmap.width,pixmap.height/2 )
  137. Else
  138. Exit
  139. EndIf
  140. mip_level:+1
  141. Forever
  142. glPixelStorei GL_UNPACK_ROW_LENGTH,0
  143. End Function
  144. Function AdjustTexSize( width Var,height Var )
  145. 'calc texture size
  146. width=Pow2Size( width )
  147. height=Pow2Size( height )
  148. Repeat
  149. Local t
  150. glTexImage2D GL_PROXY_TEXTURE_2D,0,4,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
  151. glGetTexLevelParameteriv GL_PROXY_TEXTURE_2D,0,GL_TEXTURE_WIDTH,Varptr t
  152. If t Return
  153. If width=1 And height=1 RuntimeError "Unable to calculate tex size"
  154. If width>1 width:/2
  155. If height>1 height:/2
  156. Forever
  157. End Function
  158. Type TDynamicArray
  159. Private
  160. Field data:Int Ptr
  161. Field size:Size_T
  162. Field capacity:Size_T
  163. Field guard:TMutex
  164. Public
  165. Method New(initialCapacity:Int = 8)
  166. capacity = initialCapacity
  167. data = malloc_(Size_T(initialCapacity * 4))
  168. guard = CreateMutex()
  169. End Method
  170. Method AddLast(value:Int)
  171. guard.Lock()
  172. If size = capacity Then
  173. capacity :* 2
  174. Local d:Byte Ptr = realloc_(data, capacity * 4)
  175. If Not d Then
  176. Throw "Failed to allocate more memory"
  177. End If
  178. data = d
  179. End If
  180. data[size] = value
  181. size :+ 1
  182. guard.Unlock()
  183. End Method
  184. Method RemoveLast:Int()
  185. guard.Lock()
  186. Local v:Int
  187. If size > 0 Then
  188. size :- 1
  189. v = data[size]
  190. Else
  191. v = $FFFFFFFF
  192. End If
  193. guard.Unlock()
  194. Return v
  195. End Method
  196. Method Delete()
  197. free_(data)
  198. CloseMutex(guard)
  199. End Method
  200. End Type
  201. Public
  202. Type TGLImageFrame Extends TImageFrame
  203. Field u0#,v0#,u1#,v1#,uscale#,vscale#
  204. Field name,seq
  205. Method New()
  206. seq=GraphicsSeq
  207. End Method
  208. Method Delete()
  209. If Not seq Return
  210. DeleteTex name,seq
  211. seq=0
  212. End Method
  213. Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
  214. Assert seq=GraphicsSeq Else "Image does not exist"
  215. Local u0#=sx * uscale
  216. Local v0#=sy * vscale
  217. Local u1#=(sx+sw) * uscale
  218. Local v1#=(sy+sh) * vscale
  219. EnableTex name
  220. glBegin GL_QUADS
  221. glTexCoord2f u0,v0
  222. glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
  223. glTexCoord2f u1,v0
  224. glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
  225. glTexCoord2f u1,v1
  226. glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
  227. glTexCoord2f u0,v1
  228. glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
  229. glEnd
  230. End Method
  231. Function CreateFromPixmap:TGLImageFrame( src:TPixmap,flags )
  232. 'determine tex size
  233. Local tex_w=src.width
  234. Local tex_h=src.height
  235. AdjustTexSize tex_w,tex_h
  236. 'make sure pixmap fits texture
  237. Local width=Min( src.width,tex_w )
  238. Local height=Min( src.height,tex_h )
  239. If src.width<>width Or src.height<>height src=ResizePixmap( src,width,height )
  240. 'create texture pixmap
  241. Local tex:TPixmap=src
  242. '"smear" right/bottom edges if necessary
  243. If width<tex_w Or height<tex_h
  244. tex=TPixmap.Create( tex_w,tex_h,PF_RGBA8888 )
  245. tex.Paste src,0,0
  246. If width<tex_w
  247. tex.Paste src.Window( width-1,0,1,height ),width,0
  248. EndIf
  249. If height<tex_h
  250. tex.Paste src.Window( 0,height-1,width,1 ),0,height
  251. If width<tex_w
  252. tex.Paste src.Window( width-1,height-1,1,1 ),width,height
  253. EndIf
  254. EndIf
  255. Else
  256. If tex.dds_fmt=0 ' not dds
  257. If tex.format<>PF_RGBA8888 tex=tex.Convert( PF_RGBA8888 )
  258. EndIf
  259. EndIf
  260. 'create tex
  261. Local name=CreateTex( tex_w,tex_h,flags,tex )
  262. 'upload it
  263. UploadTex tex,flags
  264. 'done!
  265. Local frame:TGLImageFrame=New TGLImageFrame
  266. frame.name=name
  267. frame.uscale=1.0/tex_w
  268. frame.vscale=1.0/tex_h
  269. frame.u1=width * frame.uscale
  270. frame.v1=height * frame.vscale
  271. Return frame
  272. End Function
  273. End Type
  274. Type TGLMax2DDriver Extends TMax2DDriver
  275. Method Create:TGLMax2DDriver()
  276. If Not GLGraphicsDriver() Return Null
  277. Return Self
  278. End Method
  279. 'graphics driver overrides
  280. Method GraphicsModes:TGraphicsMode[]() Override
  281. Return GLGraphicsDriver().GraphicsModes()
  282. End Method
  283. Method AttachGraphics:TMax2DGraphics( widget:Byte Ptr,flags ) Override
  284. Local g:TGLGraphics=GLGraphicsDriver().AttachGraphics( widget,flags )
  285. If g Return TMax2DGraphics.Create( g,Self )
  286. End Method
  287. Method CreateGraphics:TMax2DGraphics( width,height,depth,hertz,flags,x,y ) Override
  288. Local g:TGLGraphics=GLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
  289. If g Return TMax2DGraphics.Create( g,Self )
  290. End Method
  291. Method SetGraphics( g:TGraphics ) Override
  292. If Not g
  293. TMax2DGraphics.ClearCurrent
  294. GLGraphicsDriver().SetGraphics Null
  295. Return
  296. EndIf
  297. Local t:TMax2DGraphics=TMax2DGraphics(g)
  298. Assert t And TGLGraphics( t._graphics )
  299. GLGraphicsDriver().SetGraphics t._graphics
  300. ResetGLContext t
  301. t.MakeCurrent
  302. End Method
  303. Method ResetGLContext( g:TGraphics )
  304. Local gw,gh,gd,gr,gf,gx,gy
  305. g.GetSettings gw,gh,gd,gr,gf,gx,gy
  306. state_blend=0
  307. state_boundtex=0
  308. state_texenabled=0
  309. glDisable GL_TEXTURE_2D
  310. glMatrixMode GL_PROJECTION
  311. glLoadIdentity
  312. glOrtho 0,gw,gh,0,-1,1
  313. glMatrixMode GL_MODELVIEW
  314. glLoadIdentity
  315. glViewport 0,0,gw,gh
  316. End Method
  317. Method Flip( sync ) Override
  318. GLGraphicsDriver().Flip sync
  319. End Method
  320. Method ToString$() Override
  321. Return "OpenGL"
  322. End Method
  323. Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap,flags ) Override
  324. Local frame:TGLImageFrame
  325. frame=TGLImageFrame.CreateFromPixmap( pixmap,flags )
  326. Return frame
  327. End Method
  328. Method SetBlend( blend ) Override
  329. If blend=state_blend Return
  330. state_blend=blend
  331. Select blend
  332. Case MASKBLEND
  333. glDisable GL_BLEND
  334. glEnable GL_ALPHA_TEST
  335. glAlphaFunc GL_GEQUAL,.5
  336. Case SOLIDBLEND
  337. glDisable GL_BLEND
  338. glDisable GL_ALPHA_TEST
  339. Case ALPHABLEND
  340. glEnable GL_BLEND
  341. glBlendFunc GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA
  342. glDisable GL_ALPHA_TEST
  343. Case LIGHTBLEND
  344. glEnable GL_BLEND
  345. glBlendFunc GL_SRC_ALPHA,GL_ONE
  346. glDisable GL_ALPHA_TEST
  347. Case SHADEBLEND
  348. glEnable GL_BLEND
  349. glBlendFunc GL_DST_COLOR,GL_ZERO
  350. glDisable GL_ALPHA_TEST
  351. Default
  352. glDisable GL_BLEND
  353. glDisable GL_ALPHA_TEST
  354. End Select
  355. End Method
  356. Method SetAlpha( alpha# ) Override
  357. If alpha>1.0 alpha=1.0
  358. If alpha<0.0 alpha=0.0
  359. color4ub[3]=alpha*255
  360. glColor4ubv color4ub
  361. End Method
  362. Method SetLineWidth( width# ) Override
  363. glLineWidth width
  364. End Method
  365. Method SetColor( red,green,blue ) Override
  366. color4ub[0]=Min(Max(red,0),255)
  367. color4ub[1]=Min(Max(green,0),255)
  368. color4ub[2]=Min(Max(blue,0),255)
  369. glColor4ubv color4ub
  370. End Method
  371. Method SetColor( color:SColor8 ) Override
  372. color4ub[0]=color.r
  373. color4ub[1]=color.g
  374. color4ub[2]=color.b
  375. glColor4ubv color4ub
  376. End Method
  377. Method SetClsColor( red,green,blue ) Override
  378. red=Min(Max(red,0),255)
  379. green=Min(Max(green,0),255)
  380. blue=Min(Max(blue,0),255)
  381. glClearColor red/255.0,green/255.0,blue/255.0,1.0
  382. End Method
  383. Method SetClsColor( color:SColor8 ) Override
  384. glClearColor color.r/255.0,color.g/255.0,color.b/255.0,1.0
  385. End Method
  386. Method SetViewport( x,y,w,h ) Override
  387. If x=0 And y=0 And w=GraphicsWidth() And h=GraphicsHeight()
  388. glDisable GL_SCISSOR_TEST
  389. Else
  390. glEnable GL_SCISSOR_TEST
  391. glScissor x,GraphicsHeight()-y-h,w,h
  392. EndIf
  393. End Method
  394. Method SetTransform( xx#,xy#,yx#,yy# ) Override
  395. ix=xx
  396. iy=xy
  397. jx=yx
  398. jy=yy
  399. End Method
  400. Method Cls() Override
  401. glClear GL_COLOR_BUFFER_BIT
  402. End Method
  403. Method Plot( x#,y# ) Override
  404. DisableTex
  405. glBegin GL_POINTS
  406. glVertex2f x+.5,y+.5
  407. glEnd
  408. End Method
  409. Method DrawLine( x0#,y0#,x1#,y1#,tx#,ty# ) Override
  410. DisableTex
  411. glBegin GL_LINES
  412. glVertex2f x0*ix+y0*iy+tx+.5,x0*jx+y0*jy+ty+.5
  413. glVertex2f x1*ix+y1*iy+tx+.5,x1*jx+y1*jy+ty+.5
  414. glEnd
  415. End Method
  416. Method DrawRect( x0#,y0#,x1#,y1#,tx#,ty# ) Override
  417. DisableTex
  418. glBegin GL_QUADS
  419. glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
  420. glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
  421. glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
  422. glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
  423. glEnd
  424. End Method
  425. Method DrawOval( x0#,y0#,x1#,y1#,tx#,ty# ) Override
  426. Local xr#=(x1-x0)*.5
  427. Local yr#=(y1-y0)*.5
  428. Local segs=Abs(xr)+Abs(yr)
  429. segs=Max(segs,12)&~3
  430. x0:+xr
  431. y0:+yr
  432. DisableTex
  433. glBegin GL_POLYGON
  434. For Local i=0 Until segs
  435. Local th#=i*360#/segs
  436. Local x#=x0+Cos(th)*xr
  437. Local y#=y0-Sin(th)*yr
  438. glVertex2f x*ix+y*iy+tx,x*jx+y*jy+ty
  439. Next
  440. glEnd
  441. End Method
  442. Method DrawPoly( xy#[],handle_x#,handle_y#,origin_x#,origin_y# ) Override
  443. If xy.length<6 Or (xy.length&1) Return
  444. DisableTex
  445. glBegin GL_POLYGON
  446. For Local i=0 Until Len xy Step 2
  447. Local x#=xy[i+0]+handle_x
  448. Local y#=xy[i+1]+handle_y
  449. glVertex2f x*ix+y*iy+origin_x,x*jx+y*jy+origin_y
  450. Next
  451. glEnd
  452. End Method
  453. Method DrawPixmap( p:TPixmap,x,y ) Override
  454. Local blend=state_blend
  455. DisableTex
  456. SetBlend SOLIDBLEND
  457. Local t:TPixmap=p
  458. If t.format<>PF_RGBA8888 t=ConvertPixmap( t,PF_RGBA8888 )
  459. glPixelZoom 1,-1
  460. glRasterPos2i 0,0
  461. glBitmap 0,0,0,0,x,-y,Null
  462. glPixelStorei GL_UNPACK_ROW_LENGTH, t.pitch Shr 2
  463. glDrawPixels t.width,t.height,GL_RGBA,GL_UNSIGNED_BYTE,t.pixels
  464. glPixelStorei GL_UNPACK_ROW_LENGTH,0
  465. glPixelZoom 1,1
  466. SetBlend blend
  467. End Method
  468. Method GrabPixmap:TPixmap( x,y,w,h ) Override
  469. Local blend=state_blend
  470. SetBlend SOLIDBLEND
  471. Local p:TPixmap=CreatePixmap( w,h,PF_RGBA8888 )
  472. glReadPixels x,GraphicsHeight()-h-y,w,h,GL_RGBA,GL_UNSIGNED_BYTE,p.pixels
  473. p=YFlipPixmap( p )
  474. SetBlend blend
  475. Return p
  476. End Method
  477. Method SetResolution( width#,height# ) Override
  478. glMatrixMode GL_PROJECTION
  479. glLoadIdentity
  480. glOrtho 0,width,height,0,-1,1
  481. glMatrixMode GL_MODELVIEW
  482. End Method
  483. End Type
  484. Rem
  485. bbdoc: Get OpenGL Max2D Driver
  486. about:
  487. The returned driver can be used with #SetGraphicsDriver to enable OpenGL Max2D
  488. rendering.
  489. End Rem
  490. Function GLMax2DDriver:TGLMax2DDriver()
  491. Global _done
  492. If Not _done
  493. _driver=New TGLMax2DDriver.Create()
  494. _done=True
  495. EndIf
  496. Return _driver
  497. End Function
  498. Local driver:TGLMax2DDriver=GLMax2DDriver()
  499. If driver SetGraphicsDriver driver
  500. ?