glsdlmax2d.bmx 23 KB

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