Procházet zdrojové kódy

Merge pull request #54 from GWRon/feat_render2texture_update

[Max2D] Update render2texture base
Brucey před 2 roky
rodič
revize
c4babea64a

+ 281 - 454
d3d9sdlmax2d.mod/d3d9sdlmax2d.bmx

@@ -45,6 +45,10 @@ Global _d3dDev:IDirect3DDevice9
 Global _d3d9Graphics:TD3D9SDLGraphics
 Global _max2dGraphics:TMax2dGraphics
 
+Global _BackbufferRenderImageFrame:TD3D9RenderImageFrame
+Global _CurrentRenderImageFrame:TD3D9RenderImageFrame
+Global _D3D9Scissor_BMaxViewport:Rect = New Rect
+
 Function Pow2Size:Int( n:Int )
 	Local t:Int=1
 	While t<n
@@ -72,7 +76,7 @@ Type TD3D9ImageFrame Extends TImageFrame
 		If _texture
 			If _seq=GraphicsSeq
 				If _texture=_bound_texture
-					_d3dDev.SetTexture 0,nullBaseTexture9
+					_d3dDev.SetTexture 0,Null
 					_bound_texture=Null
 				EndIf
 				_d3d9Graphics.ReleaseNow _texture
@@ -100,7 +104,7 @@ Type TD3D9ImageFrame Extends TImageFrame
 				EndIf
 			EndIf
 		Else
-			If pixmap.Format<>PF_BGRA8888 pixmap=pixmap.Convert( PF_BGRA8888 )
+			If pixmap.format<>PF_BGRA8888 pixmap=pixmap.Convert( PF_BGRA8888 )
 		EndIf
 
 		Local levels:Int=(flags & MIPMAPPEDIMAGE)=0
@@ -183,206 +187,67 @@ Type TD3D9ImageFrame Extends TImageFrame
 		
 		Return Self
 	End Method
-	
+
 	Method Draw( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float,sx:Float,sy:Float,sw:Float,sh:Float ) Override
-		Local u0:Float=sx * _uscale
-		Local v0:Float=sy * _vscale
-		Local u1:Float=(sx+sw) * _uscale
-		Local v1:Float=(sy+sh) * _vscale
-	
-		_fverts[0]=x0*_ix+y0*_iy+tx
-		_fverts[1]=x0*_jx+y0*_jy+ty
-		_iverts[3]=_color
-		_fverts[4]=u0
-		_fverts[5]=v0
-		
-		_fverts[6]=x1*_ix+y0*_iy+tx
-		_fverts[7]=x1*_jx+y0*_jy+ty
-		_iverts[9]=_color
-		_fverts[10]=u1
-		_fverts[11]=v0
-		
-		_fverts[12]=x1*_ix+y1*_iy+tx
-		_fverts[13]=x1*_jx+y1*_jy+ty
-		_iverts[15]=_color
-		_fverts[16]=u1
-		_fverts[17]=v1
-		
-		_fverts[18]=x0*_ix+y1*_iy+tx
-		_fverts[19]=x0*_jx+y1*_jy+ty
-		_iverts[21]=_color
-		_fverts[22]=u0
-		_fverts[23]=v1
+		Local u0:Float = sx * _uscale
+		Local v0:Float = sy * _vscale
+		Local u1:Float = (sx + sw) * _uscale
+		Local v1:Float = (sy + sh) * _vscale
+
+		_fverts[0] = x0 * _ix + y0 * _iy + tx
+		_fverts[1] = x0 * _jx + y0 * _jy + ty
+		_iverts[3] = _color
+		_fverts[4] = u0
+		_fverts[5] = v0
+		
+		_fverts[6] = x1 * _ix + y0 * _iy + tx
+		_fverts[7] = x1 * _jx + y0 * _jy + ty
+		_iverts[9] = _color
+		_fverts[10] = u1
+		_fverts[11] = v0
+		
+		_fverts[12] = x1 * _ix + y1 * _iy + tx
+		_fverts[13] = x1 * _jx + y1 * _jy + ty
+		_iverts[15] = _color
+		_fverts[16] = u1
+		_fverts[17] = v1
+		
+		_fverts[18] = x0 * _ix + y1 * _iy + tx
+		_fverts[19] = x0 * _jx + y1 * _jy + ty
+		_iverts[21] = _color
+		_fverts[22] = u0
+		_fverts[23] = v1
 		
 		If _texture<>_bound_texture
 			_d3dDev.SetTexture 0,_texture
-			_d3dDev.SetTextureStageState 0,D3DTSS_MAGFILTER,_magfilter
-			_d3dDev.SetTextureStageState 0,D3DTSS_MINFILTER,_minfilter
-			_d3dDev.SetTextureStageState 0,D3DTSS_MIPFILTER,_mipfilter
-			_bound_texture=_texture
+			_d3dDev.SetTextureStageState(0, D3DTSS_MAGFILTER, _magfilter)
+			_d3dDev.SetTextureStageState(0, D3DTSS_MINFILTER, _minfilter)
+			_d3dDev.SetTextureStageState(0, D3DTSS_MIPFILTER, _mipfilter)
+			_bound_texture = _texture
 		EndIf
 		
 		If Not _texture_enabled
-			_d3dDev.SetTextureStageState 0,D3DTSS_COLOROP,D3DTOP_MODULATE
-			_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAOP,D3DTOP_MODULATE
-			_texture_enabled=True
+			_d3dDev.SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_MODULATE)
+			_d3dDev.SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_MODULATE)
+			_texture_enabled = True
 		EndIf
 		
-		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLEFAN,2,_fverts,24
+		_d3dDev.DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, _fverts, 24)
 	End Method
 	
-	Field _texture:IDirect3DTexture9,_seq:Int
-	
-	Field _magfilter:Int,_minfilter:Int,_mipfilter:Int,_uscale:Float,_vscale:Float
-	
-	Field _fverts:Float[24],_iverts:Int Ptr=Int Ptr( Varptr _fverts[0] )
-
+	Field _texture:IDirect3DTexture9, _seq:Int
+	Field _magfilter:Int, _minfilter:Int, _mipfilter:Int, _uscale:Float, _vscale:Float
+	Field _fverts:Float[24], _iverts:Int Ptr = Int Ptr( Varptr _fverts[0] )
 End Type
 
-
-Type TD3D9RenderImageContext Extends TRenderImageContext
-	Field _gc:TD3D9SDLGraphics
-	Field _d3ddev:IDirect3DDevice9
-	Field _backbuffer:IDirect3DSurface9
-	Field _matrix:Float[16]
-	Field _viewport:D3DVIEWPORT9
-	Field _renderimages:TList
-	Field _deviceok:Int = True
-
-	Method Delete()
-		ReleaseNow()
-	EndMethod
-	
-	Method ReleaseNow()
-		If _renderimages
-			For Local ri:TD3D9RenderImage = EachIn _renderimages
-				ri.DestroyRenderImage()
-			Next
-		EndIf
-
-		_renderimages = Null
-		_viewport = Null
-		_gc = Null
-
-		If _backbuffer
-			_backbuffer.release_
-			_backbuffer = Null
-		EndIf
-		If _d3ddev
-			_d3ddev.release_
-			_d3ddev = Null
-		EndIf
-	EndMethod
-
-	Method Create:TD3D9RenderimageContext(g:TGraphics, driver:TGraphicsDriver)
-		_gc = TD3D9SDLGraphics(g)
-
-		_d3ddev = _gc.GetDirect3DDevice()
-		_d3ddev.AddRef()
-
-		_d3ddev.GetRenderTarget(0, _backbuffer)
-
-		_viewport = New D3DVIEWPORT9
-		_d3ddev.GetViewport(_viewport)
-		_d3ddev.GetTransform(D3DTS_PROJECTION, _matrix)
-			
-		_renderimages = New TList
-
-		Return Self
-	EndMethod
-	
-	Method GraphicsContext:TGraphics()
-		Return _gc
-	EndMethod
-	
-	Method Destroy()
-		ReleaseNow()
-	EndMethod
-
-	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseImageFiltering:Int)
-		Local renderimage:TD3D9RenderImage = New TD3D9RenderImage.CreateRenderImage(width, height)
-		renderimage.Init(_d3ddev, UseImageFiltering)
-		_renderimages.AddLast(renderimage)
-
-		Return renderimage
-	EndMethod
-	
-	Method CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, UseImageFiltering:Int)
-		Local renderimage:TD3D9RenderImage = New TD3D9RenderImage.CreateRenderImage(pixmap.Width, pixmap.Height)
-		renderimage.InitFromPixmap(_d3ddev, pixmap, UseImageFiltering)
-		_renderimages.AddLast(renderimage)
-
-		Return renderimage
-	EndMethod
-	
-	Method DestroyRenderImage(renderImage:TRenderImage)
-		renderImage.DestroyRenderImage()
-		_renderimages.Remove(renderImage)
-	EndMethod
-
-	Method SetRenderImage(renderimage:TRenderimage)
-		If Not renderimage
-			_d3ddev.SetRenderTarget(0, _backbuffer)	
-			_d3ddev.SetTransform D3DTS_PROJECTION,_matrix
-			_d3ddev.SetViewport(_viewport)
-		Else
-			renderimage.SetRenderImage()
-		EndIf
-	EndMethod
-	
-	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
-		Return TD3D9RenderImage(renderImage).ToPixmap()
-	EndMethod
-
-	Method OnDeviceLost()
-		If _deviceok = False Return
-
-		For Local ri:TD3D9RenderImage = EachIn _renderimages
-			ri.OnDeviceLost()
-		Next
-		If _backbuffer
-			_backbuffer.release_
-			_backbuffer = Null
-		EndIf
-
-		_deviceok = False
-	EndMethod
-
-	Method OnDeviceReset()
-		If _deviceok = True Return
-
-		Local hr:Int = _d3ddev.GetRenderTarget(0, _backbuffer)
-		hr = _d3ddev.GetViewport(_viewport)
-
-		For Local ri:TD3D9RenderImage = EachIn _renderimages
-			ri.OnDeviceReset()
-		Next
-
-		_deviceok = True
-	EndMethod
-
-	Function fnOnDeviceLost(obj:Object)
-		Local ric:TD3D9RenderImageContext = TD3D9RenderImageContext(obj)
-		If Not ric Return
-		ric.OnDeviceLost()
-	EndFunction
-
-	Function fnOnDeviceReset(obj:Object)
-		Local ric:TD3D9RenderImageContext = TD3D9RenderImageContext(obj)
-		If Not ric Return
-		ric.OnDeviceReset()
-	EndFunction
-EndType
-
-
-
 Type TD3D9RenderImageFrame Extends TD3D9ImageFrame
 	Field _surface:IDirect3DSurface9
-	Field _persistpixmap:TPixmap
+	Field _stagingPixmap:TPixmap
+	Field _width:UInt, _height:UInt
 
 	Method Delete()
 		ReleaseNow()
-	EndMethod
+	End Method
 	
 	Method ReleaseNow()
 		If _surface
@@ -393,98 +258,128 @@ Type TD3D9RenderImageFrame Extends TD3D9ImageFrame
 			_texture.Release_
 			_texture = Null
 		EndIf
-	EndMethod
-	
-	Method Clear(d3ddev:IDirect3DDevice9, r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
-		If Not d3ddev Return
-
-		Local c:Int = (int(a*255) Shl 24) | (r Shl 16) | (g Shl 8) | b
-		d3ddev.Clear(0, Null, D3DCLEAR_TARGET, c, 0.0, 0)
 	End Method
-	
-	Method CreateRenderTarget:TD3D9RenderImageFrame( d3ddev:IDirect3DDevice9, width:Int,height:Int )
-		d3ddev.CreateTexture(width,height,1,D3DUSAGE_RENDERTARGET,D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT,_texture,Null)
-		If _texture _texture.GetSurfaceLevel 0, _surface
+
+	Function Create:TD3D9RenderImageFrame(width:UInt, height:UInt, flags:Int )
+		Local D3D9Texture:IDirect3DTexture9
+		If _d3ddev.CreateTexture(width, height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,D3DPOOL_DEFAULT, D3D9Texture, Null) < 0
+			Throw "Could not create D3D9 Render Image : Width " + width + ", Height " + height + ", Flags " + flags
+			Return Null
+		EndIf
+
+		Local D3D9Surface:IDirect3DSurface9
+		If D3D9Texture
+			If D3D9Texture.GetSurfaceLevel(0, D3D9Surface) < 0
+				Throw "Could not get surface index 0 for D3D9 Render Image : Width " + width + ", Height " + height + ", Flags " + flags
+				Return Null
+			EndIf
+		EndIf
 		
-		_magfilter = D3DTFG_LINEAR
-		_minfilter = D3DTFG_LINEAR
-		_mipfilter = D3DTFG_LINEAR
+		Local RenderImage:TD3D9RenderImageFrame = New TD3D9RenderImageFrame
+		RenderImage._texture = D3D9Texture
+		RenderImage._surface = D3D9Surface
+		RenderImage._magfilter = D3DTFG_LINEAR
+		RenderImage._minfilter = D3DTFG_LINEAR
+		RenderImage._mipfilter = D3DTFG_LINEAR
 
-		_uscale = 1.0 / width
-		_vscale = 1.0 / height
+		RenderImage._uscale = 1.0 / width
+		RenderImage._vscale = 1.0 / height
+		RenderImage._width = width
+		RenderImage._height = height
 
-		Return Self
-	EndMethod
-	
-	Method DestroyRenderImage()
-		ReleaseNow()
-	EndMethod
+		Return RenderImage
+	End Function
 
-	Method OnDeviceLost(d3ddev:IDirect3DDevice9, width:Int, height:Int)
-		_persistpixmap = ToPixmap(d3ddev, width, height)
+	Method OnDeviceLost()
+		Local BackBuffer:TD3D9RenderImageFrame = _BackBufferRenderImageFrame
+		If Self <> BackBuffer And Not _stagingpixmap
+			If _surface
+				_stagingPixmap  = RenderTargetToPixmap()
+			EndIf
+		EndIf
 		ReleaseNow()
-	EndMethod
+	End Method
 
-	Method OnDeviceReset(d3ddev:IDirect3DDevice9)
-		If(_persistpixmap)
-			d3ddev.CreateTexture(_persistpixmap.width, _persistpixmap.height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, _texture, Null)
-			If _texture
-				_texture.GetSurfaceLevel(0, _surface)
+	Method OnDeviceReset()		
+		' dont re-create until the device is ready
+		If _d3dDev.TestCooperativeLevel() = 0
+			If(_stagingPixmap)
+				LoadFromPixmap(_stagingPixmap)
+				_stagingPixmap = Null
 			EndIf
+		EndIf
+	End Method
 
-			FromPixmap(d3ddev, _persistpixmap)
+Private
+	Method LoadFromPixmap(pixmap:TPixmap)
+		If _d3ddev.CreateTexture(_width, _height, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, _texture, Null) < 0
+			Throw "Failed to create render target"
+			Return
+		EndIf
+		
+		If _texture.GetSurfaceLevel(0, _surface) < 0
+			Throw "Failed to get surface of render target"
+			ReleaseNow()
+			Return
 		EndIf
 
-		_persistpixmap = Null
-	EndMethod
-	
-	Method FromPixmap(d3ddev:IDirect3DDevice9, pixmap:TPixmap)
-		' use a staging surface to copy the pixmap into
-		Local stage:IDirect3DSurface9
-		d3ddev.CreateOffscreenPlainSurface(pixmap.width, pixmap.height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, stage, Null)
+		Local replacementSurface:IDirect3DSurface9
+		If _d3ddev.CreateOffscreenPlainSurface(_width, _height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, replacementSurface, Null) < 0
+			Throw "Failed to create a replacement surface"
+			ReleaseNow()
+			Return
+		EndIf
 
 		Local lockedrect:D3DLOCKED_RECT = New D3DLOCKED_RECT
-		stage.LockRect(lockedrect, Null, 0)
+		If replacementSurface.LockRect(lockedrect, Null, 0) < 0
+			Throw "Failed to lock the replacement surface"
+			ReleaseNow()
+			replacementSurface.Release_()
+			Return
+		EndIf
 
-		' copy the pixel data across
-		For Local y:Int = 0 Until pixmap.height
+		For Local y:Int = 0 Until _height
 			Local srcptr:Byte Ptr = pixmap.pixels + y * pixmap.pitch
 			Local dstptr:Byte Ptr = lockedrect.pBits + y * lockedrect.Pitch
 			MemCopy dstptr, srcptr, Size_T(pixmap.width * 4)
 		Next
-		stage.UnlockRect()
+		replacementSurface.UnlockRect()
 
-		' copy from the staging surface to the render surface
-		d3ddev.UpdateSurface(stage, Null, _surface, Null)
+		If _d3ddev.UpdateSurface(replacementSurface, Null, _surface, Null) < 0
+			Throw "Failed to copy the replacement surface texture data to the render target"
+			ReleaseNow()
+			replacementSurface.Release_()
+			Return
+		EndIf
 
-		' cleanup
-		stage.release_
-	EndMethod
+		replacementSurface.Release_()
+	End Method
 	
-	Method ToPixmap:TPixmap(d3ddev:IDirect3DDevice9, width:Int, height:Int)
-		Local pixmap:TPixmap = CreatePixmap(width, height, PF_RGBA8888)
-
+	Method RenderTargetToPixmap:TPixmap()	
 		' use a staging surface to get the texture contents
-		Local stage:IDirect3DSurface9
-		d3ddev.CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, stage, Null)
-
-		Local result:Int = d3ddev.GetRenderTargetData(_surface, stage)
-		If result < 0
-			If result = D3DERR_DRIVERINTERNALERROR
-				Throw "TD3D9RenderImageFrame:ToPixmap:GetRenderTargetData failed: D3DERR_DRIVERINTERNALERROR"
-			ElseIf result = D3DERR_DEVICELOST
-				'Throw "TD3D9RenderImageFrame:ToPixmap:GetRenderTargetData failed: D3DERR_DEVICELOST"
-			ElseIf result = D3DERR_INVALIDCALL
-				Throw "TD3D9RenderImageFrame:ToPixmap:GetRenderTargetData failed: D3DERR_INVALIDCALL"
-			Else
-				Throw "TD3D9RenderImageFrame:ToPixmap:GetRenderTargetData failed."
-			EndIf
+		Local StagingSurface:IDirect3DSurface9
+		If _d3ddev.CreateOffscreenPlainSurface(_width, _height, D3DFMT_A8R8G8B8, D3DPOOL_SYSTEMMEM, StagingSurface, Null) < 0
+			Throw "Failed to create staging texture to receive render target data"
+			Return Null
 		EndIf
-
+		
+		If _d3ddev.GetRenderTargetData(_surface, StagingSurface) < 0
+			Throw "Failed to get render target data from render target into the staging buffer"
+			StagingSurface.Release_()
+			Return Null
+		EndIf
+		
 		' copy the pixel data across
 		Local lockedrect:D3DLOCKED_RECT = New D3DLOCKED_RECT
-		If stage.LockRect(lockedrect, Null, 0) < 0 Throw "TD3D9RenderImageFrame:ToPixmap:LockRect failed"
+		If StagingSurface.LockRect(lockedrect, Null, 0) < 0
+			StagingSurface.UnlockRect()
+			StagingSurface.Release_()
+			Throw "Failed to lock the staging buffer to get pixel data"
+			StagingSurface.Release_()
+			Return Null
+		EndIf
 
+		Local pixmap:TPixmap = CreatePixmap(_width, _height, PF_RGBA8888)
 		For Local y:Int = 0 Until pixmap.height
 			For Local x:Int = 0 Until pixmap.width
 				Local srcptr:Int Ptr = Int Ptr (lockedrect.pBits + x * 4 + y * lockedrect.Pitch)
@@ -493,176 +388,11 @@ Type TD3D9RenderImageFrame Extends TD3D9ImageFrame
 			Next
 		Next
 		
-		pixmap = ConvertPixmap(pixmap, PF_BGRA)
-		
-		' cleanup
-		stage.UnlockRect()
-		stage.release_
-		
-		Return pixmap
-	EndMethod
-EndType
-
-Type TD3D9RenderImage Extends TRenderImage
-	Field _d3ddev:IDirect3DDevice9
-	Field _viewport:D3DVIEWPORT9
-	Field _matrix:Float[]
-
-	Method Delete()
-		ReleaseNow()
-	EndMethod
-	
-	Method ReleaseNow()
-		If _d3ddev
-			_d3ddev.release_
-			_d3ddev = Null
-		EndIf
-	EndMethod
-
-	Method CreateRenderImage:TD3D9RenderImage(width:Int ,height:Int)
-		Self.width=width	' TImage.width
-		Self.height=height	' TImage.height
-	
-		_matrix = [	2.0/width, 0.0, 0.0, 0.0,..
-					0.0, -2.0/height, 0.0, 0.0,..
-					0.0, 0.0, 1.0, 0.0,..
-					-1-(1.0/width), 1+(1.0/height), 1.0, 1.0 ]
-
-		_viewport = New D3DVIEWPORT9
-		_viewport.width = width
-		_viewport.height = height
-		_viewport.MaxZ = 1.0
-
-		Return Self
-	EndMethod
-	
-	Method DestroyRenderImage()
-		ReleaseNow()
-		TD3D9RenderImageFrame(frames[0]).ReleaseNow()
-	EndMethod
-
-	Method Init(d3ddev:IDirect3DDevice9, UseImageFiltering:Int)
-		_d3ddev = d3ddev
-		_d3ddev.AddRef()
-
-		frames = New TD3D9RenderImageFrame[1]
-		frames[0] = New TD3D9RenderImageFrame.CreateRenderTarget(d3ddev, width, height)
-		If UseImageFiltering
-			TD3D9RenderImageFrame(frames[0])._magfilter=D3DTFG_LINEAR
-			TD3D9RenderImageFrame(frames[0])._minfilter=D3DTFG_LINEAR
-			TD3D9RenderImageFrame(frames[0])._mipfilter=D3DTFG_LINEAR
-		Else
-			TD3D9RenderImageFrame(frames[0])._magfilter=D3DTFG_POINT
-			TD3D9RenderImageFrame(frames[0])._minfilter=D3DTFG_POINT
-			TD3D9RenderImageFrame(frames[0])._mipfilter=D3DTFG_POINT
-		EndIf
-
-
-		'  clear the new render target surface
-		Local prevsurf:IDirect3DSurface9
-		Local prevmatrix:Float[16]
-		Local prevviewport:D3DVIEWPORT9 = New D3DVIEWPORT9
+		StagingSurface.UnlockRect()
+		StagingSurface.Release_()
 		
-		' get previous
-		d3ddev.GetRenderTarget(0, prevsurf)
-		d3ddev.GetTransform(D3DTS_PROJECTION, prevmatrix)
-		d3ddev.GetViewport(prevviewport)
-
-		' set and clear
-		d3ddev.SetRenderTarget(0, TD3D9RenderImageFrame(frames[0])._surface)
-		d3ddev.SetTransform(D3DTS_PROJECTION, _matrix)
-		d3ddev.Clear(0, Null, D3DCLEAR_TARGET, 0, 0.0, 0)
-
-		' reset to previous
-		_d3ddev.SetRenderTarget(0, prevsurf)
-		_d3ddev.SetTransform(D3DTS_PROJECTION, prevmatrix)
-		_d3ddev.SetViewport(prevviewport)
-
-		' cleanup
-		prevsurf.release_
-	EndMethod
-	
-	Method InitFromPixmap(d3ddev:IDirect3DDevice9, Pixmap:TPixmap, UseImageFiltering:Int)
-		_d3ddev = d3ddev
-		_d3ddev.AddRef()
-
-		Pixmap = ConvertPixmap(pixmap, PF_BGRA)
-
-		frames = New TD3D9RenderImageFrame[1]
-		frames[0] = New TD3D9RenderImageFrame.CreateRenderTarget(d3ddev, width, height)
-		If UseImageFiltering
-			TD3D9RenderImageFrame(frames[0])._magfilter=D3DTFG_LINEAR
-			TD3D9RenderImageFrame(frames[0])._minfilter=D3DTFG_LINEAR
-			TD3D9RenderImageFrame(frames[0])._mipfilter=D3DTFG_LINEAR
-		Else
-			TD3D9RenderImageFrame(frames[0])._magfilter=D3DTFG_POINT
-			TD3D9RenderImageFrame(frames[0])._minfilter=D3DTFG_POINT
-			TD3D9RenderImageFrame(frames[0])._mipfilter=D3DTFG_POINT
-		EndIf
-
-		TD3D9RenderImageFrame(frames[0]).FromPixmap(d3ddev, Pixmap)
-	EndMethod
-
-	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
-		If frames[0] Then TD3D9RenderImageFrame(frames[0]).Clear(_d3ddev, r, g, b, a)
+		Return ConvertPixmap(pixmap, PF_BGRA)
 	End Method
-	
-	Method Frame:TImageFrame(index:Int=0)
-		If Not frames Return Null
-		If Not frames[0] Return Null
-		Return frames[0]
-	EndMethod
-	
-	Method SetRenderImage()
-		Local pTexture:IDirect3DTexture9
-		_d3ddev.GetTexture(0, pTexture)
-		
-		Local frame:TD3D9RenderImageFrame = TD3D9RenderImageFrame(frames[0])
-		If frame._texture <> pTexture
-			_d3ddev.SetTexture(0, pTexture)
-		EndIf
-		
-		If pTexture pTexture.Release_
-		
-		_d3ddev.SetRenderTarget(0, TD3D9RenderImageFrame(frames[0])._surface)
-		_d3ddev.SetTransform(D3DTS_PROJECTION,_matrix)
-		_d3ddev.SetViewport(_viewport)
-	EndMethod
-	
-	Method ToPixmap:TPixmap()
-		Return TD3D9RenderImageFrame(frames[0]).ToPixmap(_d3ddev, width, height)
-	EndMethod
-	
-	Method SetViewport(x:Int, y:Int, width:Int, height:Int)
-		If width = 0
-			width = Self.width
-			height = Self.height
-		EndIf
-
-		If x + width > Self.width
-			width:-(x + width - Self.width)
-		EndIf
-		If y + height > Self.height
-			height:-(y + height - Self.height)
-		EndIf
-
-		If x = 0 And y = 0 And width = Self.width And height = Self.height
-			_d3ddev.SetRenderState(D3DRS_SCISSORTESTENABLE, False)
-		Else
-			_d3ddev.SetRenderState(D3DRS_SCISSORTESTENABLE, True)
-			Local rect:Int[] = [x , y, x + width, y + height]
-			_d3ddev.SetScissorRect(rect)
-		EndIf
-
-	EndMethod
-
-	Method OnDeviceLost()
-		TD3D9RenderImageFrame(frames[0]).OnDeviceLost(_d3ddev, width, height)
-	EndMethod
-
-	Method OnDeviceReset()
-		TD3D9RenderImageFrame(frames[0]).OnDeviceReset(_d3ddev)
-	EndMethod
 EndType
 
 
@@ -672,11 +402,14 @@ Type TD3D9SDLMax2DDriver Extends TMax2dDriver
 		Return "DirectX9"
 	End Method
 
-	Method Create:TD3D9SDLMax2DDriver()
+	Method ApiIdentifier:String() Override
+		Return "SDL.Direct3D9"
+	End Method
 
+	Method Create:TD3D9SDLMax2DDriver()
 		If Not D3D9SDLGraphicsDriver() Return Null
 
-		Local d3d:IDirect3D9=D3D9SDLGraphicsDriver().GetDirect3D()
+		Local d3d:IDirect3D9 = D3D9SDLGraphicsDriver().GetDirect3D()
 
 		If d3d.CheckDeviceFormat( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,0,D3DRTYPE_TEXTURE,D3DFMT_A8R8G8B8 )<0
 			Return Null
@@ -717,7 +450,7 @@ Type TD3D9SDLMax2DDriver Extends TMax2dDriver
 
 		_max2dGraphics=TMax2dGraphics( g )
 
-		_d3d9graphics=TD3D9SDLGraphics( _max2dGraphics._graphics )
+		_d3d9graphics=TD3D9SDLGraphics( _max2dGraphics._backendGraphics )
 
 		If Not _max2dGraphics Or Not _d3d9graphics Then
 			Throw "SetGraphics failed for D3D9"
@@ -753,11 +486,11 @@ Type TD3D9SDLMax2DDriver Extends TMax2dDriver
 		Local viewport:D3DVIEWPORT9
 		viewport.X = 0
 		viewport.Y = 0
-		viewport.Width = _gw
-		viewport.Height = _gh
+		viewport.width = _gw
+		viewport.height = _gh
 		viewport.MinZ = 0.0
 		viewport.MaxZ = 1.0
-		_d3dDev.SetViewport viewport
+		_d3dDev.SetViewport(viewport)
 
 		_d3dDev.SetRenderState D3DRS_ALPHAREF,$80
 		_d3dDev.SetRenderState D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL
@@ -769,7 +502,7 @@ Type TD3D9SDLMax2DDriver Extends TMax2dDriver
 		_d3dDev.SetRenderState D3DRS_LIGHTING,False
 		_d3dDev.SetRenderState D3DRS_CULLMODE,D3DCULL_NONE	
 		
-		_d3dDev.SetTexture 0,nullBaseTexture9
+		_d3dDev.SetTexture 0,Null
 		_bound_texture=Null
 
 		_d3dDev.SetFVF D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1
@@ -789,14 +522,15 @@ Type TD3D9SDLMax2DDriver Extends TMax2dDriver
 		_d3dDev.SetTextureStageState 0,D3DTSS_MIPFILTER,D3DTFP_POINT
 		
 		_d3dDev.BeginScene
-
+		
+		_d3d9graphics.AddDeviceLostCallback(OnDeviceLost, Self)
+		_d3d9graphics.AddDeviceResetCallback(OnDeviceReset, Self)
+		
+		' Create default back buffer render image
+		AssignBackBufferRenderImage()
 	End Method
 
 	'***** TMax2DDriver *****
-	Method CreateRenderImageContext:Object(g:TGraphics) Override
-		Return New TD3D9RenderImageContext.Create(g, Self)
-	End Method
-
 	Method CreateFrameFromPixmap:TImageFrame( pixmap:TPixmap,flags:Int ) Override
 		Return New TD3D9ImageFrame.Create( pixmap,flags )
 	End Method
@@ -848,34 +582,21 @@ Type TD3D9SDLMax2DDriver Extends TMax2dDriver
 		_iverts[15]=_color
 		_iverts[21]=_color
 	End Method
-
-	Method SetColor( color:SColor8 ) Override
-		_color=(_color&$ff000000)|color.ToARGB()		
-		_iverts[3]=_color
-		_iverts[9]=_color
-		_iverts[15]=_color
-		_iverts[21]=_color
-	End Method
 	
-	Method SetClsColor( red:Int,green:Int,blue:Int ) Override
-		red=Max(Min(red,255),0)
-		green=Max(Min(green,255),0)
-		blue=Max(Min(blue,255),0)
-		_clscolor=$ff000000|(red Shl 16)|(green Shl 8)|blue
-	End Method
-
-	Method SetClsColor( color:SColor8 ) Override
-		_clscolor=$ff000000|color.ToARGB()
+	Method SetClsColor( red:Int,green:Int,blue:Int, alpha:Float ) Override
+		red = Max(Min(red, 255), 0)
+		green = Max(Min(green, 255), 0)
+		blue = Max(Min(blue, 255), 0)
+		Local a:Int = Max(Min(alpha * 255.0, 255), 0)
+		_clscolor = (a Shl 24) | (red Shl 16) | (green Shl 8) | blue
 	End Method
 	
 	Method SetViewport( x:Int,y:Int,width:Int,height:Int ) Override
-		If x=0 And y=0 And width=_gw And height=_gh 'GraphicsWidth() And height=GraphicsHeight()
-			_d3dDev.SetRenderState D3DRS_SCISSORTESTENABLE,False
-		Else
-			_d3dDev.SetRenderState D3DRS_SCISSORTESTENABLE,True
-			Local rect:Int[]=[x,y,x+width,y+height]
-			_d3dDev.SetScissorRect rect
-		EndIf
+		_D3D9Scissor_BMaxViewport.x = x
+		_D3D9Scissor_BMaxViewport.y = y
+		_D3D9Scissor_BMaxViewport.width = width
+		_D3D9Scissor_BMaxViewport.height = height
+		SetScissor(x, y, width, height)
 	End Method
 	
 	Method SetTransform( xx:Float,xy:Float,yx:Float,yy:Float ) Override
@@ -1021,6 +742,11 @@ Type TD3D9SDLMax2DDriver Extends TMax2dDriver
 
 	'GetDC/BitBlt MUCH faster than locking backbuffer!	
 	Method GrabPixmap:TPixmap( x:Int,y:Int,width:Int,height:Int ) Override
+		'for render targets we handle it differently to the backbuffer
+		If _CurrentRenderImageFrame <> _BackBufferRenderImageFrame
+			Return _CurrentRenderImageFrame.RenderTargetToPixmap()
+		EndIf
+
 	
 		Local srcsurf:IDirect3DSurface9
 		If _d3dDev.GetRenderTarget( 0,srcsurf )<0
@@ -1079,6 +805,107 @@ Type TD3D9SDLMax2DDriver Extends TMax2dDriver
 		_d3dDev.SetTransform D3DTS_PROJECTION,matrix
 	End Method
 	
+	' Render Image --------------------
+	Method AssignBackBufferRenderImage()
+		Local BackBufferRenderImageFrame:TD3D9RenderImageFrame = New TD3D9RenderImageFrame
+		BackBufferRenderImageFrame._width = _gw
+		BackBufferRenderImageFrame._height = _gh
+		_d3dDev.GetBackBuffer(0, 0, 0, Varptr BackBufferRenderImageFrame._surface)
+	
+		' cache it
+		_BackBufferRenderImageFrame = BackBufferRenderImageFrame
+		_CurrentRenderImageFrame = _BackBufferRenderImageFrame
+		
+		AddToRenderImageList(BackBufferRenderImageFrame)
+	EndMethod
+	
+	Method AddToRenderImageList(RenderImage:TD3D9RenderImageFrame)
+		_RenderImageList.AddLast(RenderImage)
+	EndMethod
+	
+	Method RemoveFromRenderImageList(RenderImage:TD3D9RenderImageFrame)
+		If(_RenderImageList.Contains(RenderImage))
+			_RenderImageList.Remove(RenderImage)
+		EndIf
+	EndMethod
+
+	Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Override
+		Local RenderImage:TD3D9RenderImageFrame = TD3D9RenderImageFrame.Create(width, height, flags)
+		AddToRenderImageList(RenderImage)
+		Return RenderImage
+	EndMethod
+	
+	Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override
+		If RenderImageFrame = _CurrentRenderImageFrame
+			Return
+		EndIf
+
+		Local D3D9RenderImageFrame:TD3D9RenderImageFrame = TD3D9RenderImageFrame(RenderImageFrame)
+		_d3dDev.SetRenderTarget(0, D3D9RenderImageFrame._surface)
+		_CurrentRenderImageFrame = D3D9RenderImageFrame
+		
+		Local vp:Rect = _D3D9Scissor_BMaxViewport
+		SetScissor(vp.x, vp.y, vp.width, vp.height)
+		SetMatrixAndViewportToCurrentRenderImage()
+	EndMethod
+	
+	Method SetBackbuffer()
+		SetRenderImageFrame(_BackBufferRenderImageFrame)
+	EndMethod
+	
+	Function OnDeviceLost(obj:Object)
+		Local Driver:TD3D9SDLMax2DDriver = TD3D9SDLMax2DDriver(obj)
+		Local RenderImageList:TList = Driver._RenderImageList
+		
+		For Local RenderImage:TD3D9RenderImageFrame = EachIn RenderImageList
+			RenderImage.OnDeviceLost()
+		Next
+		Driver.RemoveFromRenderImageList(_BackBufferRenderImageFrame)
+	EndFunction
+	
+	Function OnDeviceReset(obj:Object)
+		Local Driver:TD3D9SDLMax2DDriver = TD3D9SDLMax2DDriver(obj)
+		Local RenderImageList:TList = Driver._RenderImageList
+
+		For Local RenderImage:TD3D9RenderImageFrame = EachIn RenderImageList
+			RenderImage.OnDeviceReset()
+		Next
+	EndFunction
+		
+Private
+	Field _RenderImageList:TList = New TList
+	
+	Method SetMatrixAndViewportToCurrentRenderImage()
+		Local width:Float = _CurrentRenderImageFrame._width
+		Local height:Float = _CurrentRenderImageFrame._height
+		
+		Local matrix#[] = [..
+		2.0 / width, 0.0, 0.0, 0.0,..
+		0.0, -2.0/height, 0.0, 0.0,..
+		0.0, 0.0, 1.0, 0.0,..
+		-1 - (1.0 / width), 1 + (1.0 / height), 1.0, 1.0]
+
+		_d3dDev.SetTransform D3DTS_PROJECTION,matrix
+		
+		Local Viewport:D3DViewport9 = New D3DViewport9
+		Viewport.X = 0
+		Viewport.Y = 0
+		Viewport.width = width
+		Viewport.height = height
+		Viewport.MinZ = 0.0
+		Viewport.MaxZ = 1.0
+		_d3dDev.SetViewport(Viewport)
+	EndMethod
+
+	Method SetScissor(x:Int, y:Int, width:Int, height:Int)
+		If x = 0 And y = 0 And width = _CurrentRenderImageFrame._width And height = _CurrentRenderImageFrame._height
+			_d3dDev.SetRenderState(D3DRS_SCISSORTESTENABLE, False)
+		Else
+			_d3dDev.SetRenderState(D3DRS_SCISSORTESTENABLE, True)
+			Local Scissor:Rect = New Rect(x, y, x + width, y + height)
+			_d3dDev.SetScissorRect(Varptr Scissor)
+		EndIf
+	EndMethod
 End Type
 
 Rem

+ 3 - 1
gl2sdlmax2d.mod/gl2sdlmax2d.bmx

@@ -8,11 +8,13 @@ Legacy fixed functionality is included for testing purposes if GLMAX2D_USE_LEGAC
 End Rem
 Module SDL.GL2SDLMax2D
 
-ModuleInfo "Version: 1.01"
+ModuleInfo "Version: 1.02"
 ModuleInfo "Author: Mark Sibly, Bruce Henderson, Emil Andersson"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
 
+ModuleInfo "History: 1.02"
+ModuleInfo "History: Added RenderImages / render2texture"
 ModuleInfo "History: 1.01"
 ModuleInfo "History: Changed to SuperStrict"
 ModuleInfo "History: Extended flags to Long"

+ 226 - 342
gl2sdlmax2d.mod/main.bmx

@@ -2,7 +2,7 @@ SuperStrict
 
 Import brl.Max2D
 Import SDL.SDLGraphics
-Import brl.StandardIO
+Import brl.Threads
 ?Not opengles
 Import pub.glew
 Import Pub.OpenGL
@@ -12,8 +12,23 @@ Import Pub.OpenGLES
 
 Private
 
+Struct Rect
+	Method New (X:Int, Y:Int, width:Int, height:Int)
+		Self.X = X
+		Self.Y = Y
+		Self.width = width
+		Self.height = height
+	EndMethod
+	
+	Field X:Int, Y:Int
+	Field width:Int, height:Int
+EndStruct
+
 'Const GLMAX2D_USE_LEGACY = False
 Global _driver:TGL2Max2DDriver
+Global _BackbufferRenderImageFrame:TGL2SDLRenderImageFrame
+Global _CurrentRenderImageFrame:TGL2SDLRenderImageFrame
+Global _GLScissor_BMaxViewport:Rect = New Rect
 
 'Naughty!
 Const GL_BGR:Int = $80E0
@@ -56,45 +71,32 @@ Function Pow2Size:Int( n:Int )
 	Return t
 End Function
 
-Global dead_texs:Int[],n_dead_texs:Int,dead_tex_seq:Int,n_live_texs:Int
-
-Extern
-	Function bbAtomicAdd:Int( target:Int Ptr,value:Int )="int bbAtomicAdd( int *,int )!"
-End Extern
+Global dead_texs:TDynamicArray = New TDynamicArray(32)
+Global dead_tex_seq:Int
 
 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
 Function DeleteTex( name:Int,seq:Int )
 	If seq<>dead_tex_seq Return
 	
-	Local n:Int = bbAtomicAdd(Varptr n_dead_texs, 1)
-	bbAtomicAdd(Varptr n_live_texs, -1)
-
-	dead_texs[n] = name
-End Function
-
-Function _ManageDeadTexArray()
-	If dead_texs.length <= n_live_texs
-		' expand array so it's large enough to hold all the current live textures.
-		dead_texs=dead_texs[..n_live_texs+20]
-	EndIf
+	dead_texs.AddLast(name)
 End Function
 
-Function CreateTex:Int( width:Int, height:Int, flags:Int )
+Function CreateTex:Int( width:Int,height:Int,flags:Int,pixmap:TPixmap )
+	If pixmap.dds_fmt<>0 Return pixmap.tex_name ' if dds texture already exists
 
 	'alloc new tex
 	Local name:Int
 	glGenTextures( 1, Varptr name )
 
-	n_live_texs :+ 1
-	_ManageDeadTexArray()
-
 	'flush dead texs
-	If dead_tex_seq = GraphicsSeq
-		For Local i:Int = 0 Until n_dead_texs
-			glDeleteTextures( 1, Varptr dead_texs[i] )
-		Next
+	If dead_tex_seq=GraphicsSeq
+		Local n:Int = dead_texs.RemoveLast()
+		While n <> $FFFFFFFF
+			glDeleteTextures(1, Varptr n)
+			n = dead_texs.RemoveLast()
+		Wend
 	EndIf
-	n_dead_texs = 0
+
 	dead_tex_seq = GraphicsSeq
 
 	'bind new tex
@@ -131,22 +133,20 @@ Function CreateTex:Int( width:Int, height:Int, flags:Int )
 	Forever
 
 	Return name
-
 End Function
 
 'NOTE: Assumes a bound texture.
 Function UploadTex( pixmap:TPixmap, flags:Int )
-
 	Local mip_level:Int
+	If pixmap.dds_fmt <> 0 Then Return ' if dds texture already exists
 	Repeat
-
 		glTexImage2D( GL_TEXTURE_2D, mip_level, GL_RGBA, pixmap.width, pixmap.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null )
 		For Local y:Int = 0 Until pixmap.height
 			Local row:Byte Ptr = pixmap.pixels + ( y * pixmap.width ) * 4
 			glTexSubImage2D( GL_TEXTURE_2D, mip_level, 0, y, pixmap.width, 1, GL_RGBA, GL_UNSIGNED_BYTE, row )
 		Next
 
-		If Not ( flags & MIPMAPPEDIMAGE ) Exit
+		If Not ( flags & MIPMAPPEDIMAGE ) Then Exit
 		If pixmap.width > 1 And pixmap.height > 1
 			pixmap = ResizePixmap( pixmap, pixmap.width / 2, pixmap.height / 2 )
 		Else If pixmap.width > 1
@@ -168,6 +168,7 @@ Function AdjustTexSize( width:Int Var, height:Int Var )
 	height = Pow2Size( height )
 
 	Return ' assume this size is fine...
+	Rem
 	Repeat
 		Local t:Int
 		glTexImage2D( GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null )
@@ -181,9 +182,66 @@ Function AdjustTexSize( width:Int Var, height:Int Var )
 		If width > 1 width :/ 2
 		If height > 1 height :/ 2
 	Forever
-
+	EndRem
 End Function
 
+Type TDynamicArray
+
+	Private
+
+	Field data:Int Ptr
+	Field size:Size_T
+	Field capacity:Size_T
+
+	Field guard:TMutex
+
+	Public
+
+	Method New(initialCapacity:Int = 8)
+		capacity = initialCapacity
+		data = malloc_(Size_T(initialCapacity * 4))
+		guard = CreateMutex()
+	End Method
+
+	Method AddLast(value:Int)
+		guard.Lock()
+		If size = capacity Then
+			capacity :* 2
+			Local d:Byte Ptr = realloc_(data, capacity * 4)
+			If Not d Then
+				Throw "Failed to allocate more memory"
+			End If
+			data = d
+		End If
+
+		data[size] = value
+		size :+ 1
+		guard.Unlock()
+	End Method
+
+	Method RemoveLast:Int()
+		guard.Lock()
+		Local v:Int
+
+		If size > 0 Then
+			size :- 1
+			v = data[size]
+		Else
+			v = $FFFFFFFF
+		End If
+
+		guard.Unlock()
+
+		Return v
+	End Method
+
+	Method Delete()
+		free_(data)
+		CloseMutex(guard)
+	End Method
+
+End Type
+
 Function DefaultVShaderSource:String()
 
 	Local str:String = ""
@@ -291,137 +349,34 @@ Function DefaultTextureFShaderSource:String()
 
 End Function
 
-
-Global glewIsInit:Int
-
-Type TGL2SDLRenderImageContext Extends TRenderImageContext
-	Field _gc:TGraphics
-	Field _driver:TGraphicsDriver
-	Field _backbuffer:Int
-	Field _width:Int
-	Field _height:Int
-	Field _renderimages:TList
+Type TGL2SDLRenderImageFrame Extends TGLImageFrame
+	Field FBO:Int
+	Field width:Int
+	Field height:Int
 	
-	Field _matrix:TMatrix
-
-	Method Delete()
-		Destroy()
-	EndMethod
+	Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
+		Assert seq=GraphicsSeq Else "Image does not exist"
 
-	Method Destroy()
-		_gc = Null
-
-		If _renderimages
-			For Local ri:TGL2SDLRenderImage = EachIn _renderimages
-				ri.DestroyRenderImage()
-			Next
-		EndIf
-	EndMethod
-
-	Method Create:TGL2SDLRenderimageContext(gc:TGraphics, driver:TGraphicsDriver)
-		If Not glewIsInit
-			glewInit
-			glewIsInit = True
-		EndIf
-
-		_renderimages = New TList
-		_gc = TMax2DGraphics(gc)
-		_driver = TMax2DDriver(driver)
-		
-		_width = GraphicsWidth()
-		_height = GraphicsHeight()
-
-		' get the backbuffer - usually 0
-		glGetIntegerv(GL_FRAMEBUFFER_BINDING, Varptr _backbuffer)
-		
-		'glGetFloatv(GL_PROJECTION_MATRIX, _matrix)
-		_matrix = TGL2Max2DDriver(driver).u_pmatrix
+		' Note for a TGLRenderImage the V texture coordinate is flipped compared to the regular TImageFrame.Draw method
+		Local u0:Float = sx * uscale
+		Local v0:Float = (sy + sh) * vscale
+		Local u1:Float = (sx + sw) * uscale
+		Local v1:Float = sy * vscale
 		
-		Return Self
-	EndMethod
-
-	Method GraphicsContext:TGraphics()
-		Return _gc
-	EndMethod
-
-	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseImageFiltering:Int)
-		Local renderimage:TGL2SDLRenderImage = New TGL2SDLRenderImage.CreateRenderImage(width, height)
-		renderimage.Init(_gc, _driver, UseImageFiltering, Null)
-		Return  renderimage
-	EndMethod
-	
-	Method CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, UseImageFiltering:Int)
-		Local renderimage:TGL2SDLRenderImage = New TGL2SDLRenderImage.CreateRenderImage(pixmap.width, pixmap.height)
-		renderimage.Init(_gc, _driver, UseImageFiltering, pixmap)
-		Return  renderimage
+		_driver.DrawTexture( name, u0, v0, u1, v1, x0, y0, x1, y1, tx, ty, Self )
 	EndMethod
 	
-	Method DestroyRenderImage(renderImage:TRenderImage)
-		renderImage.DestroyRenderImage()
-		_renderImages.Remove(renderImage)
-	EndMethod
-
-	Method SetRenderImage(renderimage:TRenderimage)
-		Local driver:TGL2Max2DDriver = TGL2Max2DDriver(_driver)
-		driver.Flush()
-			
-		If Not renderimage
-			glBindFramebuffer(GL_FRAMEBUFFER,_backbuffer)
+	Function Create:TGL2SDLRenderImageFrame(width:UInt, height:UInt, flags:Int)
+		' store so that we can restore once the fbo is created
+		Local ScissorTestEnabled:Int = GlIsEnabled(GL_SCISSOR_TEST)
+		glDisable(GL_SCISSOR_TEST)
 		
-			driver.u_pmatrix = _matrix
-			
-			glViewport(0,0,_width,_height)
-		Else
-			renderimage.SetRenderImage()
-		EndIf
-	EndMethod
-	
-	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
-		Return TGL2SDLRenderImage(renderImage).ToPixmap()
-	EndMethod
-EndType
-
-
-
-Type TGL2SDLRenderImageFrame Extends TGLImageFrame
-	Field _fbo:Int
-	
-	Method Delete()
-		DeleteFramebuffer
-	EndMethod
-	
-	Method DeleteFramebuffer()
-		If _fbo
-			glDeleteFramebuffers(1, Varptr _fbo)
-			_fbo = -1 '???
-		EndIf
-	EndMethod
-	
-	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
-		'backup current
-		Local c:Float[4]
-		glGetFloatv(GL_COLOR_CLEAR_VALUE, c)		
-
-		glClearColor(r/255.0, g/255.0, b/255.0, a)
-		glClear(GL_COLOR_BUFFER_BIT)
-
-		glClearColor(c[0], c[1], c[2], c[3])
-	End Method
-
-	Method CreateRenderTarget:TGL2SDLRenderImageFrame(width:Int, height:Int, UseImageFiltering:Int, pixmap:TPixmap)
-		If pixmap pixmap = ConvertPixmap(pixmap, PF_RGBA)
+		Local TextureName:Int
+		glGenTextures(1, Varptr TextureName)
+		glBindTexture(GL_TEXTURE_2D, TextureName)
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
 		
-		glDisable(GL_SCISSOR_TEST)
-
-		glGenTextures(1, Varptr name)
-		glBindTexture(GL_TEXTURE_2D, name)
-		If pixmap
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap.pixels)
-		Else
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
-		EndIf
-
-		If UseImageFiltering
+		If flags & FILTEREDIMAGE
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
 		Else
@@ -429,113 +384,41 @@ Type TGL2SDLRenderImageFrame Extends TGLImageFrame
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
 		EndIf
 		
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
 		
-		glGenFramebuffers(1,Varptr _fbo)
-		glBindFramebuffer GL_FRAMEBUFFER,_fbo
-
-		glBindTexture GL_TEXTURE_2D,name
-		glFramebufferTexture2D GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,name,0
-
-		If Not pixmap
-			Clear()
-		EndIf
-
-		uscale = 1.0 / width
-		vscale = 1.0 / height
-
-		Return Self
-	EndMethod
-	
-	Method DestroyRenderTarget()
-		DeleteFramebuffer()
-	EndMethod
-	
-	Method ToPixmap:TPixmap(width:Int, height:Int)
-		Local prevTexture:Int
-		Local prevFBO:Int
+		Local FrameBufferObject:Int
+		glGenFramebuffers(1, Varptr FrameBufferObject)
+		glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferObject)
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureName, 0)
 		
-		glGetIntegerv(GL_TEXTURE_BINDING_2D,Varptr prevTexture)
-		glBindTexture(GL_TEXTURE_2D,name)
-
-		Local pixmap:TPixmap = CreatePixmap(width, height, PF_RGBA8888)		
-		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap.pixels)
+		Local RenderTarget:TGL2SDLRenderImageFrame = New TGL2SDLRenderImageFrame
+		RenderTarget.name = TextureName
+		RenderTarget.FBO = FrameBufferObject
 		
-		glBindTexture(GL_TEXTURE_2D,prevTexture)
-				
-		Return pixmap
-	EndMethod
-EndType
-
-Type TGL2SDLRenderImage Extends TRenderImage
-	'Field _matrix:Float[16]
-	Field _matrix:TMatrix
-	Field _driver:TGL2Max2DDriver
-
-	Method CreateRenderImage:TGL2SDLRenderImage(width:Int, height:Int)
-		Self.width = width	' TImage.width
-		Self.height = height	' TImage.height
-
-		Return Self
-	EndMethod
-	
-	Method DestroyRenderImage()
-		TGL2SDLRenderImageFrame(frames[0]).DestroyRenderTarget()
-	EndMethod
-	
-	Method Init(g:TGraphics, driver:TGraphicsDriver, UseImageFiltering:Int, pixmap:TPixmap)
-		_driver = TGL2Max2DDriver(driver)
-		_matrix = New TMatrix
-	
-		'_matrix.SetOrthographic( 0, width, 0, height, -1, 1 )
-		_matrix.SetOrthographic( 0, width, height, 0, -1, 1 )
-	
-		Local prevFBO:Int
-		Local prevTexture:Int
-		Local prevScissorTest:Int
-
-		glGetIntegerv(GL_FRAMEBUFFER_BINDING, Varptr prevFBO)
-		glGetIntegerv(GL_TEXTURE_BINDING_2D,Varptr prevTexture)
-		glGetIntegerv(GL_SCISSOR_TEST, Varptr prevScissorTest)
+		RenderTarget.width = width
+		RenderTarget.height = height
+		RenderTarget.uscale = 1.0 / width
+		RenderTarget.vscale = 1.0 / height
+		RenderTarget.u1 = width * RenderTarget.uscale
+		RenderTarget.v1 = height * RenderTarget.vscale
 		
-		frames = New TGL2SDLRenderImageFrame[1]
-		frames[0] = New TGL2SDLRenderImageFrame.CreateRenderTarget(width, height, UseImageFiltering, pixmap)
+		If ScissorTestEnabled
+			glEnable(GL_SCISSOR_TEST)
+		EndIf
 		
-		If prevScissorTest glEnable(GL_SCISSOR_TEST)
-		glBindTexture GL_TEXTURE_2D,prevTexture
-		glBindFramebuffer GL_FRAMEBUFFER,prevFBO
-	EndMethod
+		Return RenderTarget
+	EndFunction
 	
-	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
-		If frames[0] Then TGL2SDLRenderImageFrame(frames[0]).Clear(r, g, b, a)
-	End Method
-
-	Method Frame:TImageFrame(index:Int=0)
-		Return frames[0]
-	EndMethod
-	
-	Method SetRenderImage()
-		glBindFrameBuffer(GL_FRAMEBUFFER, TGL2SDLRenderImageFrame(frames[0])._fbo)
-		_driver.u_pmatrix = _matrix
-		glViewport 0,0,width,height 
-	EndMethod
-	
-	Method ToPixmap:TPixmap()
-		Return TGL2SDLRenderImageFrame(frames[0]).ToPixmap(width, height)
+Private
+	Method Delete()
+		glDeleteFrameBuffers(1, Varptr FBO) ' gl ignores 0
 	EndMethod
-	
-	Method SetViewport(x:Int, y:Int, width:Int, height:Int)
-		If x = 0 And y = 0 And width = Self.width And height = Self.height
-			glDisable GL_SCISSOR_TEST
-		Else
-			glEnable GL_SCISSOR_TEST
-			glScissor x, y, width, height
-		EndIf
+
+	Method New()
 	EndMethod
 EndType
 
-
 Public
 
 '============================================================================================'
@@ -602,11 +485,13 @@ Type TGLImageFrame Extends TImageFrame
 				EndIf
 			EndIf
 		Else
-			If tex.format <> PF_RGBA8888 tex = tex.Convert( PF_RGBA8888 )
+			If tex.dds_fmt = 0 ' not dds
+				If tex.format <> PF_RGBA8888 Then tex = tex.Convert( PF_RGBA8888 )
+			EndIf
 		EndIf
 		
 		'create tex
-		Local name:Int = CreateTex( tex_w, tex_h, flags )
+		Local name:Int = CreateTex( tex_w, tex_h, flags, tex )
 		
 		'upload it
 		UploadTex( tex, flags )
@@ -974,34 +859,25 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 
 	'graphics driver overrides
 	Method GraphicsModes:TGraphicsMode[]() Override
-
 		Return SDLGraphicsDriver().GraphicsModes()
-
 	End Method
 
 	Method AttachGraphics:TMax2DGraphics( widget:Byte Ptr, flags:Long ) Override
-
 		Local g:TSDLGraphics = SDLGraphicsDriver().AttachGraphics( widget, flags )
 
 		If g Then Return TMax2DGraphics.Create( g, Self )
-
 	End Method
 	
 	Method CreateGraphics:TMax2DGraphics( width:Int, height:Int, depth:Int, hertz:Int, flags:Long, x:Int, y:Int ) Override
-
 		Local g:TSDLGraphics = SDLGraphicsDriver().CreateGraphics( width, height, depth, hertz, flags | SDL_GRAPHICS_GL, x, y )
 		
 		If g Then Return TMax2DGraphics.Create( g, Self )
-
 	End Method
 
 	Method SetGraphics( g:TGraphics ) Override
-
 		If Not g
-			TMax2DGraphics.ClearCurrent
-
-			SDLGraphicsDriver().SetGraphics Null
-			
+			TMax2DGraphics.ClearCurrent()
+			SDLGraphicsDriver().SetGraphics(Null)
 			inited = Null
 
 			Return
@@ -1009,14 +885,14 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 
 		Local t:TMax2DGraphics = TMax2DGraphics( g )
 		?Not opengles
-		Assert t And TSDLGraphics( t._graphics )
+		Assert t And TSDLGraphics( t._backendGraphics )
 		?
 
-		SDLGraphicsDriver().SetGraphics t._graphics
+		SDLGraphicsDriver().SetGraphics(t._backendGraphics)
 
-		ResetGLContext t
-		t.MakeCurrent
+		ResetGLContext(t)
 
+		t.MakeCurrent()
 	End Method
 	
 	Method ResetGLContext( g:TGraphics )
@@ -1044,37 +920,38 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		u_pmatrix = New TMatrix
 		u_pmatrix.SetOrthographic( 0, gw, 0, gh, -1, 1 )
 
+		' Create default back buffer render image - the FBO will be value 0 which is the default for the existing backbuffer
+		Local BackBufferRenderImageFrame:TGL2SDLRenderImageFrame = New TGL2SDLRenderImageFrame
+		BackBufferRenderImageFrame.width = gw
+		BackBufferRenderImageFrame.height = gh
+	
+		' cache it
+		_BackBufferRenderImageFrame = BackBufferRenderImageFrame
+		_CurrentRenderImageFrame = _BackBufferRenderImageFrame
 	End Method
 	
 	Method Flip:Int( sync:Int ) Override
-
 		Flush()
 
-		SDLGraphicsDriver().Flip sync
+		SDLGraphicsDriver().Flip(sync)
 ?ios
 		glViewport(0, 0, GraphicsWidth(), GraphicsHeight())
 ?
 	End Method
 
 	Method ToString:String() Override
-
 		Return "OpenGL"
-
 	End Method
 
-	Method CreateRenderImageContext:Object(g:TGraphics) Override
-		Return new TGL2SDLRenderImageContext.Create(g, self)
+	Method ApiIdentifier:String() Override
+		Return "SDL.OpenGL (GL2SDL)"
 	End Method
-	
-	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap, flags:Int ) Override
-		Local frame:TGLImageFrame
-		frame = TGLImageFrame.CreateFromPixmap( pixmap, flags )
-		Return frame
 
+	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap, flags:Int ) Override
+		Return TGLImageFrame.CreateFromPixmap( pixmap, flags )
 	End Method
-	
-	Method SetBlend( blend:Int ) Override
 
+	Method SetBlend( blend:Int ) Override
 		If state_blend = blend Return
 
 		?opengles
@@ -1083,7 +960,7 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		End If
 		?
 
-		state_blend=blend
+		state_blend = blend
 
 		Select blend
 		Case MASKBLEND
@@ -1125,70 +1002,48 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 			glDisable( GL_ALPHA_TEST )
 			?
 		End Select
-
 	End Method
 
 	Method SetAlpha( alpha:Float ) Override
-
 		If alpha > 1.0 Then alpha = 1.0
 		If alpha < 0.0 Then alpha = 0.0
 		color4f[3] = alpha
-
 	End Method
 
 	Method SetLineWidth( width:Float ) Override
-
 		glLineWidth( width )
-
 	End Method
 
 	Method SetColor( red:Int, green:Int, blue:Int ) Override
-
 		color4f[0] = Min( Max( red, 0 ), 255 ) / 255.0
 		color4f[1] = Min( Max( green, 0 ), 255 ) / 255.0
 		color4f[2] = Min( Max( blue, 0 ), 255 ) / 255.0
-
 	End Method
 
-	Method SetColor( color:SColor8 ) Override
-		color4f[0]=color.r / 255.0
-		color4f[1]=color.g / 255.0
-		color4f[2]=color.b / 255.0
-	End Method
-
-	Method SetClsColor( red:Int, green:Int, blue:Int ) Override
-
-		red = Min( Max( red, 0 ), 255 )
-		green = Min( Max( green, 0 ), 255 )
-		blue = Min( Max( blue, 0 ), 255 )
-		glClearColor( red / 255.0, green / 255.0, blue / 255.0, 1.0 )
+	Method SetClsColor( red:Int, green:Int, blue:Int, alpha:Float ) Override
+		red = Min(Max(red,0),255)
+		green = Min(Max(green,0),255)
+		blue = Min(Max(blue,0),255)
 
-	End Method
-
-	Method SetClsColor( color:SColor8 ) Override
-		glClearColor( color.r / 255.0, color.g / 255.0, color.b / 255.0, 1.0 )
+		glClearColor(red/255.0, green/255.0, blue/255.0, alpha)
 	End Method
 	
 	Method SetViewport( x:Int, y:Int, w:Int, h:Int ) Override
 		'render what has been batched till now
 		FlushTest( PRIMITIVE_VIEWPORT )
 
-		If x = 0 And y = 0 And w = GraphicsWidth() And h = GraphicsHeight()
-			glDisable( GL_SCISSOR_TEST )
-		Else
-			glEnable( GL_SCISSOR_TEST )
-			glScissor( x, GraphicsHeight() - y - h, w, h )
-		EndIf
-
+		_GLScissor_BMaxViewport.x = x
+		_GLScissor_BMaxViewport.y = y
+		_GLScissor_BMaxViewport.width = w
+		_GLScissor_BMaxViewport.height = h
+		SetScissor(x, y, w, h)
 	End Method
 
 	Method SetTransform( xx:Float, xy:Float, yx:Float, yy:Float ) Override
-
 		ix = xx
 		iy = xy
 		jx = yx
 		jy = yy
-
 	End Method
 
 	Method Cls() Override
@@ -1197,17 +1052,15 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		FlushTest( PRIMITIVE_CLS )
 
 		glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
-
 	End Method
 
-	Method Plot( px:Float, py:Float ) Override
-
+	Method Plot( x:Float, y:Float ) Override
 		FlushTest( PRIMITIVE_DOT )
 
 		Local in:Int = vert_index * 2
 
-		vert_array[in + 0] = px
-		vert_array[in + 1] = py
+		vert_array[in + 0] = x
+		vert_array[in + 1] = y
 
 		in = vert_index * 4
 
@@ -1221,7 +1074,6 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 	End Method
 
 	Method DrawLine( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
-
 		FlushTest( PRIMITIVE_LINE )
 
 		Local in:Int = vert_index * 2
@@ -1245,11 +1097,9 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		col_array[in + 7] = color4f[3] 'alpha
 
 		vert_index :+ 2
-
 	End Method
 
 	Method DrawRect( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
-
 		FlushTest( PRIMITIVE_PLAIN_TRIANGLE )
 
 		Local in:Int = vert_index * 2
@@ -1287,11 +1137,9 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 
 		vert_index :+ 4
 		quad_index :+ 1
-
 	End Method
 
 	Method DrawOval( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
-
 		' TRIANGLE_FAN (no batching)
 		FlushTest( PRIMITIVE_TRIANGLE_FAN )
 
@@ -1338,11 +1186,9 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		Next
 
 		vert_index :+ segs + 2
-
 	End Method
 
 	Method DrawPoly( xy:Float[], handle_x:Float, handle_y:Float, origin_x:Float, origin_y:Float, indices:Int[] ) Override
-
 		If xy.length < 6 Or ( xy.length & 1 ) Then Return
 
 		' TRIANGLE_FAN (no batching)
@@ -1371,7 +1217,6 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 	End Method
 
 	Method DrawPixmap( p:TPixmap, x:Int, y:Int ) Override
-
 		Local blend:Int = state_blend
 		SetBlend( SOLIDBLEND )
 
@@ -1379,14 +1224,12 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		If t.format <> PF_RGBA8888 Then t = ConvertPixmap( t, PF_RGBA8888 )
 
 		Local img:TImage = LoadImage(t)
-		DrawImage img, x, y
+		DrawImage( img, x, y )
 
 		SetBlend( blend )
-
 	End Method
 
 	Method DrawTexture( name:Int, u0:Float, v0:Float, u1:Float, v1:Float, x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float, img:TImageFrame = Null )
-
 		FlushTest( PRIMITIVE_TEXTURED_TRIANGLE, name )
 
 		Local in:Int = vert_index * 2
@@ -1437,31 +1280,32 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		If img Then
 			imgCache.AddLast(img)
 		End If
-
 	End Method
 
 	Method GrabPixmap:TPixmap( x:Int, y:Int, w:Int, h:Int ) Override
-
 		Local blend:Int = state_blend
 		SetBlend( SOLIDBLEND )
 		Local p:TPixmap = CreatePixmap( w, h, PF_RGBA8888 )
+
+		'The default backbuffer in Max2D was opaque so overwrote any
+		'trash data of a freshly created pixmap. Potentially transparent
+		'backbuffers require a complete transparent pixmap to start with.
+		p.ClearPixels(0)
+
 		' flush everything to ensure there's something to read
 		Flush()
-		glReadPixels( x, GraphicsHeight() - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels )
+		If _CurrentRenderImageFrame and _CurrentRenderImageFrame <> _BackbufferRenderImageFrame
+			glReadPixels(x, _CurrentRenderImageFrame.height - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels)
+		Else
+			glReadPixels(x, _BackbufferRenderImageFrame.height - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels)
+		EndIf
 		p = YFlipPixmap( p )
 		SetBlend( blend )
 		Return p
-
 	End Method
 
 	Method SetResolution( width:Float, height:Float ) Override
-
 		u_pmatrix.SetOrthographic( 0, width, 0, height, -1, 1 )
-		'glMatrixMode( GL_PROJECTION )
-		'glLoadIdentity()
-		'glOrtho( 0, width, height, 0, -1, 1 )
-		'glMatrixMode( GL_MODELVIEW )
-
 	End Method
 
 	Method Init()
@@ -1673,6 +1517,46 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 '
 '	End Method
 
+	Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Override
+		Return TGL2SDLRenderImageFrame.Create(width, height, flags)
+	EndMethod
+	
+	Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override		
+		If RenderImageFrame = _CurrentRenderImageFrame
+			Return
+		EndIf
+		
+		Flush()
+		
+		glBindFrameBuffer(GL_FRAMEBUFFER, TGL2SDLRenderImageFrame(RenderImageFrame).FBO)
+		_CurrentRenderImageFrame = TGL2SDLRenderImageFrame(RenderImageFrame)
+		
+		Local vp:Rect = _GLScissor_BMaxViewport
+		SetScissor(vp.x, vp.y, vp.width, vp.height)
+		SetMatrixAndViewportToCurrentRenderImage()
+	EndMethod
+	
+	Method SetBackbuffer()
+		SetRenderImageFrame(_BackBufferRenderImageFrame)
+	EndMethod
+	
+Private
+	Field _glewIsInitialised:Int = False
+
+	Method SetMatrixAndViewportToCurrentRenderImage()
+		u_pmatrix.SetOrthographic( 0, _CurrentRenderImageFrame.width, 0, _CurrentRenderImageFrame.height, -1, 1 )
+		glViewport(0, 0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height)
+	EndMethod
+
+	Method SetScissor(x:Int, y:Int, w:Int, h:Int)
+		Local ri:TImageFrame = _CurrentRenderImageFrame
+		If x = 0  And y = 0 And w = _CurrentRenderImageFrame.width And h = _CurrentRenderImageFrame.height
+			glDisable(GL_SCISSOR_TEST)
+		Else
+			glEnable(GL_SCISSOR_TEST)
+			glScissor(x, _CurrentRenderImageFrame.height - y - h, w, h)
+		EndIf
+	EndMethod
 End Type
 
 Rem
@@ -1681,7 +1565,7 @@ about:
 The returned driver can be used with #SetGraphicsDriver to enable OpenGL Max2D rendering.
 End Rem
 Function GL2Max2DDriver:TGL2Max2DDriver()
-	Print "GL2 (with shaders) Active"
+	'Print "GL2 (with shaders) Active"
 	Global _done:Int
 	If Not _done
 		_driver = New TGL2Max2DDriver.Create()

+ 0 - 63
gl2sdlmax2d.mod/rectnode.bmx

@@ -1,63 +0,0 @@
-
-Strict
-
-Rem
-Simple rect packer
-Based on lightmap packing code by blackpawn
-To remove a rect, set its kind to HOLLOW and optimize the root rect
-End Rem
-
-Type TRectNode
-
-	Const NODE=0,SOLID=1,HOLLOW=-1
-
-	Field x,y,width,height,kind
-	Field child0:TRectNode,child1:TRectNode
-	
-	Method Insert:TRectNode( w,h )
-		Local r:TRectNode
-		If kind=NODE
-			r=child0.Insert( w,h )
-			If r Return r
-			Return child1.Insert( w,h )
-		EndIf
-		If kind=SOLID Return Null
-		If w>width Or h>height Return Null
-		If w=width And h=height
-			kind=SOLID
-			Return Self
-		EndIf
-		kind=NODE
-		Local dw=width-w
-		Local dh=height-h
-		If dw>dh
-			child0=Create( x,y,w,height )
-			child1=Create( x+w,y,dw,height )
-		Else
-			child0=Create( x,y,width,h )
-			child1=Create( x,y+h,width,dh )
-		EndIf
-		Return child0.Insert( w,h )
-	End Method
-	
-	Method Optimize()
-		If kind<>NODE Return
-		child0.Optimize
-		child1.Optimize
-		If child0.kind<>HOLLOW Or child1.kind<>HOLLOW Return
-		kind=HOLLOW
-		child0=Null
-		child1=Null
-	End Method
-	
-	Function Create:TRectNode( x,y,w,h )
-		Local r:TRectNode=New TRectNode
-		r.x=x
-		r.y=y
-		r.width=w
-		r.height=h
-		r.kind=HOLLOW
-		Return r
-	End Function
-	
-End Type

+ 456 - 492
glsdlmax2d.mod/glsdlmax2d.bmx

@@ -8,12 +8,14 @@ The OpenGL Max2D module provides an SDL-backend OpenGL driver for #Max2D.
 End Rem
 Module SDL.GLSDLMax2D
 
-ModuleInfo "Version: 1.15"
+ModuleInfo "Version: 1.16"
 ModuleInfo "Author: Mark Sibly"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
 ModuleInfo "Modserver: BRL"
 
+ModuleInfo "History: 1.16"
+ModuleInfo "History: Added RenderImages / render2texture"
 ModuleInfo "History: 1.15"
 ModuleInfo "History: Changed to SuperStrict"
 ModuleInfo "History: Extended flags to Long"
@@ -42,16 +44,32 @@ ModuleInfo "History: Added checks to prevent invalid textures deletes"
 
 Import BRL.Max2D
 Import SDL.GLSDLGraphics
+Import BRL.Threads
 
 Private
 
+Struct Rect
+	Method New (X:Int, Y:Int, width:Int, height:Int)
+		Self.X = X
+		Self.Y = Y
+		Self.width = width
+		Self.height = height
+	EndMethod
+	
+	Field X:Int, Y:Int
+	Field width:Int, height:Int
+EndStruct
+
 Global _driver:TGLMax2DDriver
+Global _BackbufferRenderImageFrame:TGLSDLRenderImageFrame
+Global _CurrentRenderImageFrame:TGLSDLRenderImageFrame
+Global _GLScissor_BMaxViewport:Rect = New Rect
 
 'Naughty!
-Const GL_BGR:Int=$80E0
-Const GL_BGRA:Int=$80E1
-Const GL_CLAMP_TO_EDGE:Int=$812F
-Const GL_CLAMP_TO_BORDER:Int=$812D
+Const GL_BGR:Int = $80E0
+Const GL_BGRA:Int = $80E1
+Const GL_CLAMP_TO_EDGE:Int = $812F
+Const GL_CLAMP_TO_BORDER:Int = $812D
 
 Global ix:Float,iy:Float,jx:Float,jy:Float
 Global color4ub:Byte[4]
@@ -61,408 +79,218 @@ Global state_boundtex:Int
 Global state_texenabled:Int
 
 Function BindTex( name:Int )
-	If name=state_boundtex Return
-	glBindTexture GL_TEXTURE_2D,name
-	state_boundtex=name
+	If name = state_boundtex Return
+	glBindTexture( GL_TEXTURE_2D, name )
+	state_boundtex = name
 End Function
 
 Function EnableTex( name:Int )
-	BindTex name
+	BindTex( name )
 	If state_texenabled Return
-	glEnable GL_TEXTURE_2D
-	state_texenabled=True
+	glEnable( GL_TEXTURE_2D )
+	state_texenabled = True
 End Function
 
 Function DisableTex()
 	If Not state_texenabled Return
-	glDisable GL_TEXTURE_2D
-	state_texenabled=False
+	glDisable( GL_TEXTURE_2D )
+	state_texenabled = False
 End Function
 
 Function Pow2Size:Int( n:Int )
-	Local t:Int=1
-	While t<n
-		t:*2
+	Local t:Int = 1
+	While t < n
+		t :* 2
 	Wend
 	Return t
 End Function
 
-Global dead_texs:Int[],n_dead_texs:Int,dead_tex_seq:Int,n_live_texs:Int
-
-Extern
-	Function bbAtomicAdd:Int( target:Int Ptr,value:Int )="int bbAtomicAdd( int *,int )!"
-End Extern
+Global dead_texs:TDynamicArray = New TDynamicArray(32)
+Global dead_tex_seq:Int
 
 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
 Function DeleteTex( name:Int,seq:Int )
 	If seq<>dead_tex_seq Return
-	
-	Local n:Int = bbAtomicAdd(Varptr n_dead_texs, 1)
-	bbAtomicAdd(Varptr n_live_texs, -1)
 
-	dead_texs[n] = name
+	dead_texs.AddLast(name)
 End Function
 
-Function _ManageDeadTexArray()
-	If dead_texs.length <= n_live_texs
-		' expand array so it's large enough to hold all the current live textures.
-		dead_texs=dead_texs[..n_live_texs+20]
-	EndIf
-End Function
+Function CreateTex:Int( width:Int,height:Int,flags:Int,pixmap:TPixmap )
+	If pixmap.dds_fmt<>0 Then Return pixmap.tex_name ' if dds texture already exists
 
-Function CreateTex:Int( width:Int,height:Int,flags:Int )
 	'alloc new tex
 	Local name:Int
-	glGenTextures 1,Varptr name
-
-	n_live_texs :+ 1
-	_ManageDeadTexArray()
+	glGenTextures( 1, Varptr name )
 
 	'flush dead texs
 	If dead_tex_seq=GraphicsSeq
-		For Local i:Int=0 Until n_dead_texs
-			glDeleteTextures 1,Varptr dead_texs[i]
-		Next
+		Local n:Int = dead_texs.RemoveLast()
+		While n <> $FFFFFFFF
+			glDeleteTextures(1, Varptr n)
+			n = dead_texs.RemoveLast()
+		Wend
 	EndIf
-	n_dead_texs=0
-	dead_tex_seq=GraphicsSeq
+
+	dead_tex_seq = GraphicsSeq
 
 	'bind new tex
-	BindTex name
-	
+	BindTex( name )
+
 	'set texture parameters
-	glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE
-	glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE
-	
+	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE )
+	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE )
+
 	If flags & FILTEREDIMAGE
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
+		glTexParameteri GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
 		If flags & MIPMAPPEDIMAGE
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR
+			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR )
 		Else
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
+			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )
 		EndIf
 	Else
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
+		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST )
 		If flags & MIPMAPPEDIMAGE
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST
+			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_NEAREST )
 		Else
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
+			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST )
 		EndIf
 	EndIf
 
 	Local mip_level:Int
-
 	Repeat
-		glTexImage2D GL_TEXTURE_2D,mip_level,GL_RGBA8,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
-		If Not (flags & MIPMAPPEDIMAGE) Exit
-		If width=1 And height=1 Exit
-		If width>1 width:/2
-		If height>1 height:/2
-		mip_level:+1
+		glTexImage2D( GL_TEXTURE_2D, mip_level, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null )
+		If Not ( flags & MIPMAPPEDIMAGE ) Exit
+		If width = 1 And height = 1 Exit
+		If width > 1 width :/ 2
+		If height > 1 height :/ 2
+		mip_level :+ 1
 	Forever
 
 	Return name
 End Function
 
-Function UploadTex( pixmap:TPixmap,flags:Int )
+'NOTE: Assumes a bound texture.
+Function UploadTex( pixmap:TPixmap, flags:Int )
 	Local mip_level:Int
+	If pixmap.dds_fmt <> 0 Then Return ' if dds texture already exists
 	Repeat
 		glPixelStorei GL_UNPACK_ROW_LENGTH,pixmap.pitch/BytesPerPixel[pixmap.format]
 		glTexSubImage2D GL_TEXTURE_2D,mip_level,0,0,pixmap.width,pixmap.height,GL_RGBA,GL_UNSIGNED_BYTE,pixmap.pixels
-		If Not (flags & MIPMAPPEDIMAGE) Exit
-		If pixmap.width>1 And pixmap.height>1
-			pixmap=ResizePixmap( pixmap,pixmap.width/2,pixmap.height/2 )
-		Else If pixmap.width>1
-			pixmap=ResizePixmap( pixmap,pixmap.width/2,pixmap.height )
-		Else If pixmap.height>1
-			pixmap=ResizePixmap( pixmap,pixmap.width,pixmap.height/2 )
+
+		If Not ( flags & MIPMAPPEDIMAGE ) Then Exit
+		If pixmap.width > 1 And pixmap.height > 1
+			pixmap = ResizePixmap( pixmap, pixmap.width / 2, pixmap.height / 2 )
+		Else If pixmap.width > 1
+			pixmap = ResizePixmap( pixmap, pixmap.width / 2, pixmap.height )
+		Else If pixmap.height > 1
+			pixmap = ResizePixmap( pixmap, pixmap.width, pixmap.height / 2 )
 		Else
 			Exit
 		EndIf
-		mip_level:+1
+		mip_level :+ 1
 	Forever
 	glPixelStorei GL_UNPACK_ROW_LENGTH,0
 End Function
 
-Function AdjustTexSize( width:Int Var,height:Int Var )
+Function AdjustTexSize( width:Int Var, height:Int Var )
 	'calc texture size
-	width=Pow2Size( width )
-	height=Pow2Size( height )
+	width = Pow2Size( width )
+	height = Pow2Size( height )
 	Repeat
 		Local t:Int
 		glTexImage2D GL_PROXY_TEXTURE_2D,0,4,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
 		glGetTexLevelParameteriv GL_PROXY_TEXTURE_2D,0,GL_TEXTURE_WIDTH,Varptr t
-		If t Return
-		If width=1 And height=1 RuntimeError "Unable to calculate tex size"
-		If width>1 width:/2
-		If height>1 height:/2
+		If t Then Return
+		If width = 1 And height = 1 Then RuntimeError "Unable to calculate tex size"
+		If width > 1 width :/ 2
+		If height > 1 height :/ 2
 	Forever
 End Function
 
+Type TDynamicArray
 
+	Private
 
-Global glewIsInit:Int
-
-Type TGLRenderImageContext Extends TRenderImageContext
-	Field _gc:TSDLGraphics
-	Field _backbuffer:Int
-	Field _width:Int
-	Field _height:Int
-	Field _renderimages:TList
-	
-	Field _matrix:Float[16]
-
-	Method Delete()
-		Destroy()
-	EndMethod
-
-	Method Destroy()
-		_gc = Null
-		If _renderimages
-			For Local ri:TGLRenderImage = EachIn _renderimages
-				ri.DestroyRenderImage()
-			Next
-		EndIf
-	EndMethod
+	Field data:Int Ptr
+	Field size:Size_T
+	Field capacity:Size_T
 
-	Method Create:TGLRenderimageContext(gc:TGraphics, driver:TGraphicsDriver)
-		If Not glewIsInit
-			glewInit()
-			glewIsInit = True
-		EndIf
+	Field guard:TMutex
 
-		_renderimages = New TList
-		_gc = TSDLGraphics(gc)
-		_width = GraphicsWidth()
-		_height = GraphicsHeight()
+	Public
 
-		' get the backbuffer - usually 0
-		glGetIntegerv(GL_FRAMEBUFFER_BINDING, Varptr _backbuffer)
-		glGetFloatv(GL_PROJECTION_MATRIX, _matrix)
-		
-		Return Self
-	EndMethod
-
-	Method GraphicsContext:TGraphics()
-		Return _gc
-	EndMethod
-
-	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseImageFiltering:Int)
-		Local renderimage:TGLRenderImage = New TGLRenderImage.CreateRenderImage(width, height)
-		renderimage.Init(UseImageFiltering, Null)
-		Return  renderimage
-	EndMethod
-	
-	Method CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, UseImageFiltering:Int)
-		Local renderimage:TGLRenderImage = New TGLRenderImage.CreateRenderImage(pixmap.width, pixmap.height)
-		renderimage.Init(UseImageFiltering, pixmap)
-		Return  renderimage
-	EndMethod
-	
-	Method DestroyRenderImage(renderImage:TRenderImage)
-		renderImage.DestroyRenderImage()
-		_renderImages.Remove(renderImage)
-	EndMethod
-
-	Method SetRenderImage(renderimage:TRenderimage)
-		If Not renderimage
-			glBindFramebuffer(GL_FRAMEBUFFER,_backbuffer)
-		
-			glMatrixMode(GL_PROJECTION)
-			glLoadMatrixf(_matrix)
-			
-			glViewport(0,0,_width,_height)
-		Else
-			renderimage.SetRenderImage()
-		EndIf
-	EndMethod
-	
-	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
-		Return TGLRenderImage(renderImage).ToPixmap()
-	EndMethod
-EndType
-
-
-Type TGLRenderImageFrame Extends TGLImageFrame
-	Field _fbo:Int
-	
-	Method Delete()
-		DeleteFramebuffer
-	EndMethod
-	
-	Method DeleteFramebuffer()
-		If _fbo
-			glDeleteFramebuffers(1, Varptr _fbo)
-			_fbo = -1 '???
-		EndIf
-	EndMethod
-	
-	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
-		'backup current
-		Local c:Float[4]
-		glGetFloatv(GL_COLOR_CLEAR_VALUE, c)		
+	Method New(initialCapacity:Int = 8)
+		capacity = initialCapacity
+		data = malloc_(Size_T(initialCapacity * 4))
+		guard = CreateMutex()
+	End Method
 
-		glClearColor(r/255.0, g/255.0, b/255.0, a)
-		glClear(GL_COLOR_BUFFER_BIT)
+	Method AddLast(value:Int)
+		guard.Lock()
+		If size = capacity Then
+			capacity :* 2
+			Local d:Byte Ptr = realloc_(data, capacity * 4)
+			If Not d Then
+				Throw "Failed to allocate more memory"
+			End If
+			data = d
+		End If
 
-		glClearColor(c[0], c[1], c[2], c[3])
+		data[size] = value
+		size :+ 1
+		guard.Unlock()
 	End Method
-	
-	Method CreateRenderTarget:TGLRenderImageFrame(width:Int, height:Int, UseImageFiltering:Int, pixmap:TPixmap)
-		If pixmap pixmap = ConvertPixmap(pixmap, PF_RGBA)
-		
-		glDisable(GL_SCISSOR_TEST)
 
-		glGenTextures(1, Varptr name)
-		glBindTexture(GL_TEXTURE_2D, name)
-		If pixmap
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap.pixels)
-		Else
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
-		EndIf
+	Method RemoveLast:Int()
+		guard.Lock()
+		Local v:Int
 
-		If UseImageFiltering
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
+		If size > 0 Then
+			size :- 1
+			v = data[size]
 		Else
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
-		EndIf
-		
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE
-		
-		glGenFramebuffers(1,Varptr _fbo)
-		glBindFramebuffer GL_FRAMEBUFFER,_fbo
-
-		glBindTexture GL_TEXTURE_2D,name
-		glFramebufferTexture2D GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,name,0
-
-		If Not pixmap
-			' set and clear to a default colour
-			glClearColor 0, 0, 0, 0
-			glClear(GL_COLOR_BUFFER_BIT)
-		EndIf
+			v = $FFFFFFFF
+		End If
 
-		uscale = 1.0 / width
-		vscale = 1.0 / height
+		guard.Unlock()
 
-		Return Self
-	EndMethod
-	
-	Method DestroyRenderTarget()
-		DeleteFramebuffer()
-	EndMethod
-	
-	Method ToPixmap:TPixmap(width:Int, height:Int)
-		Local prevTexture:Int
-		Local prevFBO:Int
-		
-		glGetIntegerv(GL_TEXTURE_BINDING_2D,Varptr prevTexture)
-		glBindTexture(GL_TEXTURE_2D,name)
-
-		Local pixmap:TPixmap = CreatePixmap(width, height, PF_RGBA8888)		
-		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap.pixels)
-		
-		glBindTexture(GL_TEXTURE_2D,prevTexture)
-				
-		Return pixmap
-	EndMethod
-EndType
-
-Type TGLRenderImage Extends TRenderImage
-	Field _matrix:Float[16]
-
-	Method CreateRenderImage:TGLRenderImage(width:Int, height:Int)
-		Self.width = width		' TImage.width
-		Self.height = height	' TImage.height
-
-		_matrix = [	2.0/width, 0.0, 0.0, 0.0,..
-					0.0, 2.0/height, 0.0, 0.0,..
-					0.0, 0.0, 1.0, 0.0,..
-					-1-(1.0/width), -1-(1.0/height), 1.0, 1.0 ]
+		Return v
+	End Method
 
-		Return Self
-	EndMethod
-	
-	Method DestroyRenderImage()
-		TGLRenderImageFrame(frames[0]).DestroyRenderTarget()
-	EndMethod
-	
-	Method Init(UseImageFiltering:Int, pixmap:TPixmap)
-		Local prevFBO:Int
-		Local prevTexture:Int
-		Local prevScissorTest:Int
-
-		glGetIntegerv(GL_FRAMEBUFFER_BINDING, Varptr prevFBO)
-		glGetIntegerv(GL_TEXTURE_BINDING_2D,Varptr prevTexture)
-		glGetIntegerv(GL_SCISSOR_TEST, Varptr prevScissorTest)
-		
-		frames = New TGLRenderImageFrame[1]
-		frames[0] = New TGLRenderImageFrame.CreateRenderTarget(width, height, UseImageFiltering, pixmap)
-		
-		If prevScissorTest glEnable(GL_SCISSOR_TEST)
-		glBindTexture GL_TEXTURE_2D,prevTexture
-		glBindFramebuffer GL_FRAMEBUFFER,prevFBO
-	EndMethod
-	
-	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
-		If frames[0] Then TGLRenderImageFrame(frames[0]).Clear(r, g, b, a)
+	Method Delete()
+		free_(data)
+		CloseMutex(guard)
 	End Method
 
-	Method Frame:TImageFrame(index:Int=0)
-		Return frames[0]
-	EndMethod
-	
-	Method SetRenderImage()
-		glBindFrameBuffer(GL_FRAMEBUFFER, TGLRenderImageFrame(frames[0])._fbo)
+End Type
 
-		glMatrixMode(GL_PROJECTION)
-		glLoadMatrixf(_matrix)
-	
-		glViewport 0,0,width,height 
-	EndMethod
-	
-	Method ToPixmap:TPixmap()
-		Return TGLRenderImageFrame(frames[0]).ToPixmap(width, height)
-	EndMethod
-	
-	Method SetViewport(x:Int, y:Int, width:Int, height:Int)
-		If x = 0 And y = 0 And width = Self.width And height = Self.height
-			glDisable GL_SCISSOR_TEST
-		Else
-			glEnable GL_SCISSOR_TEST
-			glScissor x, y, width, height
-		EndIf
-	EndMethod
-EndType
+Global glewIsInit:Int
 
 Public
 
-Type TGLImageFrame Extends TImageFrame
 
-	Field u0:Float,v0:Float,u1:Float,v1:Float,uscale:Float,vscale:Float
+Type TGLImageFrame Extends TImageFrame
+	Field u0:Float, v0:Float, u1:Float, v1:Float, uscale:Float, vscale:Float
+	Field name:Int, seq:Int
 
-	Field name:Int,seq:Int
-	
 	Method New()
-		seq=GraphicsSeq
+		seq = GraphicsSeq
 	End Method
-	
+
 	Method Delete()
-		If Not seq Return
-		DeleteTex name,seq
-		seq=0
+		If Not seq Then Return
+		DeleteTex( name, seq )
+		seq = 0
 	End Method
 	
 	Method Draw( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float,sx:Float,sy:Float,sw:Float,sh:Float ) Override
 		Assert seq=GraphicsSeq Else "Image does not exist"
 
-		Local u0:Float=sx * uscale
-		Local v0:Float=sy * vscale
-		Local u1:Float=(sx+sw) * uscale
-		Local v1:Float=(sy+sh) * vscale
-		
+		Local u0:Float = sx * uscale
+		Local v0:Float = sy * vscale
+		Local u1:Float = (sx + sw) * uscale
+		Local v1:Float = (sy + sh) * vscale
+
 		EnableTex name
 		glBegin GL_QUADS
 		glTexCoord2f u0,v0
@@ -476,61 +304,149 @@ Type TGLImageFrame Extends TImageFrame
 		glEnd
 	End Method
 	
-	Function CreateFromPixmap:TGLImageFrame( src:TPixmap,flags:Int )
+	Function CreateFromPixmap:TGLImageFrame( src:TPixmap, flags:Int )
 		'determine tex size
-		Local tex_w:Int=src.width
-		Local tex_h:Int=src.height
-		AdjustTexSize tex_w,tex_h
+		Local tex_w:Int = src.width
+		Local tex_h:Int = src.height
+		AdjustTexSize( tex_w, tex_h )
 		
 		'make sure pixmap fits texture
-		Local width:Int=Min( src.width,tex_w )
-		Local height:Int=Min( src.height,tex_h )
-		If src.width<>width Or src.height<>height src=ResizePixmap( src,width,height )
+		Local width:Int = Min( src.width, tex_w )
+		Local height:Int = Min( src.height, tex_h )
+		If src.width <> width Or src.height <> height Then src = ResizePixmap( src, width, height )
 
 		'create texture pixmap
-		Local tex:TPixmap=src
+		Local tex:TPixmap = src
 		
 		'"smear" right/bottom edges if necessary
-		If width<tex_w Or height<tex_h
-			tex=TPixmap.Create( tex_w,tex_h,PF_RGBA8888 )
-			tex.Paste src,0,0
-			If width<tex_w
-				tex.Paste src.Window( width-1,0,1,height ),width,0
+		If width < tex_w Or height < tex_h
+			tex = TPixmap.Create( tex_w, tex_h, PF_RGBA8888 )
+			tex.Paste( src, 0, 0 )
+			If width < tex_w
+				tex.Paste( src.Window( width - 1, 0, 1, height ), width, 0 )
 			EndIf
-			If height<tex_h
-				tex.Paste src.Window( 0,height-1,width,1 ),0,height
-				If width<tex_w 
-					tex.Paste src.Window( width-1,height-1,1,1 ),width,height
+			If height < tex_h
+				tex.Paste( src.Window( 0, height - 1, width, 1 ), 0, height )
+				If width < tex_w 
+					tex.Paste( src.Window( width - 1, height - 1, 1, 1 ), width, height )
 				EndIf
 			EndIf
 		Else
-			If tex.format<>PF_RGBA8888 tex=tex.Convert( PF_RGBA8888 )
+			If tex.dds_fmt = 0 ' not dds
+				If tex.format <> PF_RGBA8888 Then tex = tex.Convert( PF_RGBA8888 )
+			EndIf
 		EndIf
 		
 		'create tex
-		Local name:Int=CreateTex( tex_w,tex_h,flags )
+		Local name:Int = CreateTex( tex_w, tex_h, flags, tex )
 		
 		'upload it
-		UploadTex tex,flags
+		UploadTex( tex, flags )
 
 		'done!
-		Local frame:TGLImageFrame=New TGLImageFrame
-		frame.name=name
-		frame.uscale=1.0/tex_w
-		frame.vscale=1.0/tex_h
-		frame.u1=width * frame.uscale
-		frame.v1=height * frame.vscale
+		Local frame:TGLImageFrame = New TGLImageFrame
+		frame.name = name
+		frame.uscale = 1.0 / tex_w
+		frame.vscale = 1.0 / tex_h
+		frame.u1 = width * frame.uscale
+		frame.v1 = height * frame.vscale
 		Return frame
 
 	End Function
 
 End Type
 
-Type TGLMax2DDriver Extends TMax2DDriver
+Type TGLSDLRenderImageFrame Extends TGLImageFrame
+	Field FBO:Int
+	Field width:Int
+	Field height:Int
+	
+	Method Draw( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float, sx:Float, sy:Float, sw:Float, sh:Float ) Override
+		Assert seq=GraphicsSeq Else "Image does not exist"
 
-	Method Create:TGLMax2DDriver()
-		If Not SDLGraphicsDriver() Return Null
+		' Note for a TGLRenderImage the V texture coordinate is flipped compared to the regular TImageFrame.Draw method
+		Local u0:Float = sx * uscale
+		Local v0:Float = (sy + sh) * vscale
+		Local u1:Float = (sx + sw) * uscale
+		Local v1:Float = sy * vscale
 		
+		EnableTex name
+		glBegin GL_QUADS
+		glTexCoord2f u0,v0
+		glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
+		glTexCoord2f u1,v0
+		glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
+		glTexCoord2f u1,v1
+		glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
+		glTexCoord2f u0,v1
+		glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
+		glEnd
+	End Method
+	
+	Function Create:TGLSDLRenderImageFrame(width:UInt, height:UInt, flags:Int)
+		' Need this to enable frame buffer objects - glGenFramebuffers
+		Global GlewIsInitialised:Int = False
+		If Not GlewIsInitialised
+			GlewInit()
+			GlewIsInitialised = True
+		EndIf
+		
+		' store so that we can restore once the fbo is created
+		Local ScissorTestEnabled:Int = GlIsEnabled(GL_SCISSOR_TEST)
+		glDisable(GL_SCISSOR_TEST)
+		
+		Local TextureName:Int
+		glGenTextures(1, Varptr TextureName)
+		glBindTexture(GL_TEXTURE_2D, TextureName)
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
+		
+		If flags & FILTEREDIMAGE
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
+		Else
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
+		EndIf
+		
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
+		
+		Local FrameBufferObject:Int
+		glGenFramebuffers(1, Varptr FrameBufferObject)
+		glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferObject)
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureName, 0)
+		
+		Local RenderTarget:TGLSDLRenderImageFrame = New TGLSDLRenderImageFrame
+		RenderTarget.name = TextureName
+		RenderTarget.FBO = FrameBufferObject
+		
+		RenderTarget.width = width
+		RenderTarget.height = height
+		RenderTarget.uscale = 1.0 / width
+		RenderTarget.vscale = 1.0 / height
+		RenderTarget.u1 = width * RenderTarget.uscale
+		RenderTarget.v1 = height * RenderTarget.vscale
+		
+		If ScissorTestEnabled
+			glEnable(GL_SCISSOR_TEST)
+		EndIf
+		
+		Return RenderTarget
+	End Function
+	
+Private
+	Method Delete()
+		glDeleteFramebuffers(1, Varptr FBO) ' gl ignores 0
+	End Method
+
+	Method New()
+	End Method
+EndType
+
+Type TGLMax2DDriver Extends TMax2DDriver
+	Method Create:TGLMax2DDriver()
+		If Not SDLGraphicsDriver() Then Return Null
+	
 		Return Self
 	End Method
 
@@ -538,251 +454,299 @@ Type TGLMax2DDriver Extends TMax2DDriver
 	Method GraphicsModes:TGraphicsMode[]() Override
 		Return SDLGraphicsDriver().GraphicsModes()
 	End Method
-	
+
 	Method AttachGraphics:TMax2DGraphics( widget:Byte Ptr,flags:Long ) Override
-		Local g:TSDLGraphics=SDLGraphicsDriver().AttachGraphics( widget,flags )
+		Local g:TSDLGraphics = SDLGraphicsDriver().AttachGraphics( widget,flags )
 		If g Return TMax2DGraphics.Create( g,Self )
 	End Method
 	
 	Method CreateGraphics:TMax2DGraphics( width:Int,height:Int,depth:Int,hertz:Int,flags:Long,x:Int,y:Int ) Override
-		Local g:TSDLGraphics=SDLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags | SDL_GRAPHICS_GL,x,y )
+		Local g:TSDLGraphics = SDLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags | SDL_GRAPHICS_GL,x,y )
 		If g Return TMax2DGraphics.Create( g,Self )
 	End Method
 	
 	Method SetGraphics( g:TGraphics ) Override
 		If Not g
-			TMax2DGraphics.ClearCurrent
+			TMax2DGraphics.ClearCurrent()
 			SDLGraphicsDriver().SetGraphics Null
 			Return
 		EndIf
-	
-		Local t:TMax2DGraphics=TMax2DGraphics(g)
-		Assert t And TSDLGraphics( t._graphics )
 
-		SDLGraphicsDriver().SetGraphics t._graphics
+		Local t:TMax2DGraphics = TMax2DGraphics( g )
+		Assert t And TSDLGraphics( t._backendGraphics )
+
+		SDLGraphicsDriver().SetGraphics(t._backendGraphics)
 
-		ResetGLContext t
+		ResetGLContext(t)
 		
-		t.MakeCurrent
+		t.MakeCurrent()
 	End Method
 	
 	Method ResetGLContext( g:TGraphics )
-		Local gw:Int,gh:Int,gd:Int,gr:Int,gf:Long,gx:Int,gy:Int
-		g.GetSettings gw,gh,gd,gr,gf,gx,gy
+		Local gw:Int, gh:Int, gd:Int, gr:Int, gf:Long, gx:Int, gy:Int
+		g.GetSettings( gw, gh, gd, gr, gf, gx, gy )
 		
-		state_blend=0
-		state_boundtex=0
-		state_texenabled=0
-		glDisable GL_TEXTURE_2D
+		state_blend = 0
+		state_boundtex = 0
+		state_texenabled = 0
+		glDisable( GL_TEXTURE_2D )
+
 		glMatrixMode GL_PROJECTION
 		glLoadIdentity
 		glOrtho 0,gw,gh,0,-1,1
 		glMatrixMode GL_MODELVIEW
 		glLoadIdentity
 		glViewport 0,0,gw,gh
+		
+		' Create default back buffer render image - the FBO will be value 0 which is the default for the existing backbuffer
+		Local BackBufferRenderImageFrame:TGLSDLRenderImageFrame = New TGLSDLRenderImageFrame
+		BackBufferRenderImageFrame.width = gw
+		BackBufferRenderImageFrame.height = gh
+	
+		' cache it
+		_BackBufferRenderImageFrame = BackBufferRenderImageFrame
+		_CurrentRenderImageFrame = _BackBufferRenderImageFrame
 	End Method
 	
 	Method Flip:Int( sync:Int ) Override
-		SDLGraphicsDriver().Flip sync
+		SDLGraphicsDriver().Flip(sync)
 	End Method
 	
 	Method ToString:String() Override
 		Return "OpenGL"
 	End Method
 
-	
-	Method CreateRenderImageContext:Object(g:TGraphics) Override
-		Return new TGLRenderImageContext.Create(g, self)
+	Method ApiIdentifier:String() Override
+		Return "SDL.OpenGL (GLSDL)"
 	End Method
 
-	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap,flags:Int ) Override
-		Local frame:TGLImageFrame
-		frame=TGLImageFrame.CreateFromPixmap( pixmap,flags )
-		Return frame
+	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap, flags:Int ) Override
+		Return TGLImageFrame.CreateFromPixmap( pixmap, flags )
 	End Method
 
 	Method SetBlend( blend:Int ) Override
-		If blend=state_blend Return
-		state_blend=blend
+		If state_blend = blend Return
+
+		state_blend = blend
+
 		Select blend
 		Case MASKBLEND
-			glDisable GL_BLEND
-			glEnable GL_ALPHA_TEST
-			glAlphaFunc GL_GEQUAL,.5
+			glDisable( GL_BLEND )
+			glEnable( GL_ALPHA_TEST )
+			glAlphaFunc( GL_GEQUAL, 0.5 )
 		Case SOLIDBLEND
-			glDisable GL_BLEND
-			glDisable GL_ALPHA_TEST
+			glDisable( GL_BLEND )
+			glDisable( GL_ALPHA_TEST )
 		Case ALPHABLEND
-			glEnable GL_BLEND
-			glBlendFunc GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA
-			glDisable GL_ALPHA_TEST
+			glEnable( GL_BLEND )
+			glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA )
+			glDisable( GL_ALPHA_TEST )
 		Case LIGHTBLEND
-			glEnable GL_BLEND
-			glBlendFunc GL_SRC_ALPHA,GL_ONE
-			glDisable GL_ALPHA_TEST
+			glEnable( GL_BLEND )
+			glBlendFunc( GL_SRC_ALPHA, GL_ONE )
+			glDisable( GL_ALPHA_TEST )
 		Case SHADEBLEND
-			glEnable GL_BLEND
-			glBlendFunc GL_DST_COLOR,GL_ZERO
-			glDisable GL_ALPHA_TEST
+			glEnable( GL_BLEND )
+			glBlendFunc( GL_DST_COLOR, GL_ZERO )
+			glDisable( GL_ALPHA_TEST )
 		Default
-			glDisable GL_BLEND
-			glDisable GL_ALPHA_TEST
+			glDisable( GL_BLEND )
+			glDisable( GL_ALPHA_TEST )
 		End Select
 	End Method
 
 	Method SetAlpha( alpha:Float ) Override
-		If alpha>1.0 alpha=1.0
-		If alpha<0.0 alpha=0.0
-		color4ub[3]=alpha*255
-		glColor4ubv color4ub
+		If alpha > 1.0 Then alpha = 1.0
+		If alpha < 0.0 Then alpha = 0.0
+		color4ub[3] = alpha * 255
+		glColor4ubv( color4ub )
 	End Method
 
 	Method SetLineWidth( width:Float ) Override
-		glLineWidth width
+		glLineWidth( width )
 	End Method
 	
 	Method SetColor( red:Int,green:Int,blue:Int ) Override
-		color4ub[0]=Min(Max(red,0),255)
-		color4ub[1]=Min(Max(green,0),255)
-		color4ub[2]=Min(Max(blue,0),255)
-		glColor4ubv color4ub
-	End Method
-
-	Method SetColor( color:SColor8 ) Override
-		color4ub[0]=color.r
-		color4ub[1]=color.g
-		color4ub[2]=color.b
-		glColor4ubv color4ub
+		color4ub[0] = Min( Max( red, 0 ), 255 )
+		color4ub[1] = Min( Max( green, 0 ), 255 )
+		color4ub[2] = Min( Max( blue, 0 ), 255 )
+		glColor4ubv( color4ub )
 	End Method
 
-	Method SetClsColor( red:Int,green:Int,blue:Int ) Override
-		red=Min(Max(red,0),255)
-		green=Min(Max(green,0),255)
-		blue=Min(Max(blue,0),255)
-		glClearColor red/255.0,green/255.0,blue/255.0,1.0
-	End Method
+	Method SetClsColor( red:Int, green:Int, blue:Int, alpha:Float ) Override
+		red = Min(Max(red,0),255)
+		green = Min(Max(green,0),255)
+		blue = Min(Max(blue,0),255)
 
-	Method SetClsColor( color:SCOlor8 ) Override
-		glClearColor color.r/255.0,color.g/255.0,color.b/255.0,1.0
+		glClearColor(red/255.0, green/255.0, blue/255.0, alpha)
 	End Method
 	
-	Method SetViewport( x:Int,y:Int,w:Int,h:Int ) Override
-		If x=0 And y=0 And w=GraphicsWidth() And h=GraphicsHeight()
-			glDisable GL_SCISSOR_TEST
-		Else
-			glEnable GL_SCISSOR_TEST
-			glScissor x,GraphicsHeight()-y-h,w,h
-		EndIf
+	Method SetViewport( x:Int, y:Int, w:Int, h:Int ) Override
+		_GLScissor_BMaxViewport.x = x
+		_GLScissor_BMaxViewport.y = y
+		_GLScissor_BMaxViewport.width = w
+		_GLScissor_BMaxViewport.height = h
+		SetScissor(x, y, w, h)
 	End Method
 
 	Method SetTransform( xx:Float,xy:Float,yx:Float,yy:Float ) Override
-		ix=xx
-		iy=xy
-		jx=yx
-		jy=yy
+		ix = xx
+		iy = xy
+		jx = yx
+		jy = yy
 	End Method
 
 	Method Cls() Override
-		glClear GL_COLOR_BUFFER_BIT
+		glClear( GL_COLOR_BUFFER_BIT )
 	End Method
 
-	Method Plot( x:Float,y:Float ) Override
-		DisableTex
-		glBegin GL_POINTS
-		glVertex2f x+.5,y+.5
-		glEnd
+	Method Plot( x:Float, y:Float ) Override
+		DisableTex()
+		glBegin( GL_POINTS )
+		glVertex2f( x+.5,y+.5 )
+		glEnd()
 	End Method
 
-	Method DrawLine( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float ) Override
-		DisableTex
-		glBegin GL_LINES
-		glVertex2f x0*ix+y0*iy+tx+.5,x0*jx+y0*jy+ty+.5
-		glVertex2f x1*ix+y1*iy+tx+.5,x1*jx+y1*jy+ty+.5
-		glEnd
+	Method DrawLine( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
+		DisableTex()
+		glBegin( GL_LINES )
+		glVertex2f( x0 * ix + y0 * iy + tx + .5, x0 * jx + y0 * jy + ty + .5 )
+		glVertex2f( x1 * ix + y1 * iy + tx + .5, x1 * jx + y1 * jy + ty + .5 )
+		glEnd()
 	End Method
 
-	Method DrawRect( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float ) Override
-		DisableTex
-		glBegin GL_QUADS
-		glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
-		glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
-		glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
-		glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
-		glEnd
+	Method DrawRect( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float ) Override
+		DisableTex()
+		glBegin( GL_QUADS )
+		glVertex2f( x0 * ix + y0 * iy + tx, x0 * jx + y0 * jy + ty )
+		glVertex2f( x1 * ix + y0 * iy + tx, x1 * jx + y0 * jy + ty )
+		glVertex2f( x1 * ix + y1 * iy + tx, x1 * jx + y1 * jy + ty )
+		glVertex2f( x0 * ix + y1 * iy + tx, x0 * jx + y1 * jy + ty )
+		glEnd()
 	End Method
 	
 	Method DrawOval( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float ) Override
-	
-		Local xr:Float=(x1-x0)*.5
-		Local yr:Float=(y1-y0)*.5
-		Local segs:Int=Abs(xr)+Abs(yr)
-		
-		segs=Max(segs,12)&~3
-
-		x0:+xr
-		y0:+yr
-		
-		DisableTex
-		glBegin GL_POLYGON
-		For Local i:Int=0 Until segs
-			Local th:Float=i*360:Float/segs
-			Local x:Float=x0+Cos(th)*xr
-			Local y:Float=y0-Sin(th)*yr
-			glVertex2f x*ix+y*iy+tx,x*jx+y*jy+ty
+		Local xr:Float = ( x1 - x0 ) * 0.5
+		Local yr:Float = ( y1 - y0 ) * 0.5
+		Local segs:Int = Abs( xr ) + Abs( yr )
+
+		segs = Max( segs, 12 ) &~ 3
+
+		x0 :+ xr
+		y0 :+ yr
+
+		DisableTex()
+		glBegin( GL_POLYGON )
+		For Local i:Int = 0 Until segs
+			Local th:Float = i * 360.0 / segs
+			Local x:Float = x0 +Cos(th) * xr
+			Local y:Float = y0 -Sin(th) * yr
+			glVertex2f( x * ix + y * iy + tx, x * jx + y * jy + ty )
 		Next
-		glEnd
-		
+		glEnd()
 	End Method
 	
-	Method DrawPoly( xy:Float[],handle_x:Float,handle_y:Float,origin_x:Float,origin_y:Float, indices:Int[] ) Override
-		If xy.length<6 Or (xy.length&1) Return
-		
-		DisableTex
-		glBegin GL_POLYGON
-		For Local i:Int=0 Until Len xy Step 2
-			Local x:Float=xy[i+0]+handle_x
-			Local y:Float=xy[i+1]+handle_y
-			glVertex2f x*ix+y*iy+origin_x,x*jx+y*jy+origin_y
+	Method DrawPoly( xy:Float[], handle_x:Float, handle_y:Float, origin_x:Float, origin_y:Float, indices:Int[] ) Override
+		If xy.length < 6 Or ( xy.length & 1 ) Then Return
+
+		DisableTex()
+		glBegin( GL_POLYGON )
+		For Local i:Int = 0 Until xy.length Step 2
+			Local x:Float = xy[i + 0] + handle_x
+			Local y:Float = xy[i + 1] + handle_y
+			glVertex2f( x * ix + y * iy + origin_x, x * jx + y * jy + origin_y )
 		Next
-		glEnd
+		glEnd()
 	End Method
-		
-	Method DrawPixmap( p:TPixmap,x:Int,y:Int ) Override
-		Local blend:Int=state_blend
-		DisableTex
-		SetBlend SOLIDBLEND
+
+	Method DrawPixmap( p:TPixmap, x:Int, y:Int ) Override
+		Local blend:Int = state_blend
+		DisableTex()
+		SetBlend( SOLIDBLEND )
 	
-		Local t:TPixmap=p
-		If t.format<>PF_RGBA8888 t=ConvertPixmap( t,PF_RGBA8888 )
-
-		glPixelZoom 1,-1
-		glRasterPos2i 0,0
-		glBitmap 0,0,0,0,x,-y,Null
-		glPixelStorei GL_UNPACK_ROW_LENGTH, t.pitch Shr 2
-		glDrawPixels t.width,t.height,GL_RGBA,GL_UNSIGNED_BYTE,t.pixels
-		glPixelStorei GL_UNPACK_ROW_LENGTH,0
-		glPixelZoom 1,1
+		Local t:TPixmap = p
+		If t.format <> PF_RGBA8888 Then t = ConvertPixmap( t, PF_RGBA8888 )
+
+		glPixelZoom( 1, -1 )
+		glRasterPos2i( 0, 0 )
+		glBitmap( 0, 0, 0, 0, x, -y, Null)
+		glPixelStorei( GL_UNPACK_ROW_LENGTH, t.pitch Shr 2 )
+		glDrawPixels( t.width, t.height, GL_RGBA, GL_UNSIGNED_BYTE, t.pixels )
+		glPixelStorei( GL_UNPACK_ROW_LENGTH, 0 )
+		glPixelZoom( 1, 1 )
 		
-		SetBlend blend
+		SetBlend( blend )
 	End Method
 
-	Method GrabPixmap:TPixmap( x:Int,y:Int,w:Int,h:Int ) Override
-		Local blend:Int=state_blend
-		SetBlend SOLIDBLEND
-		Local p:TPixmap=CreatePixmap( w,h,PF_RGBA8888 )
-		glReadPixels x,GraphicsHeight()-h-y,w,h,GL_RGBA,GL_UNSIGNED_BYTE,p.pixels
-		p=YFlipPixmap( p )
-		SetBlend blend
+	Method GrabPixmap:TPixmap( x:Int, y:Int, w:Int, h:Int ) Override
+		Local blend:Int = state_blend
+		SetBlend( SOLIDBLEND )
+		Local p:TPixmap=CreatePixmap( w, h, PF_RGBA8888 )
+
+		'The default backbuffer in Max2D was opaque so overwrote any
+		'trash data of a freshly created pixmap. Potentially transparent
+		'backbuffers require a complete transparent pixmap to start with.
+		p.ClearPixels(0)
+		
+		If _CurrentRenderImageFrame and _CurrentRenderImageFrame <> _BackbufferRenderImageFrame
+			glReadPixels(x, _CurrentRenderImageFrame.height - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels)
+		Else
+			glReadPixels(x, _BackbufferRenderImageFrame.height - h - y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, p.pixels)
+		EndIf
+		p = YFlipPixmap( p )
+		SetBlend( blend )
 		Return p
 	End Method
 	
-	Method SetResolution( width:Float,height:Float ) Override
-		glMatrixMode GL_PROJECTION
-		glLoadIdentity
-		glOrtho 0,width,height,0,-1,1
-		glMatrixMode GL_MODELVIEW
+	Method SetResolution( width:Float, height:Float ) Override
+		glMatrixMode( GL_PROJECTION )
+		glLoadIdentity()
+		glOrtho( 0, width, height, 0, -1, 1 )
+		glMatrixMode( GL_MODELVIEW )
 	End Method
+
+	Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Override
+		Return TGLSDLRenderImageFrame.Create(width, height, flags)
+	EndMethod
+	
+	Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override
+		If RenderImageFrame = _CurrentRenderImageFrame
+			Return
+		EndIf
+		
+		glBindFrameBuffer(GL_FRAMEBUFFER, TGLSDLRenderImageFrame(RenderImageFrame).FBO)
+		_CurrentRenderImageFrame = TGLSDLRenderImageFrame(RenderImageFrame)
+		
+		Local vp:Rect = _GLScissor_BMaxViewport
+		SetScissor(vp.x, vp.y, vp.width, vp.height)
+		SetMatrixAndViewportToCurrentRenderImage()
+	EndMethod
 	
+	Method SetBackbuffer()
+		SetRenderImageFrame(_BackBufferRenderImageFrame)
+	EndMethod
+	
+Private
+	Field _glewIsInitialised:Int = False
+
+	Method SetMatrixAndViewportToCurrentRenderImage()
+		glMatrixMode(GL_PROJECTION)
+		glLoadIdentity()
+		glOrtho(0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height, 0, -1, 1)
+		glMatrixMode(GL_MODELVIEW)
+		glLoadIdentity()
+		glViewport(0, 0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height)
+	EndMethod
+
+	Method SetScissor(x:Int, y:Int, w:Int, h:Int)
+		Local ri:TImageFrame = _CurrentRenderImageFrame
+		If x = 0 And y = 0 And w = _CurrentRenderImageFrame.width And h = _CurrentRenderImageFrame.height
+			glDisable(GL_SCISSOR_TEST)
+		Else
+			glEnable(GL_SCISSOR_TEST)
+			glScissor(x, _CurrentRenderImageFrame.height - y - h, w, h)
+		EndIf
+	EndMethod
 End Type
 
 Rem

+ 0 - 63
glsdlmax2d.mod/rectnode.bmx

@@ -1,63 +0,0 @@
-
-Strict
-
-Rem
-Simple rect packer
-Based on lightmap packing code by blackpawn
-To remove a rect, set its kind to HOLLOW and optimize the root rect
-End Rem
-
-Type TRectNode
-
-	Const NODE=0,SOLID=1,HOLLOW=-1
-
-	Field x,y,width,height,kind
-	Field child0:TRectNode,child1:TRectNode
-	
-	Method Insert:TRectNode( w,h )
-		Local r:TRectNode
-		If kind=NODE
-			r=child0.Insert( w,h )
-			If r Return r
-			Return child1.Insert( w,h )
-		EndIf
-		If kind=SOLID Return Null
-		If w>width Or h>height Return Null
-		If w=width And h=height
-			kind=SOLID
-			Return Self
-		EndIf
-		kind=NODE
-		Local dw=width-w
-		Local dh=height-h
-		If dw>dh
-			child0=Create( x,y,w,height )
-			child1=Create( x+w,y,dw,height )
-		Else
-			child0=Create( x,y,width,h )
-			child1=Create( x,y+h,width,dh )
-		EndIf
-		Return child0.Insert( w,h )
-	End Method
-	
-	Method Optimize()
-		If kind<>NODE Return
-		child0.Optimize
-		child1.Optimize
-		If child0.kind<>HOLLOW Or child1.kind<>HOLLOW Return
-		kind=HOLLOW
-		child0=Null
-		child1=Null
-	End Method
-	
-	Function Create:TRectNode( x,y,w,h )
-		Local r:TRectNode=New TRectNode
-		r.x=x
-		r.y=y
-		r.width=w
-		r.height=h
-		r.kind=HOLLOW
-		Return r
-	End Function
-	
-End Type

+ 102 - 27
sdlrendermax2d.mod/sdlrendermax2d.bmx

@@ -43,6 +43,10 @@ Private
 
 Global _driver:TSDLRenderMax2DDriver
 Global _preferredRenderer:Int = -1
+Global _BackbufferRenderImageFrame:TSDLRenderImageFrame
+Global _CurrentRenderImageFrame:TSDLRenderImageFrame
+Global _ClipRect_BMaxViewport:Rect = New Rect
+
 
 Function Pow2Size:Int( n:Int )
 	Local t:Int = 1
@@ -62,7 +66,10 @@ Public
 
 Type TSDLRenderImageFrame Extends TImageFrame
 
+
 	Field u0:Float, v0:Float, u1:Float, v1:Float, uscale:Float, vscale:Float
+	Field width:Int
+	Field height:Int
 
 	Field pixmap:TPixmap
 	Field surface:TSDLSurface
@@ -100,23 +107,23 @@ Type TSDLRenderImageFrame Extends TImageFrame
 		Local tex_w:Int = src.width
 		Local tex_h:Int = src.height
 		
-		Local width:Int = Min( src.width, tex_w )
-		Local height:Int = Min( src.height, tex_h )
-		
 		If src.format <> PF_RGBA8888 And src.format <> PF_RGB888 Then
 			src = src.Convert( PF_RGBA8888 )
 		End If
 
 		'done!
 		Local frame:TSDLRenderImageFrame=New TSDLRenderImageFrame
+		frame.width = Min( src.width, tex_w )
+		frame.height = Min( src.height, tex_h )
+
 		frame.renderer = _driver.renderer
 		frame.pixmap = src
 		frame.surface = TSDLSurface.CreateRGBFrom(src.pixels, src.width, src.height, BitsPerPixel[src.format], src.pitch, $000000ff:UInt, $0000ff00:UInt, $00ff0000:UInt, $ff000000:UInt)
 		frame.texture = frame.renderer.CreateTextureFromSurface(frame.surface)
 		frame.uscale = 1.0 / tex_w
 		frame.vscale = 1.0 / tex_h
-		frame.u1 = width * frame.uscale
-		frame.v1 = height * frame.vscale
+		frame.u1 = frame.width * frame.uscale
+		frame.v1 = frame.height * frame.vscale
 		Return frame
 	End Function
 
@@ -160,11 +167,11 @@ Type TSDLRenderMax2DDriver Extends TMax2DDriver
 		EndIf
 	
 		Local t:TMax2DGraphics=TMax2DGraphics(g)
-		Assert t And TSDLGraphics( t._graphics )
+		Assert t And TSDLGraphics( t._backendGraphics )
 
-		Local gfx:TSDLGraphics = TSDLGraphics( t._graphics )
+		Local gfx:TSDLGraphics = TSDLGraphics( t._backendGraphics )
 
-		SDLGraphicsDriver().SetGraphics gfx
+		SDLGraphicsDriver().SetGraphics( gfx )
 
 		Local flags:UInt
 		If gfx._context.flags & GRAPHICS_SWAPINTERVAL1 Then
@@ -172,6 +179,15 @@ Type TSDLRenderMax2DDriver Extends TMax2DDriver
 		End If
 
 		renderer = TSDLRenderer.Create(gfx._context.window, _preferredRenderer, flags)
+
+		' Create default back buffer render image
+		Local BackBufferRenderImageFrame:TSDLRenderImageFrame = New TSDLRenderImageFrame
+		BackBufferRenderImageFrame.width = GraphicsWidth()
+		BackBufferRenderImageFrame.height = GraphicsHeight()
+	
+		' cache it
+		_BackBufferRenderImageFrame = BackBufferRenderImageFrame
+		_CurrentRenderImageFrame = _BackBufferRenderImageFrame
 		
 		t.MakeCurrent
 	End Method
@@ -184,10 +200,16 @@ Type TSDLRenderMax2DDriver Extends TMax2DDriver
 		Return "SDLRenderer"
 	End Method
 
+	Method ApiIdentifier:String() Override
+		If renderer
+			Return "SDL." + renderer.GetInfo().GetName() + " (SDLRender)"
+		Else
+			Return "SDL.undefined (SDLRender)"
+		EndIf
+	End Method
+
 	Method CreateFrameFromPixmap:TSDLRenderImageFrame( pixmap:TPixmap,flags:Int ) Override
-		Local frame:TSDLRenderImageFrame
-		frame=TSDLRenderImageFrame.CreateFromPixmap( pixmap,flags )
-		Return frame
+		Return TSDLRenderImageFrame.CreateFromPixmap( pixmap,flags )
 	End Method
 
 	Method SetBlend( blend:Int ) Override
@@ -227,33 +249,23 @@ Type TSDLRenderMax2DDriver Extends TMax2DDriver
 		renderer.SetDrawColor(drawColor.r, drawColor.g, drawColor.b, drawColor.a)
 	End Method
 
-	Method SetColor( color:SColor8 ) Override
-		drawColor.r=color.r
-		drawColor.g=color.g
-		drawColor.b=color.b
-		renderer.SetDrawColor(drawColor.r, drawColor.g, drawColor.b, drawColor.a)
-	End Method
-
-	Method SetClsColor( red:Int,green:Int,blue:Int ) Override
+	Method SetClsColor( red:Int,green:Int,blue:Int, alpha:Float) Override
 		clsColor.r = Min(Max(red,0),255)
 		clsColor.g = Min(Max(green,0),255)
 		clsColor.b = Min(Max(blue,0),255)
-		clsColor.a = 255
+		clsColor.a = alpha
 	End Method
 
-	Method SetClsColor( color:SColor8 ) Override
-		clsColor.r=color.r
-		clsColor.g=color.g
-		clsColor.b=color.b
-		clsColor.a = 255
-	End Method
-	
 	Method SetViewport( x:Int,y:Int,w:Int,h:Int ) Override
 		If x=0 And y=0 And w=GraphicsWidth() And h=GraphicsHeight()
 			renderer.SetClipRect()
 		Else
 			renderer.SetClipRect(x, y, w, h)
 		EndIf
+		_ClipRect_BMaxViewport.x = x
+		_ClipRect_BMaxViewport.y = y
+		_ClipRect_BMaxViewport.width = w
+		_ClipRect_BMaxViewport.height = h
 	End Method
 
 	Method SetTransform( xx:Float,xy:Float,yx:Float,yy:Float ) Override
@@ -479,7 +491,53 @@ Type TSDLRenderMax2DDriver Extends TMax2DDriver
 	Method SetResolution( width:Float,height:Float ) Override
 		renderer.SetLogicalSize(Int(width), Int(height))
 	End Method
+
+	Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Override
+		Local frame:TSDLRenderImageFrame = New TSDLRenderImageFrame
+		frame.renderer = _driver.renderer
+'Ronny: TODO - still needed?
+		frame.pixmap = CreatePixmap( width, height, PF_RGBA8888 )
+
+		frame.surface = TSDLSurface.CreateRGB(width, height, 4, $000000ff:UInt, $0000ff00:UInt, $00ff0000:UInt, $ff000000:UInt)
+		frame.texture = frame.renderer.CreateTexture(SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, width, height)
+
+		frame.uscale = 1.0 / width
+		frame.vscale = 1.0 / height
+		frame.u1 = width * frame.uscale
+		frame.v1 = height * frame.vscale
+		Return frame
+	EndMethod
 	
+	Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override
+		If RenderImageFrame = _CurrentRenderImageFrame
+			Return
+		EndIf
+		If not TSDLRenderImageFrame(RenderImageFrame) Then Return
+		
+		renderer.SetTarget(TSDLRenderImageFrame(RenderImageFrame).texture)
+		_CurrentRenderImageFrame = TSDLRenderImageFrame(RenderImageFrame)
+		
+		Local vp:Rect = _ClipRect_BMaxViewport
+		renderer.SetClipRect(vp.x, vp.y, vp.width, vp.height)
+		SetMatrixAndViewportToCurrentRenderImage()
+	EndMethod
+	
+	Method SetBackbuffer()
+		SetRenderImageFrame(_BackBufferRenderImageFrame)
+	EndMethod
+	
+
+	Method SetMatrixAndViewportToCurrentRenderImage()
+'Ronny: TODO - still needed?
+rem
+		glMatrixMode(GL_PROJECTION)
+		glLoadIdentity()
+		glOrtho(0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height, 0, -1, 1)
+		glMatrixMode(GL_MODELVIEW)
+		glLoadIdentity()
+		glViewport(0, 0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height)
+endrem
+	EndMethod
 End Type
 
 Rem
@@ -532,3 +590,20 @@ Function SDLPrioritizeRenderer( renderer:String, priority:ESDLHintPriority = ESD
 		End If
 	Next
 End Function
+
+
+Rem
+bbdoc: Get a list of available renderer drivers.
+about: Available renderers vary by platform.
+End Rem
+Function SDLGetRendererNames:String[]()
+	Local result:String[] = New String[ SDLGetNumRenderDrivers() ]
+
+	For Local i:int = 0 Until SDLGetNumRenderDrivers()
+		Local info:SDLRendererInfo
+		SDLGetRenderDriverInfo(i, info)
+
+		result[i] = info.GetName()
+	Next
+	Return result
+End Function