glmax2d.bmx 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770
  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. Type TDynamicArray
  166. Private
  167. Field data:Int Ptr
  168. Field size:Size_T
  169. Field capacity:Size_T
  170. Field guard:TMutex
  171. Public
  172. Method New(initialCapacity:Int = 8)
  173. capacity = initialCapacity
  174. data = malloc_(Size_T(initialCapacity * 4))
  175. guard = CreateMutex()
  176. End Method
  177. Method AddLast(value:Int)
  178. guard.Lock()
  179. If size = capacity Then
  180. capacity :* 2
  181. Local d:Byte Ptr = realloc_(data, capacity * 4)
  182. If Not d Then
  183. Throw "Failed to allocate more memory"
  184. End If
  185. data = d
  186. End If
  187. data[size] = value
  188. size :+ 1
  189. guard.Unlock()
  190. End Method
  191. Method RemoveLast:Int()
  192. guard.Lock()
  193. Local v:Int
  194. If size > 0 Then
  195. size :- 1
  196. v = data[size]
  197. Else
  198. v = $FFFFFFFF
  199. End If
  200. guard.Unlock()
  201. Return v
  202. End Method
  203. Method Delete()
  204. free_(data)
  205. CloseMutex(guard)
  206. End Method
  207. End Type
  208. Global glewIsInit:Int
  209. Public
  210. Type TGLImageFrame Extends TImageFrame
  211. Field u0:Float, v0:Float, u1:Float, v1:Float, uscale:Float, vscale:Float
  212. Field name:Int, seq:Int
  213. Method New()
  214. seq = GraphicsSeq
  215. End Method
  216. Method Delete()
  217. If Not seq Then Return
  218. DeleteTex( name, seq )
  219. seq = 0
  220. End Method
  221. Method Draw( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float,sx:Float,sy:Float,sw:Float,sh:Float ) Override
  222. Assert seq=GraphicsSeq Else "Image does not exist"
  223. Local u0:Float = sx * uscale
  224. Local v0:Float = sy * vscale
  225. Local u1:Float = (sx + sw) * uscale
  226. Local v1:Float = (sy + sh) * vscale
  227. EnableTex name
  228. glBegin GL_QUADS
  229. glTexCoord2f u0,v0
  230. glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
  231. glTexCoord2f u1,v0
  232. glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
  233. glTexCoord2f u1,v1
  234. glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
  235. glTexCoord2f u0,v1
  236. glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
  237. glEnd
  238. End Method
  239. Function CreateFromPixmap:TGLImageFrame( src:TPixmap, flags:Int )
  240. 'determine tex size
  241. Local tex_w:Int = src.width
  242. Local tex_h:Int = src.height
  243. AdjustTexSize( tex_w, tex_h )
  244. 'make sure pixmap fits texture
  245. Local width:Int = Min( src.width, tex_w )
  246. Local height:Int = Min( src.height, tex_h )
  247. If src.width <> width Or src.height <> height Then src = ResizePixmap( src, width, height )
  248. 'create texture pixmap
  249. Local tex:TPixmap = src
  250. '"smear" right/bottom edges if necessary
  251. If width < tex_w Or height < tex_h
  252. tex = TPixmap.Create( tex_w, tex_h, PF_RGBA8888 )
  253. tex.Paste( src, 0, 0 )
  254. If width < tex_w
  255. tex.Paste( src.Window( width - 1, 0, 1, height ), width, 0 )
  256. EndIf
  257. If height < tex_h
  258. tex.Paste( src.Window( 0, height - 1, width, 1 ), 0, height )
  259. If width < tex_w
  260. tex.Paste( src.Window( width - 1, height - 1, 1, 1 ), width, height )
  261. EndIf
  262. EndIf
  263. Else
  264. If tex.dds_fmt = 0 ' not dds
  265. If tex.format <> PF_RGBA8888 Then tex = tex.Convert( PF_RGBA8888 )
  266. EndIf
  267. EndIf
  268. 'create tex
  269. Local name:Int = CreateTex( tex_w, tex_h, flags, tex )
  270. 'upload it
  271. UploadTex( tex, flags )
  272. 'done!
  273. Local frame:TGLImageFrame = New TGLImageFrame
  274. frame.name = name
  275. frame.uscale = 1.0 / tex_w
  276. frame.vscale = 1.0 / tex_h
  277. frame.u1 = width * frame.uscale
  278. frame.v1 = height * frame.vscale
  279. Return frame
  280. End Function
  281. End Type
  282. Type TGLRenderImageFrame Extends TGLImageFrame
  283. Field FBO:Int
  284. Field width:Int
  285. Field height:Int
  286. Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
  287. Assert seq=GraphicsSeq Else "Image does not exist"
  288. ' Note for a TGLRenderImage the V texture coordinate is flipped compared to the regular TImageFrame.Draw method
  289. Local u0:Float = sx * uscale
  290. Local v0:Float = (sy + sh) * vscale
  291. Local u1:Float = (sx + sw) * uscale
  292. Local v1:Float = sy * vscale
  293. EnableTex name
  294. glBegin GL_QUADS
  295. glTexCoord2f u0,v0
  296. glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
  297. glTexCoord2f u1,v0
  298. glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
  299. glTexCoord2f u1,v1
  300. glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
  301. glTexCoord2f u0,v1
  302. glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
  303. glEnd
  304. EndMethod
  305. Function Create:TGLRenderImageFrame(width:UInt, height:UInt, flags:Int)
  306. ' Need this to enable frame buffer objects - glGenFramebuffers
  307. If Not glewIsInit
  308. GlewInit()
  309. glewIsInit = True
  310. EndIf
  311. ' store so that we can restore once the fbo is created
  312. Local ScissorTestEnabled:Int = GlIsEnabled(GL_SCISSOR_TEST)
  313. glDisable(GL_SCISSOR_TEST)
  314. Local TextureName:Int
  315. glGenTextures(1, Varptr TextureName)
  316. ' inform engine about TextureName being GL_TEXTURE_2D target
  317. ' do not just call glBindTexture directly!
  318. BindTex(TextureName)
  319. 'glBindTexture(GL_TEXTURE_2D, TextureName)
  320. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
  321. If flags & FILTEREDIMAGE
  322. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
  323. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
  324. Else
  325. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
  326. glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
  327. EndIf
  328. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
  329. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
  330. Local FrameBufferObject:Int
  331. glGenFramebuffers(1, Varptr FrameBufferObject)
  332. glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferObject)
  333. glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureName, 0)
  334. Local RenderTarget:TGLRenderImageFrame = New TGLRenderImageFrame
  335. RenderTarget.name = TextureName
  336. RenderTarget.FBO = FrameBufferObject
  337. RenderTarget.width = width
  338. RenderTarget.height = height
  339. RenderTarget.uscale = 1.0 / width
  340. RenderTarget.vscale = 1.0 / height
  341. RenderTarget.u1 = width * RenderTarget.uscale
  342. RenderTarget.v1 = height * RenderTarget.vscale
  343. If ScissorTestEnabled
  344. glEnable(GL_SCISSOR_TEST)
  345. EndIf
  346. Return RenderTarget
  347. EndFunction
  348. Private
  349. Method Delete()
  350. 'remove framebuffer if used
  351. if FBO <> 0
  352. glDeleteFramebuffers(1, Varptr FBO) ' gl ignores 0
  353. EndIf
  354. EndMethod
  355. Method New()
  356. EndMethod
  357. EndType
  358. Type TGLMax2DDriver Extends TMax2DDriver
  359. Method Create:TGLMax2DDriver()
  360. If Not GLGraphicsDriver() Return Null
  361. Return Self
  362. End Method
  363. 'graphics driver overrides
  364. Method GraphicsModes:TGraphicsMode[]() Override
  365. Return GLGraphicsDriver().GraphicsModes()
  366. End Method
  367. Method AttachGraphics:TMax2DGraphics( widget:Byte Ptr,flags:Long ) Override
  368. Local g:TGLGraphics = GLGraphicsDriver().AttachGraphics( widget,flags )
  369. If g Return TMax2DGraphics.Create( g,Self )
  370. End Method
  371. Method CreateGraphics:TMax2DGraphics( width:Int,height:Int,depth:Int,hertz:Int,flags:Long,x:Int,y:Int ) Override
  372. Local g:TGLGraphics = GLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
  373. If g Return TMax2DGraphics.Create( g,Self )
  374. End Method
  375. Method SetGraphics( g:TGraphics ) Override
  376. If Not g
  377. TMax2DGraphics.ClearCurrent()
  378. GLGraphicsDriver().SetGraphics(Null)
  379. Return
  380. EndIf
  381. Local t:TMax2DGraphics = TMax2DGraphics( g )
  382. Assert t And TGLGraphics( t._backendGraphics )
  383. GLGraphicsDriver().SetGraphics(t._backendGraphics)
  384. ResetGLContext(t)
  385. t.MakeCurrent()
  386. End Method
  387. Method ResetGLContext( g:TGraphics )
  388. Local gw:Int, gh:Int, gd:Int, gr:Int, gf:Long, gx:Int, gy:Int
  389. g.GetSettings( gw, gh, gd, gr, gf, gx, gy )
  390. state_blend = 0
  391. state_boundtex = 0
  392. state_texenabled = 0
  393. glDisable( GL_TEXTURE_2D )
  394. glMatrixMode GL_PROJECTION
  395. glLoadIdentity
  396. glOrtho 0,gw,gh,0,-1,1
  397. glMatrixMode GL_MODELVIEW
  398. glLoadIdentity
  399. glViewport 0,0,gw,gh
  400. ' Need this to enable "glBlendFuncSeparate" (required for
  401. ' alpha blending on non-opaque backgrounds like render images)
  402. If Not glewIsInit
  403. GlewInit()
  404. glewIsInit = True
  405. EndIf
  406. ' Create default back buffer render image - the FBO will be value 0 which is the default for the existing backbuffer
  407. Local BackBufferRenderImageFrame:TGLRenderImageFrame = New TGLRenderImageFrame
  408. BackBufferRenderImageFrame.width = gw
  409. BackBufferRenderImageFrame.height = gh
  410. ' cache it
  411. _BackBufferRenderImageFrame = BackBufferRenderImageFrame
  412. _CurrentRenderImageFrame = _BackBufferRenderImageFrame
  413. End Method
  414. Method Flip:Int( sync:Int ) Override
  415. GLGraphicsDriver().Flip sync
  416. End Method
  417. Method ToString:String() Override
  418. Return "OpenGL"
  419. End Method
  420. Method ApiIdentifier:String() Override
  421. Return "BRL.OpenGL"
  422. End Method
  423. Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap, flags:Int ) Override
  424. Return TGLImageFrame.CreateFromPixmap( pixmap, flags )
  425. End Method
  426. Method SetBlend( blend:Int ) Override
  427. If state_blend = blend Return
  428. state_blend = blend
  429. Select blend
  430. Case MASKBLEND
  431. glDisable( GL_BLEND )
  432. glEnable( GL_ALPHA_TEST )
  433. glAlphaFunc( GL_GEQUAL, 0.5 )
  434. Case SOLIDBLEND
  435. glDisable( GL_BLEND )
  436. glDisable( GL_ALPHA_TEST )
  437. Case ALPHABLEND
  438. glEnable( GL_BLEND )
  439. ' simple alphablend:
  440. 'glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )
  441. ' more advanced blend function allows blending on a non-opaque
  442. ' "background" (eg. render image)
  443. glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA)
  444. glDisable( GL_ALPHA_TEST )
  445. Case LIGHTBLEND
  446. glEnable( GL_BLEND )
  447. glBlendFunc( GL_SRC_ALPHA, GL_ONE )
  448. glDisable( GL_ALPHA_TEST )
  449. Case SHADEBLEND
  450. glEnable( GL_BLEND )
  451. glBlendFunc( GL_DST_COLOR, GL_ZERO )
  452. glDisable( GL_ALPHA_TEST )
  453. Default
  454. glDisable( GL_BLEND )
  455. glDisable( GL_ALPHA_TEST )
  456. End Select
  457. End Method
  458. Method SetAlpha( alpha:Float ) Override
  459. If alpha > 1.0 Then alpha = 1.0
  460. If alpha < 0.0 Then alpha = 0.0
  461. color4ub[3] = alpha * 255
  462. glColor4ubv( color4ub )
  463. End Method
  464. Method SetLineWidth( width:Float ) Override
  465. glLineWidth( width )
  466. End Method
  467. Method SetColor( red:Int,green:Int,blue:Int ) Override
  468. color4ub[0] = Min( Max( red, 0 ), 255 )
  469. color4ub[1] = Min( Max( green, 0 ), 255 )
  470. color4ub[2] = Min( Max( blue, 0 ), 255 )
  471. glColor4ubv( color4ub )
  472. End Method
  473. Method SetClsColor( red:Int, green:Int, blue:Int, alpha:Float ) Override
  474. red = Min(Max(red,0),255)
  475. green = Min(Max(green,0),255)
  476. blue = Min(Max(blue,0),255)
  477. glClearColor(red/255.0, green/255.0, blue/255.0, alpha)
  478. End Method
  479. Method SetViewport( x:Int, y:Int, w:Int, h:Int ) Override
  480. _GLScissor_BMaxViewport.x = x
  481. _GLScissor_BMaxViewport.y = y
  482. _GLScissor_BMaxViewport.width = w
  483. _GLScissor_BMaxViewport.height = h
  484. SetScissor(x, y, w, h)
  485. End Method
  486. Method SetTransform( xx:Float, xy:Float, yx:Float, yy:Float ) Override
  487. ix = xx
  488. iy = xy
  489. jx = yx
  490. jy = yy
  491. End Method
  492. Method Cls() Override
  493. glClear( GL_COLOR_BUFFER_BIT )
  494. End Method
  495. Method Plot( x:Float, y:Float ) Override
  496. DisableTex()
  497. glBegin( GL_POINTS )
  498. glVertex2f( x+.5,y+.5 )
  499. glEnd()
  500. End Method
  501. Method DrawLine( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
  502. DisableTex()
  503. glBegin( GL_LINES )
  504. glVertex2f( x0 * ix + y0 * iy + tx + .5, x0 * jx + y0 * jy + ty + .5 )
  505. glVertex2f( x1 * ix + y1 * iy + tx + .5, x1 * jx + y1 * jy + ty + .5 )
  506. glEnd()
  507. End Method
  508. Method DrawRect( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
  509. DisableTex()
  510. glBegin( GL_QUADS )
  511. glVertex2f( x0 * ix + y0 * iy + tx, x0 * jx + y0 * jy + ty )
  512. glVertex2f( x1 * ix + y0 * iy + tx, x1 * jx + y0 * jy + ty )
  513. glVertex2f( x1 * ix + y1 * iy + tx, x1 * jx + y1 * jy + ty )
  514. glVertex2f( x0 * ix + y1 * iy + tx, x0 * jx + y1 * jy + ty )
  515. glEnd()
  516. End Method
  517. Method DrawOval( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float ) Override
  518. Local xr:Float = ( x1 - x0 ) * 0.5
  519. Local yr:Float = ( y1 - y0 ) * 0.5
  520. Local segs:Int = Abs( xr ) + Abs( yr )
  521. segs = Max( segs, 12 ) &~ 3
  522. x0 :+ xr
  523. y0 :+ yr
  524. DisableTex()
  525. glBegin( GL_POLYGON )
  526. For Local i:Int = 0 Until segs
  527. Local th:Float = i * 360.0 / segs
  528. Local x:Float = x0 +Cos(th) * xr
  529. Local y:Float = y0 -Sin(th) * yr
  530. glVertex2f( x * ix + y * iy + tx, x * jx + y * jy + ty )
  531. Next
  532. glEnd()
  533. End Method
  534. Method DrawPoly( xy:Float[], handle_x:Float, handle_y:Float, origin_x:Float, origin_y:Float, indices:Int[] ) Override
  535. If xy.length < 6 Or ( xy.length & 1 ) Then Return
  536. DisableTex()
  537. glBegin( GL_POLYGON )
  538. For Local i:Int = 0 Until xy.length Step 2
  539. Local x:Float = xy[i + 0] + handle_x
  540. Local y:Float = xy[i + 1] + handle_y
  541. glVertex2f( x * ix + y * iy + origin_x, x * jx + y * jy + origin_y )
  542. Next
  543. glEnd()
  544. End Method
  545. Method DrawPixmap( p:TPixmap, x:Int, y:Int ) Override
  546. Local blend:Int = state_blend
  547. DisableTex()
  548. SetBlend( SOLIDBLEND )
  549. Local t:TPixmap = p
  550. If t.format <> PF_RGBA8888 Then t = ConvertPixmap( t, PF_RGBA8888 )
  551. glPixelZoom( 1, -1 )
  552. glRasterPos2i( 0, 0 )
  553. glBitmap( 0, 0, 0, 0, x, -y, Null)
  554. glPixelStorei( GL_UNPACK_ROW_LENGTH, t.pitch Shr 2 )
  555. glDrawPixels( t.width, t.height, GL_RGBA, GL_UNSIGNED_BYTE, t.pixels )
  556. glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 )
  557. glPixelZoom( 1, 1 )
  558. SetBlend( blend )
  559. End Method
  560. Method GrabPixmap:TPixmap( x:Int, y:Int, w:Int, h:Int ) Override
  561. Local blend:Int = state_blend
  562. SetBlend( SOLIDBLEND )
  563. Local p:TPixmap=CreatePixmap( w, h, PF_RGBA8888 )
  564. 'The default backbuffer in Max2D was opaque so overwrote any
  565. 'trash data of a freshly created pixmap. Potentially transparent
  566. 'backbuffers require a complete transparent pixmap to start with.
  567. p.ClearPixels(0)
  568. If _CurrentRenderImageFrame and _CurrentRenderImageFrame <> _BackbufferRenderImageFrame
  569. glReadPixels(x, _CurrentRenderImageFrame.height - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels)
  570. Else
  571. glReadPixels(x, _BackbufferRenderImageFrame.height - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels)
  572. EndIf
  573. p = YFlipPixmap( p )
  574. SetBlend( blend )
  575. Return p
  576. End Method
  577. Method SetResolution( width:Float, height:Float ) Override
  578. glMatrixMode( GL_PROJECTION )
  579. glLoadIdentity()
  580. glOrtho( 0, width, height, 0, -1, 1 )
  581. glMatrixMode( GL_MODELVIEW )
  582. End Method
  583. Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Override
  584. Return TGLRenderImageFrame.Create(width, height, flags)
  585. EndMethod
  586. Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override
  587. If RenderImageFrame = _CurrentRenderImageFrame
  588. Return
  589. EndIf
  590. glBindFrameBuffer(GL_FRAMEBUFFER, TGLRenderImageFrame(RenderImageFrame).FBO)
  591. _CurrentRenderImageFrame = TGLRenderImageFrame(RenderImageFrame)
  592. Local vp:Rect = _GLScissor_BMaxViewport
  593. SetScissor(vp.x, vp.y, vp.width, vp.height)
  594. SetMatrixAndViewportToCurrentRenderImage()
  595. EndMethod
  596. Method SetBackbuffer()
  597. SetRenderImageFrame(_BackBufferRenderImageFrame)
  598. EndMethod
  599. Private
  600. Method SetMatrixAndViewportToCurrentRenderImage()
  601. glMatrixMode(GL_PROJECTION)
  602. glLoadIdentity()
  603. glOrtho(0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height, 0, -1, 1)
  604. glMatrixMode(GL_MODELVIEW)
  605. glLoadIdentity()
  606. glViewport(0, 0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height)
  607. EndMethod
  608. Method SetScissor(x:Int, y:Int, w:Int, h:Int)
  609. Local ri:TImageFrame = _CurrentRenderImageFrame
  610. If x = 0 And y = 0 And w = _CurrentRenderImageFrame.width And h = _CurrentRenderImageFrame.height
  611. glDisable(GL_SCISSOR_TEST)
  612. Else
  613. glEnable(GL_SCISSOR_TEST)
  614. glScissor(x, _CurrentRenderImageFrame.height - y - h, w, h)
  615. EndIf
  616. EndMethod
  617. End Type
  618. Rem
  619. bbdoc: Get OpenGL Max2D Driver
  620. about:
  621. The returned driver can be used with #SetGraphicsDriver to enable OpenGL Max2D
  622. rendering.
  623. End Rem
  624. Function GLMax2DDriver:TGLMax2DDriver()
  625. Global _done:Int
  626. If Not _done
  627. _driver=New TGLMax2DDriver.Create()
  628. _done=True
  629. EndIf
  630. Return _driver
  631. End Function
  632. Local driver:TGLMax2DDriver=GLMax2DDriver()
  633. If driver SetGraphicsDriver driver
  634. ?