glmax2d.bmx 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. SuperStrict
  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.15"
  9. ModuleInfo "Author: Mark Sibly"
  10. ModuleInfo "License: zlib/libpng"
  11. ModuleInfo "Copyright: Blitz Research Ltd"
  12. ModuleInfo "Modserver: BRL"
  13. ModuleInfo "History: 1.15"
  14. ModuleInfo "History: Added RenderImages / render2texture"
  15. ModuleInfo "History: 1.14"
  16. ModuleInfo "History: Changed to SuperStrict"
  17. ModuleInfo "History: Extended flags to Long"
  18. ModuleInfo "History: 1.13 Release"
  19. ModuleInfo "History: Cleaned up SetGraphics"
  20. ModuleInfo "History: 1.12 Release"
  21. ModuleInfo "History: Fixed filtered image min filters"
  22. ModuleInfo "History: 1.11 Release"
  23. ModuleInfo "History: Fixed texture delete logic"
  24. ModuleInfo "History: 1.10 Release"
  25. ModuleInfo "History: Add SetColor/SetClsColor clamping"
  26. ModuleInfo "History: 1.09 Release"
  27. ModuleInfo "History: Fixed DrawPixmap using current blend mode - now always uses SOLIDBLEND"
  28. ModuleInfo "History: 1.08 Release"
  29. ModuleInfo "History: Added MIPMAPPEDIMAGE support"
  30. ModuleInfo "History: 1.07 Release"
  31. ModuleInfo "History: Now default driver for MacOS/Linux only (D3D7 for windows)"
  32. ModuleInfo "History: 1.06 Release"
  33. ModuleInfo "History: Ripped out a bunch of dead code"
  34. ModuleInfo "History: 1.05 Release"
  35. ModuleInfo "History: Added checks to prevent invalid textures deletes"
  36. ?Not opengles And Not nx And Not raspberrypi And Not haiku
  37. Import BRL.Max2D
  38. Import BRL.GLGraphics
  39. Import BRL.Threads
  40. Private
  41. Global _driver:TGLMax2DDriver
  42. Global _BackbufferRenderImageFrame:TGLRenderImageFrame
  43. Global _CurrentRenderImageFrame:TGLRenderImageFrame
  44. Global _GLScissor_BMaxViewport:Rect = New Rect
  45. 'Naughty!
  46. Const GL_BGR:Int = $80E0
  47. Const GL_BGRA:Int = $80E1
  48. Const GL_CLAMP_TO_EDGE:Int = $812F
  49. Const GL_CLAMP_TO_BORDER:Int = $812D
  50. Global ix:Float,iy:Float,jx:Float,jy:Float
  51. Global color4ub:Byte[4]
  52. Global state_blend:Int
  53. Global state_boundtex:Int
  54. Global state_texenabled:Int
  55. Function BindTex( name:Int )
  56. If name = state_boundtex Return
  57. glBindTexture( GL_TEXTURE_2D, name )
  58. state_boundtex = name
  59. End Function
  60. Function EnableTex( name:Int )
  61. BindTex( name )
  62. If state_texenabled Return
  63. glEnable( GL_TEXTURE_2D )
  64. state_texenabled = True
  65. End Function
  66. Function DisableTex()
  67. If Not state_texenabled Return
  68. glDisable( GL_TEXTURE_2D )
  69. state_texenabled = False
  70. End Function
  71. Function Pow2Size:Int( n:Int )
  72. Local t:Int = 1
  73. While t < n
  74. t :* 2
  75. Wend
  76. Return t
  77. End Function
  78. Global dead_texs:TDynamicArray = New TDynamicArray(32)
  79. Global dead_tex_seq:Int
  80. 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
  81. Function DeleteTex( name:Int,seq:Int )
  82. If seq<>dead_tex_seq Return
  83. dead_texs.AddLast(name)
  84. End Function
  85. Function CreateTex:Int( width:Int,height:Int,flags:Int,pixmap:TPixmap )
  86. If pixmap.dds_fmt<>0 Then Return pixmap.tex_name ' if dds texture already exists
  87. 'alloc new tex
  88. Local name:Int
  89. glGenTextures( 1, Varptr name )
  90. 'flush dead texs
  91. If dead_tex_seq=GraphicsSeq
  92. Local n:Int = dead_texs.RemoveLast()
  93. While n <> $FFFFFFFF
  94. glDeleteTextures(1, Varptr n)
  95. n = dead_texs.RemoveLast()
  96. Wend
  97. EndIf
  98. dead_tex_seq = GraphicsSeq
  99. 'bind new tex
  100. BindTex( name )
  101. 'set texture parameters
  102. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE )
  103. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE )
  104. If flags & FILTEREDIMAGE
  105. glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
  106. If flags & MIPMAPPEDIMAGE
  107. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR )
  108. Else
  109. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )
  110. EndIf
  111. Else
  112. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST )
  113. If flags & MIPMAPPEDIMAGE
  114. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST )
  115. Else
  116. glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST )
  117. EndIf
  118. EndIf
  119. Local mip_level:Int
  120. Repeat
  121. glTexImage2D( GL_TEXTURE_2D, mip_level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null )
  122. If Not ( flags & MIPMAPPEDIMAGE ) Exit
  123. If width = 1 And height = 1 Exit
  124. If width > 1 width :/ 2
  125. If height > 1 height :/ 2
  126. mip_level :+ 1
  127. Forever
  128. Return name
  129. End Function
  130. 'NOTE: Assumes a bound texture.
  131. Function UploadTex( pixmap:TPixmap, flags:Int )
  132. Local mip_level:Int
  133. If pixmap.dds_fmt <> 0 Then Return ' if dds texture already exists
  134. Repeat
  135. glPixelStorei GL_UNPACK_ROW_LENGTH,pixmap.pitch/BytesPerPixel[pixmap.format]
  136. glTexSubImage2D GL_TEXTURE_2D,mip_level,0,0,pixmap.width,pixmap.height,GL_RGBA,GL_UNSIGNED_BYTE,pixmap.pixels
  137. If Not ( flags & MIPMAPPEDIMAGE ) Then Exit
  138. If pixmap.width > 1 And pixmap.height > 1
  139. pixmap = ResizePixmap( pixmap, pixmap.width / 2, pixmap.height / 2 )
  140. Else If pixmap.width > 1
  141. pixmap = ResizePixmap( pixmap, pixmap.width / 2, pixmap.height )
  142. Else If pixmap.height > 1
  143. pixmap = ResizePixmap( pixmap, pixmap.width, pixmap.height / 2 )
  144. Else
  145. Exit
  146. EndIf
  147. mip_level :+ 1
  148. Forever
  149. glPixelStorei GL_UNPACK_ROW_LENGTH,0
  150. End Function
  151. Function AdjustTexSize( width:Int Var, height:Int Var )
  152. 'calc texture size
  153. width = Pow2Size( width )
  154. height = Pow2Size( height )
  155. Repeat
  156. Local t:Int
  157. glTexImage2D GL_PROXY_TEXTURE_2D,0,4,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
  158. glGetTexLevelParameteriv GL_PROXY_TEXTURE_2D,0,GL_TEXTURE_WIDTH,Varptr t
  159. If t Then Return
  160. If width = 1 And height = 1 Then RuntimeError "Unable to calculate tex size"
  161. If width > 1 width :/ 2
  162. If height > 1 height :/ 2
  163. Forever
  164. End Function
  165. Global dead_FBOs:TDynamicArray = New TDynamicArray(32)
  166. Global dead_FBO_seq:Int
  167. 'Enqueues a FBO for deletion, to prevent releasing framebuffers on wrong thread.
  168. Function DeleteFBO( FBO:Int,seq:Int )
  169. If seq<>dead_FBO_seq Return
  170. dead_FBOs.AddLast(FBO)
  171. End Function
  172. Function CreateFBO:Int(TextureName:Int )
  173. Local FrameBufferObject:Int
  174. glGenFramebuffers(1, Varptr FrameBufferObject)
  175. glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferObject)
  176. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureName, 0)
  177. ' Flush dead FBOs, this ensures to delete FBOs from within the
  178. ' main thread, while Delete() of image frames can happen from subthread
  179. ' too.
  180. ' This also means, it only deletes FBOs if a new is created!
  181. If dead_FBO_seq = GraphicsSeq
  182. Local deadFBO:Int = dead_FBOs.RemoveLast()
  183. While deadFBO <> $FFFFFFFF
  184. glDeleteFramebuffers(1, Varptr deadFBO) ' gl ignores 0
  185. deadFBO = dead_FBOs.RemoveLast()
  186. Wend
  187. EndIf
  188. dead_FBO_seq = GraphicsSeq
  189. Return FrameBufferObject
  190. End Function
  191. Type TDynamicArray
  192. Private
  193. Field data:Int Ptr
  194. Field size:Size_T
  195. Field capacity:Size_T
  196. Field guard:TMutex
  197. Public
  198. Method New(initialCapacity:Int = 8)
  199. capacity = initialCapacity
  200. data = malloc_(Size_T(initialCapacity * 4))
  201. guard = CreateMutex()
  202. End Method
  203. Method AddLast(value:Int)
  204. guard.Lock()
  205. If size = capacity Then
  206. capacity :* 2
  207. Local d:Byte Ptr = realloc_(data, capacity * 4)
  208. If Not d Then
  209. Throw "Failed to allocate more memory"
  210. End If
  211. data = d
  212. End If
  213. data[size] = value
  214. size :+ 1
  215. guard.Unlock()
  216. End Method
  217. Method RemoveLast:Int()
  218. guard.Lock()
  219. Local v:Int
  220. If size > 0 Then
  221. size :- 1
  222. v = data[size]
  223. Else
  224. v = $FFFFFFFF
  225. End If
  226. guard.Unlock()
  227. Return v
  228. End Method
  229. Method Delete()
  230. free_(data)
  231. CloseMutex(guard)
  232. End Method
  233. End Type
  234. Global glewIsInit:Int
  235. Public
  236. Type TGLImageFrame Extends TImageFrame
  237. Field u0:Float, v0:Float, u1:Float, v1:Float, uscale:Float, vscale:Float
  238. Field name:Int, seq:Int
  239. Method New()
  240. seq = GraphicsSeq
  241. End Method
  242. Method Delete()
  243. If Not seq Then Return
  244. DeleteTex( name, seq )
  245. seq = 0
  246. End Method
  247. Method Draw( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float,sx:Float,sy:Float,sw:Float,sh:Float ) Override
  248. Assert seq=GraphicsSeq Else "Image does not exist"
  249. Local u0:Float = sx * uscale
  250. Local v0:Float = sy * vscale
  251. Local u1:Float = (sx + sw) * uscale
  252. Local v1:Float = (sy + sh) * vscale
  253. EnableTex name
  254. glBegin GL_QUADS
  255. glTexCoord2f u0,v0
  256. glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
  257. glTexCoord2f u1,v0
  258. glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
  259. glTexCoord2f u1,v1
  260. glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
  261. glTexCoord2f u0,v1
  262. glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
  263. glEnd
  264. End Method
  265. Function CreateFromPixmap:TGLImageFrame( src:TPixmap, flags:Int )
  266. 'determine tex size
  267. Local tex_w:Int = src.width
  268. Local tex_h:Int = src.height
  269. AdjustTexSize( tex_w, tex_h )
  270. 'make sure pixmap fits texture
  271. Local width:Int = Min( src.width, tex_w )
  272. Local height:Int = Min( src.height, tex_h )
  273. If src.width <> width Or src.height <> height Then src = ResizePixmap( src, width, height )
  274. 'create texture pixmap
  275. Local tex:TPixmap = src
  276. '"smear" right/bottom edges if necessary
  277. If width < tex_w Or height < tex_h
  278. tex = TPixmap.Create( tex_w, tex_h, PF_RGBA8888 )
  279. tex.Paste( src, 0, 0 )
  280. If width < tex_w
  281. tex.Paste( src.Window( width - 1, 0, 1, height ), width, 0 )
  282. EndIf
  283. If height < tex_h
  284. tex.Paste( src.Window( 0, height - 1, width, 1 ), 0, height )
  285. If width < tex_w
  286. tex.Paste( src.Window( width - 1, height - 1, 1, 1 ), width, height )
  287. EndIf
  288. EndIf
  289. Else
  290. If tex.dds_fmt = 0 ' not dds
  291. If tex.format <> PF_RGBA8888 Then tex = tex.Convert( PF_RGBA8888 )
  292. EndIf
  293. EndIf
  294. 'create tex
  295. Local name:Int = CreateTex( tex_w, tex_h, flags, tex )
  296. 'upload it
  297. UploadTex( tex, flags )
  298. 'done!
  299. Local frame:TGLImageFrame = New TGLImageFrame
  300. frame.name = name
  301. frame.uscale = 1.0 / tex_w
  302. frame.vscale = 1.0 / tex_h
  303. frame.u1 = width * frame.uscale
  304. frame.v1 = height * frame.vscale
  305. Return frame
  306. End Function
  307. End Type
  308. Type TGLRenderImageFrame Extends TGLImageFrame
  309. Field FBO:Int
  310. Field width:Int
  311. Field height:Int
  312. Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
  313. Assert seq=GraphicsSeq Else "Image does not exist"
  314. ' Note for a TGLRenderImage the V texture coordinate is flipped compared to the regular TImageFrame.Draw method
  315. Local u0:Float = sx * uscale
  316. Local v0:Float = (sy + sh) * vscale
  317. Local u1:Float = (sx + sw) * uscale
  318. Local v1:Float = sy * vscale
  319. EnableTex name
  320. glBegin GL_QUADS
  321. glTexCoord2f u0,v0
  322. glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
  323. glTexCoord2f u1,v0
  324. glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
  325. glTexCoord2f u1,v1
  326. glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
  327. glTexCoord2f u0,v1
  328. glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
  329. glEnd
  330. EndMethod
  331. Function Create:TGLRenderImageFrame(width:UInt, height:UInt, flags:Int)
  332. ' Need this to enable frame buffer objects - glGenFramebuffers
  333. If Not glewIsInit
  334. GlewInit()
  335. glewIsInit = True
  336. EndIf
  337. ' store so that we can restore once the fbo is created
  338. Local ScissorTestEnabled:Int = GlIsEnabled(GL_SCISSOR_TEST)
  339. glDisable(GL_SCISSOR_TEST)
  340. Local TextureName:Int
  341. glGenTextures(1, Varptr TextureName)
  342. ' inform engine about TextureName being GL_TEXTURE_2D target
  343. ' do not just call glBindTexture directly!
  344. BindTex(TextureName)
  345. 'glBindTexture(GL_TEXTURE_2D, TextureName)
  346. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
  347. If flags & FILTEREDIMAGE
  348. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
  349. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
  350. Else
  351. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
  352. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
  353. EndIf
  354. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
  355. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
  356. Local FrameBufferObject:Int = CreateFBO(TextureName)
  357. Local RenderTarget:TGLRenderImageFrame = New TGLRenderImageFrame
  358. RenderTarget.name = TextureName
  359. RenderTarget.FBO = FrameBufferObject
  360. RenderTarget.width = width
  361. RenderTarget.height = height
  362. RenderTarget.uscale = 1.0 / width
  363. RenderTarget.vscale = 1.0 / height
  364. RenderTarget.u1 = width * RenderTarget.uscale
  365. RenderTarget.v1 = height * RenderTarget.vscale
  366. If ScissorTestEnabled
  367. glEnable(GL_SCISSOR_TEST)
  368. EndIf
  369. Return RenderTarget
  370. EndFunction
  371. Private
  372. Method Delete()
  373. If Not seq Then Return
  374. If Not FBO Then Return
  375. 'delete FBO deferred
  376. DeleteFBO( FBO, seq )
  377. FBO = 0
  378. End Method
  379. Method New()
  380. EndMethod
  381. EndType
  382. Type TGLMax2DDriver Extends TMax2DDriver
  383. Method Create:TGLMax2DDriver()
  384. If Not GLGraphicsDriver() Return Null
  385. Return Self
  386. End Method
  387. 'graphics driver overrides
  388. Method GraphicsModes:TGraphicsMode[]() Override
  389. Return GLGraphicsDriver().GraphicsModes()
  390. End Method
  391. Method AttachGraphics:TMax2DGraphics( widget:Byte Ptr,flags:Long ) Override
  392. Local g:TGLGraphics = GLGraphicsDriver().AttachGraphics( widget,flags )
  393. If g Return TMax2DGraphics.Create( g,Self )
  394. End Method
  395. Method CreateGraphics:TMax2DGraphics( width:Int,height:Int,depth:Int,hertz:Int,flags:Long,x:Int,y:Int ) Override
  396. Local g:TGLGraphics = GLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
  397. If g Return TMax2DGraphics.Create( g,Self )
  398. End Method
  399. Method SetGraphics( g:TGraphics ) Override
  400. If Not g
  401. TMax2DGraphics.ClearCurrent()
  402. GLGraphicsDriver().SetGraphics(Null)
  403. Return
  404. EndIf
  405. Local t:TMax2DGraphics = TMax2DGraphics( g )
  406. Assert t And TGLGraphics( t._backendGraphics )
  407. GLGraphicsDriver().SetGraphics(t._backendGraphics)
  408. ResetGLContext(t)
  409. t.MakeCurrent()
  410. End Method
  411. Method ResetGLContext( g:TGraphics )
  412. Local gw:Int, gh:Int, gd:Int, gr:Int, gf:Long, gx:Int, gy:Int
  413. g.GetSettings( gw, gh, gd, gr, gf, gx, gy )
  414. state_blend = 0
  415. state_boundtex = 0
  416. state_texenabled = 0
  417. glDisable( GL_TEXTURE_2D )
  418. glMatrixMode GL_PROJECTION
  419. glLoadIdentity
  420. glOrtho 0,gw,gh,0,-1,1
  421. glMatrixMode GL_MODELVIEW
  422. glLoadIdentity
  423. glViewport 0,0,gw,gh
  424. ' Need this to enable "glBlendFuncSeparate" (required for
  425. ' alpha blending on non-opaque backgrounds like render images)
  426. If Not glewIsInit
  427. GlewInit()
  428. glewIsInit = True
  429. EndIf
  430. ' Create default back buffer render image - the FBO will be value 0 which is the default for the existing backbuffer
  431. Local BackBufferRenderImageFrame:TGLRenderImageFrame = New TGLRenderImageFrame
  432. BackBufferRenderImageFrame.width = gw
  433. BackBufferRenderImageFrame.height = gh
  434. ' cache it
  435. _BackBufferRenderImageFrame = BackBufferRenderImageFrame
  436. _CurrentRenderImageFrame = _BackBufferRenderImageFrame
  437. End Method
  438. Method Flip:Int( sync:Int ) Override
  439. GLGraphicsDriver().Flip sync
  440. End Method
  441. Method ToString:String() Override
  442. Return "OpenGL"
  443. End Method
  444. Method ApiIdentifier:String() Override
  445. Return "BRL.OpenGL"
  446. End Method
  447. Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap, flags:Int ) Override
  448. Return TGLImageFrame.CreateFromPixmap( pixmap, flags )
  449. End Method
  450. Method SetBlend( blend:Int ) Override
  451. If state_blend = blend Return
  452. state_blend = blend
  453. Select blend
  454. Case MASKBLEND
  455. glDisable( GL_BLEND )
  456. glEnable( GL_ALPHA_TEST )
  457. glAlphaFunc( GL_GEQUAL, 0.5 )
  458. Case SOLIDBLEND
  459. glDisable( GL_BLEND )
  460. glDisable( GL_ALPHA_TEST )
  461. Case ALPHABLEND
  462. glEnable( GL_BLEND )
  463. ' simple alphablend:
  464. 'glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )
  465. ' more advanced blend function allows blending on a non-opaque
  466. ' "background" (eg. render image)
  467. glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
  468. glDisable( GL_ALPHA_TEST )
  469. Case LIGHTBLEND
  470. glEnable( GL_BLEND )
  471. glBlendFunc( GL_SRC_ALPHA, GL_ONE )
  472. glDisable( GL_ALPHA_TEST )
  473. Case SHADEBLEND
  474. glEnable( GL_BLEND )
  475. glBlendFunc( GL_DST_COLOR, GL_ZERO )
  476. glDisable( GL_ALPHA_TEST )
  477. Default
  478. glDisable( GL_BLEND )
  479. glDisable( GL_ALPHA_TEST )
  480. End Select
  481. End Method
  482. Method SetAlpha( alpha:Float ) Override
  483. If alpha > 1.0 Then alpha = 1.0
  484. If alpha < 0.0 Then alpha = 0.0
  485. color4ub[3] = alpha * 255
  486. glColor4ubv( color4ub )
  487. End Method
  488. Method SetLineWidth( width:Float ) Override
  489. glLineWidth( width )
  490. End Method
  491. Method SetColor( red:Int,green:Int,blue:Int ) Override
  492. color4ub[0] = Min( Max( red, 0 ), 255 )
  493. color4ub[1] = Min( Max( green, 0 ), 255 )
  494. color4ub[2] = Min( Max( blue, 0 ), 255 )
  495. glColor4ubv( color4ub )
  496. End Method
  497. Method SetClsColor( red:Int, green:Int, blue:Int, alpha:Float ) Override
  498. red = Min(Max(red,0),255)
  499. green = Min(Max(green,0),255)
  500. blue = Min(Max(blue,0),255)
  501. glClearColor(red/255.0, green/255.0, blue/255.0, alpha)
  502. End Method
  503. Method SetViewport( x:Int, y:Int, w:Int, h:Int ) Override
  504. _GLScissor_BMaxViewport.x = x
  505. _GLScissor_BMaxViewport.y = y
  506. _GLScissor_BMaxViewport.width = w
  507. _GLScissor_BMaxViewport.height = h
  508. SetScissor(x, y, w, h)
  509. End Method
  510. Method SetTransform( xx:Float, xy:Float, yx:Float, yy:Float ) Override
  511. ix = xx
  512. iy = xy
  513. jx = yx
  514. jy = yy
  515. End Method
  516. Method Cls() Override
  517. glClear( GL_COLOR_BUFFER_BIT )
  518. End Method
  519. Method Plot( x:Float, y:Float ) Override
  520. DisableTex()
  521. glBegin( GL_POINTS )
  522. glVertex2f( x+.5,y+.5 )
  523. glEnd()
  524. End Method
  525. Method DrawLine( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
  526. DisableTex()
  527. glBegin( GL_LINES )
  528. glVertex2f( x0 * ix + y0 * iy + tx + .5, x0 * jx + y0 * jy + ty + .5 )
  529. glVertex2f( x1 * ix + y1 * iy + tx + .5, x1 * jx + y1 * jy + ty + .5 )
  530. glEnd()
  531. End Method
  532. Method DrawRect( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
  533. DisableTex()
  534. glBegin( GL_QUADS )
  535. glVertex2f( x0 * ix + y0 * iy + tx, x0 * jx + y0 * jy + ty )
  536. glVertex2f( x1 * ix + y0 * iy + tx, x1 * jx + y0 * jy + ty )
  537. glVertex2f( x1 * ix + y1 * iy + tx, x1 * jx + y1 * jy + ty )
  538. glVertex2f( x0 * ix + y1 * iy + tx, x0 * jx + y1 * jy + ty )
  539. glEnd()
  540. End Method
  541. Method DrawOval( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float ) Override
  542. Local xr:Float = ( x1 - x0 ) * 0.5
  543. Local yr:Float = ( y1 - y0 ) * 0.5
  544. Local segs:Int = Abs( xr ) + Abs( yr )
  545. segs = Max( segs, 12 ) &~ 3
  546. x0 :+ xr
  547. y0 :+ yr
  548. DisableTex()
  549. glBegin( GL_POLYGON )
  550. For Local i:Int = 0 Until segs
  551. Local th:Float = i * 360.0 / segs
  552. Local x:Float = x0 +Cos(th) * xr
  553. Local y:Float = y0 -Sin(th) * yr
  554. glVertex2f( x * ix + y * iy + tx, x * jx + y * jy + ty )
  555. Next
  556. glEnd()
  557. End Method
  558. Method DrawPoly( xy:Float[], handle_x:Float, handle_y:Float, origin_x:Float, origin_y:Float, indices:Int[] ) Override
  559. If xy.length < 6 Or ( xy.length & 1 ) Then Return
  560. DisableTex()
  561. glBegin( GL_POLYGON )
  562. For Local i:Int = 0 Until xy.length Step 2
  563. Local x:Float = xy[i + 0] + handle_x
  564. Local y:Float = xy[i + 1] + handle_y
  565. glVertex2f( x * ix + y * iy + origin_x, x * jx + y * jy + origin_y )
  566. Next
  567. glEnd()
  568. End Method
  569. Method DrawPixmap( p:TPixmap, x:Int, y:Int ) Override
  570. Local blend:Int = state_blend
  571. DisableTex()
  572. SetBlend( SOLIDBLEND )
  573. Local t:TPixmap = p
  574. If t.format <> PF_RGBA8888 Then t = ConvertPixmap( t, PF_RGBA8888 )
  575. glPixelZoom( 1, -1 )
  576. glRasterPos2i( 0, 0 )
  577. glBitmap( 0, 0, 0, 0, x, -y, Null)
  578. glPixelStorei( GL_UNPACK_ROW_LENGTH, t.pitch Shr 2 )
  579. glDrawPixels( t.width, t.height, GL_RGBA, GL_UNSIGNED_BYTE, t.pixels )
  580. glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 )
  581. glPixelZoom( 1, 1 )
  582. SetBlend( blend )
  583. End Method
  584. Method GrabPixmap:TPixmap( x:Int, y:Int, w:Int, h:Int ) Override
  585. Local blend:Int = state_blend
  586. SetBlend( SOLIDBLEND )
  587. Local p:TPixmap=CreatePixmap( w, h, PF_RGBA8888 )
  588. 'The default backbuffer in Max2D was opaque so overwrote any
  589. 'trash data of a freshly created pixmap. Potentially transparent
  590. 'backbuffers require a complete transparent pixmap to start with.
  591. p.ClearPixels(0)
  592. If _CurrentRenderImageFrame and _CurrentRenderImageFrame <> _BackbufferRenderImageFrame
  593. glReadPixels(x, _CurrentRenderImageFrame.height - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels)
  594. Else
  595. glReadPixels(x, _BackbufferRenderImageFrame.height - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels)
  596. EndIf
  597. p = YFlipPixmap( p )
  598. SetBlend( blend )
  599. Return p
  600. End Method
  601. Method SetResolution( width:Float, height:Float ) Override
  602. glMatrixMode( GL_PROJECTION )
  603. glLoadIdentity()
  604. glOrtho( 0, width, height, 0, -1, 1 )
  605. glMatrixMode( GL_MODELVIEW )
  606. End Method
  607. Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Override
  608. Return TGLRenderImageFrame.Create(width, height, flags)
  609. EndMethod
  610. Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override
  611. If RenderImageFrame = _CurrentRenderImageFrame
  612. Return
  613. EndIf
  614. glBindFrameBuffer(GL_FRAMEBUFFER, TGLRenderImageFrame(RenderImageFrame).FBO)
  615. _CurrentRenderImageFrame = TGLRenderImageFrame(RenderImageFrame)
  616. Local vp:Rect = _GLScissor_BMaxViewport
  617. SetScissor(vp.x, vp.y, vp.width, vp.height)
  618. SetMatrixAndViewportToCurrentRenderImage()
  619. EndMethod
  620. Method SetBackbuffer()
  621. SetRenderImageFrame(_BackBufferRenderImageFrame)
  622. EndMethod
  623. Private
  624. Method SetMatrixAndViewportToCurrentRenderImage()
  625. glMatrixMode(GL_PROJECTION)
  626. glLoadIdentity()
  627. glOrtho(0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height, 0, -1, 1)
  628. glMatrixMode(GL_MODELVIEW)
  629. glLoadIdentity()
  630. glViewport(0, 0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height)
  631. EndMethod
  632. Method SetScissor(x:Int, y:Int, w:Int, h:Int)
  633. Local ri:TImageFrame = _CurrentRenderImageFrame
  634. If x = 0 And y = 0 And w = _CurrentRenderImageFrame.width And h = _CurrentRenderImageFrame.height
  635. glDisable(GL_SCISSOR_TEST)
  636. Else
  637. glEnable(GL_SCISSOR_TEST)
  638. glScissor(x, _CurrentRenderImageFrame.height - y - h, w, h)
  639. EndIf
  640. EndMethod
  641. End Type
  642. Rem
  643. bbdoc: Get OpenGL Max2D Driver
  644. about:
  645. The returned driver can be used with #SetGraphicsDriver to enable OpenGL Max2D
  646. rendering.
  647. End Rem
  648. Function GLMax2DDriver:TGLMax2DDriver()
  649. Global _done:Int
  650. If Not _done
  651. _driver=New TGLMax2DDriver.Create()
  652. _done=True
  653. EndIf
  654. Return _driver
  655. End Function
  656. Local driver:TGLMax2DDriver=GLMax2DDriver()
  657. If driver SetGraphicsDriver driver
  658. ?