Browse Source

Merge pull request #284 from GWRon/feat_render2texture_update

[Max2D] Update render2texture base
Brucey 2 years ago
parent
commit
a6420b252a

+ 273 - 519
d3d9max2d.mod/d3d9max2d.bmx

@@ -48,6 +48,10 @@ Global _d3dDev:IDirect3DDevice9
 Global _d3d9Graphics:TD3D9Graphics
 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
@@ -103,7 +107,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
@@ -188,244 +192,65 @@ Type TD3D9ImageFrame Extends TImageFrame
 	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:TD3D9Graphics
-	Field _d3ddev:IDirect3DDevice9
-	Field _backbuffer:IDirect3DSurface9
-	Field _matrix:Float[16]
-	Field _viewport:D3DVIEWPORT9
-	Field _renderImages:TList
-	Field _deviceok:Int = True
-
-	Method Delete()
-		ReleaseNow()
-	End Method
-	
-	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
-	End Method
-
-	Method Create:TD3D9RenderimageContext(g:TGraphics, driver:TGraphicsDriver)
-		_gc = TD3D9Graphics(g)
-
-'		_gc.AddDeviceMightGetLostCallback(fnOnDeviceMightGetLost, Self)
-		_gc.AddDeviceLostCallback(fnOnDeviceLost, Self)
-		_gc.AddDeviceResetCallback(fnOnDeviceReset, Self)
-
-		_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
-	End Method
-	
-	Method GraphicsContext:TGraphics()
-		Return _gc
-	End Method
-	
-	Method Destroy()
-'		_gc.RemoveDeviceMightGetLostCallback(fnOnDeviceMightGetLost)
-		_gc.RemoveDeviceLostCallback(fnOnDeviceLost)
-		_gc.RemoveDeviceResetCallback(fnOnDeviceReset)
-		ReleaseNow()
-	End Method
-
-	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
-	End Method
-	
-	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
-	End Method
-	
-	Method DestroyRenderImage(renderImage:TRenderImage)
-		renderImage.DestroyRenderImage()
-		_renderImages.Remove(renderImage)
-	End Method
-
-	Method SetRenderImage(renderimage:TRenderimage)
-		If Not renderimage
-			_d3ddev.SetRenderTarget(0, _backbuffer)	
-			_d3ddev.SetTransform D3DTS_PROJECTION,_matrix
-			_d3ddev.SetViewport(_viewport)
-		Else
-			renderimage.SetRenderImage()
-		EndIf
-	End Method
-	
-	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
-		Return TD3D9RenderImage(renderImage).ToPixmap()
-	End Method
-
-rem
-	Method OnDeviceMightGetLost()
-		For Local ri:TD3D9RenderImage = EachIn _renderImages
-			ri.OnDeviceMightGetLost()
-		Next
-	End Method
-endrem
-
-	Method OnDeviceLost()
-		If _deviceok = False Then Return
-
-		For Local ri:TD3D9RenderImage = EachIn _renderImages
-			ri.OnDeviceLost()
-		Next
-		If _backbuffer
-			_backbuffer.release_
-			_backbuffer = Null
-		EndIf
-
-		_deviceok = False
-	End Method
-
-	Method OnDeviceReset()
-		If _deviceok = True Then Return
-
-		Local hr:Int = _d3ddev.GetRenderTarget(0, _backbuffer)
-		if hr = D3D_OK
-'			print "  _d3ddev.GetRenderTarget() result: D3D_OK" 
-		Elseif hr = D3DERR_INVALIDCALL
-			print "  _d3ddev.GetRenderTarget() result: D3DERR_INVALIDCALL" 
-		Elseif hr = D3DERR_NOTFOUND
-			print "  _d3ddev.GetRenderTarget() result: D3DERR_NOTFOUND"
-		Else 
-			print "  _d3ddev.GetRenderTarget() result: " + hr
-		EndIf
-		hr = _d3ddev.GetViewport(_viewport)
-
-		For Local ri:TD3D9RenderImage = EachIn _renderImages
-			ri.OnDeviceReset()
-		Next
-
-		_deviceok = True
-	End Method
-
-rem
-	Function fnOnDeviceMightGetLost(obj:Object)
-		Local ric:TD3D9RenderImageContext = TD3D9RenderImageContext(obj)
-		If Not ric Return
-		ric.OnDeviceMightGetLost()
-	EndFunction
-endrem
-
-	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()
 	End Method
-
-	'ensure the GPU located render image would survive a "appsuspend"
-	'by eg. reading it into a TPixmap
-	Method Persist:Int(d3ddev:IDirect3DDevice9, width:Int, height:Int)
-		_persistPixmap = ToPixmap(d3ddev, width, height)
-		Return True
-	End Method
-
 	
 	Method ReleaseNow()
 		If _surface
@@ -437,111 +262,127 @@ Type TD3D9RenderImageFrame Extends TD3D9ImageFrame
 			_texture = Null
 		EndIf
 	End Method
-	
-	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
+	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
 
-	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
+		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
-	End Method
-	
-	Method DestroyRenderImage()
-		ReleaseNow()
-	End Method
-	
-rem
-	'once a device is lost we cannot simply backup a pixmap, so better
-	'do it any time we _could_ loose the device (eg. app suspend)
-	Method OnDeviceMightGetLost(d3ddev:IDirect3DDevice9, width:Int, height:Int)
-		print "TD3D9ImageFrame.OnDeviceMightGetLost(): persisting to pixmap"
-		Persist()
-	End Method
-endrem
-
-	Method OnDeviceLost(d3ddev:IDirect3DDevice9, width:Int, height:Int)
-		'only read in a new pixmap if none was created before
-		'in case of "suspend and resum" this ToPixmap() call will return
-		'an empty pixmap (because of "D3DERR_DEVICELOST")
-		If Not _persistPixmap
-			_persistPixmap = ToPixmap(d3ddev, width, height)
+		Return RenderImage
+	End Function
+
+	Method OnDeviceLost()
+		Local BackBuffer:TD3D9RenderImageFrame = _BackBufferRenderImageFrame
+		If Self <> BackBuffer And Not _stagingpixmap
+			If _surface
+				_stagingPixmap  = RenderTargetToPixmap()
+			EndIf
 		EndIf
 		ReleaseNow()
 	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
-	End Method
-	
-	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)
+			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_
+		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)
@@ -550,210 +391,29 @@ endrem
 			Next
 		Next
 		
-		pixmap = ConvertPixmap(pixmap, PF_BGRA)
-		
-		' cleanup
-		stage.UnlockRect()
-		stage.release_
+		StagingSurface.UnlockRect()
+		StagingSurface.Release_()
 		
-		Return pixmap
+		Return ConvertPixmap(pixmap, PF_BGRA)
 	End Method
 EndType
 
-Type TD3D9RenderImage Extends TRenderImage
-	Field _d3ddev:IDirect3DDevice9
-	Field _viewport:D3DVIEWPORT9
-	Field _matrix:Float[]
-
-	Method Delete()
-		ReleaseNow()
-	End Method
-
-	'ensure the GPU located render image would survive a "appsuspend"
-	'by eg. reading it into a TPixmap
-	Method Persist:Int() Override
-		if TD3D9RenderImageFrame(frames[0])
-			Return TD3D9RenderImageFrame(frames[0]).Persist(_d3ddev, width, height)
-		EndIf
-		Return False
-	End Method
-
-	
-	Method ReleaseNow()
-		If _d3ddev
-			_d3ddev.release_
-			_d3ddev = Null
-		EndIf
-	End Method
-
-	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
-	End Method
-	
-	Method DestroyRenderImage()
-		ReleaseNow()
-		TD3D9RenderImageFrame(frames[0]).ReleaseNow()
-	End Method
-
-	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
-		
-		' 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
-		If prevsurf Then prevsurf.release_
-	End Method
-	
-	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)
-	End Method	
-
-	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)
-	End Method
-
-	Method Frame:TImageFrame(index:Int=0)
-		If Not frames Return Null
-		If Not frames[0] Return Null
-		Return frames[0]
-	End Method
-	
-	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)
-	End Method
-	
-	Method ToPixmap:TPixmap()
-		Return TD3D9RenderImageFrame(frames[0]).ToPixmap(_d3ddev, width, height)
-	End Method
-	
-	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
-
-	End Method
-
-'	Method OnDeviceMightGetLost()
-'		TD3D9RenderImageFrame(frames[0]).OnDeviceMightGetLost(_d3ddev, width, height)
-'	End Method
-
-	Method OnDeviceLost()
-		'invalidate (even with existing persistPixmap!)
-		_valid = False
-
-		TD3D9RenderImageFrame(frames[0]).OnDeviceLost(_d3ddev, width, height)
-	End Method
-
-	Method OnDeviceReset()
-		TD3D9RenderImageFrame(frames[0]).OnDeviceReset(_d3ddev)
-	End Method
-EndType
-
-
-
 Type TD3D9Max2DDriver Extends TMax2dDriver
 
 	Method ToString:String() Override
 		Return "DirectX9"
 	End Method
 
-	Method Create:TD3D9Max2DDriver()
+	Method ApiIdentifier:String() Override
+		Return "BRL.Direct3D9"
+	End Method
 
+	Method Create:TD3D9Max2DDriver()
 		If Not D3D9GraphicsDriver() Return Null
 
 		Local d3d:IDirect3D9 = D3D9GraphicsDriver().GetDirect3D()
 		
-		If d3d.CheckDeviceFormat( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,0,D3DRTYPE_TEXTURE,D3DFMT_A8R8G8B8 )<0
+		If d3d.CheckDeviceFormat( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,0,D3DRTYPE_TEXTURE,D3DFMT_A8R8G8B8 ) < 0
 			Return Null
 		EndIf
 
@@ -792,7 +452,7 @@ Type TD3D9Max2DDriver Extends TMax2dDriver
 
 		_max2dGraphics=TMax2dGraphics( g )
 
-		_d3d9graphics=TD3D9Graphics( _max2dGraphics._graphics )
+		_d3d9graphics=TD3D9Graphics( _max2dGraphics._backendGraphics )
 
 		If Not _max2dGraphics Or Not _d3d9graphics Then
 			Throw "SetGraphics failed for D3D9"
@@ -828,8 +488,8 @@ Type TD3D9Max2DDriver 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)
@@ -864,14 +524,15 @@ Type TD3D9Max2DDriver 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
@@ -923,34 +584,21 @@ Type TD3D9Max2DDriver 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
@@ -1096,6 +744,11 @@ Type TD3D9Max2DDriver 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
@@ -1154,6 +807,107 @@ Type TD3D9Max2DDriver 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:TD3D9Max2DDriver = TD3D9Max2DDriver(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:TD3D9Max2DDriver = TD3D9Max2DDriver(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:Float[] = [..
+		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

+ 13 - 10
dxgraphics.mod/d3d9graphics.bmx

@@ -176,12 +176,12 @@ Function CloseD3DDevice()
 
 		_d3dDev.Release_
 		_d3dDev=Null
-'		_presentParams=null
+		_presentParams=Null
 	EndIf
 End Function
 
 Function ResetD3DDevice()
-	If _graphics 
+	If _graphics
 		_graphics.OnDeviceLost()
 	EndIf
 	If _d3dOccQuery
@@ -195,7 +195,7 @@ Function ResetD3DDevice()
 		Throw "_d3dDev.Reset failed"
 	EndIf
 
-	If _graphics 
+	If _graphics
 		_graphics.OnDeviceReset()
 	EndIf
 	If _d3ddev.CreateQuery(9,_d3dOccQuery)<0
@@ -313,10 +313,14 @@ Type TD3D9Graphics Extends TGraphics
 		Local state:Short = (wp Shr 16) & $FFFF
 		
 		' only release when fullscreen
-		If activate = 0 And _depth <> 0
-			OnDeviceLost()
+		If _depth <> 0
+			If activate = 0			' deactive
+				OnDeviceLost()
+			EndIf
+			If activate = 1
+				OnDeviceReset()		' active
+			EndIf
 		EndIf
-		' the Flip(sync) method will call into ResetD3DDevice where OnDeviceReset will be called
 	EndMethod
 
 	Method AddDeviceLostCallback(fnOnDeviceLostCallback(obj:Object), obj:Object)
@@ -405,7 +409,6 @@ Type TD3D9Graphics Extends TGraphics
 
 			EndIf
 		Case D3DERR_DEVICENOTRESET
-
 			ResetD3DDevice
 
 		End Select
@@ -498,9 +501,9 @@ Type TD3D9GraphicsDriver Extends TGraphicsDriver
 			EndIf
 
 			Local Mode:TGraphicsMode=New TGraphicsMode
-			Mode.width=d3dmode.Width
-			Mode.height=d3dmode.Height
-			Mode.hertz=d3dmode.RefreshRate
+			Mode.width=d3dmode.width
+			Mode.height=d3dmode.height
+			Mode.hertz=d3dmode.refreshRate
 			Mode.depth=32
 			_modes[j]=Mode
 			j:+1

+ 405 - 507
glmax2d.mod/glmax2d.bmx

@@ -8,12 +8,14 @@ The OpenGL Max2D module provides an OpenGL driver for #Max2D.
 End Rem
 Module BRL.GLMax2D
 
-ModuleInfo "Version: 1.14"
+ModuleInfo "Version: 1.15"
 ModuleInfo "Author: Mark Sibly"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
 ModuleInfo "Modserver: BRL"
 
+ModuleInfo "History: 1.15"
+ModuleInfo "History: Added RenderImages / render2texture"
 ModuleInfo "History: 1.14"
 ModuleInfo "History: Changed to SuperStrict"
 ModuleInfo "History: Extended flags to Long"
@@ -45,12 +47,15 @@ Import BRL.Threads
 Private
 
 Global _driver:TGLMax2DDriver
+Global _BackbufferRenderImageFrame:TGLRenderImageFrame
+Global _CurrentRenderImageFrame:TGLRenderImageFrame
+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]
@@ -60,37 +65,34 @@ 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:TDynamicArray = New TDynamicArray(32),dead_tex_seq: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 )
@@ -100,108 +102,109 @@ Function DeleteTex( name:Int,seq:Int )
 End Function
 
 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
-	
+	If pixmap.dds_fmt<>0 Then Return pixmap.tex_name ' if dds texture already exists
+
 	'alloc new tex
 	Local name:Int
-	glGenTextures 1,Varptr name
-	
+	glGenTextures( 1, Varptr name )
+
 	'flush dead texs
 	If dead_tex_seq=GraphicsSeq
 		Local n:Int = dead_texs.RemoveLast()
 		While n <> $FFFFFFFF
-			glDeleteTextures 1, Varptr n
+			glDeleteTextures(1, Varptr n)
 			n = dead_texs.RemoveLast()
 		Wend
 	EndIf
 
-	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 Return ' if dds texture already exists
+	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
-	
+
 	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))
@@ -218,25 +221,25 @@ Type TDynamicArray
 			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
 
@@ -244,278 +247,36 @@ Type TDynamicArray
 		free_(data)
 		CloseMutex(guard)
 	End Method
-	
-End Type
-
-
-
-
-Global glewIsInit:Int
-
-Type TGLRenderImageContext Extends TRenderImageContext
-	Field _gc:TGLGraphics
-	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
-
-	Method Create:TGLRenderimageContext(gc:TGraphics, driver:TGraphicsDriver)
-		If Not glewIsInit
-			glewInit()
-			glewIsInit = True
-		EndIf
 
-		_renderimages = New TList
-		_gc = TGLGraphics(gc)
-		_width = GraphicsWidth()
-		_height = GraphicsHeight()
-
-		' 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
 End Type
 
-
-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)		
-
-		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: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
-
-		If UseImageFiltering
-			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
-		
-		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()
-			' set and clear to a default colour
-			'glClearColor 0, 0, 0, 0
-			'glClear(GL_COLOR_BUFFER_BIT)
-		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
-		
-		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 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)
-	End Method
-
-	Method Frame:TImageFrame(index:Int=0)
-		Return frames[0]
-	EndMethod
-	
-	Method SetRenderImage()
-		glBindFrameBuffer(GL_FRAMEBUFFER, TGLRenderImageFrame(frames[0])._fbo)
-
-		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
@@ -529,63 +290,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.dds_fmt=0 ' not dds
-				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,tex )
+		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 TGLRenderImageFrame Extends TGLImageFrame
+	Field FBO:Int
+	Field width:Int
+	Field height:Int
+	
+	Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
+		Assert seq=GraphicsSeq Else "Image does not exist"
+
+		' 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
+	EndMethod
+	
+	Function Create:TGLRenderImageFrame(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:TGLRenderImageFrame = New TGLRenderImageFrame
+		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
+	EndFunction
+	
+Private
+	Method Delete()
+		glDeleteFramebuffers(1, Varptr FBO) ' gl ignores 0
+	EndMethod
+
+	Method New()
+	EndMethod
+EndType
 
+Type TGLMax2DDriver Extends TMax2DDriver
 	Method Create:TGLMax2DDriver()
 		If Not GLGraphicsDriver() Return Null
-		
+	
 		Return Self
 	End Method
 
@@ -595,46 +442,56 @@ Type TGLMax2DDriver Extends TMax2DDriver
 	End Method
 	
 	Method AttachGraphics:TMax2DGraphics( widget:Byte Ptr,flags:Long ) Override
-		Local g:TGLGraphics=GLGraphicsDriver().AttachGraphics( widget,flags )
+		Local g:TGLGraphics = GLGraphicsDriver().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:TGLGraphics=GLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
+		Local g:TGLGraphics = GLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
 		If g Return TMax2DGraphics.Create( g,Self )
 	End Method
 	
 	Method SetGraphics( g:TGraphics ) Override
 		If Not g
-			TMax2DGraphics.ClearCurrent
-			GLGraphicsDriver().SetGraphics Null
+			TMax2DGraphics.ClearCurrent()
+			GLGraphicsDriver().SetGraphics(Null)
 			Return
 		EndIf
 	
-		Local t:TMax2DGraphics=TMax2DGraphics(g)
-		Assert t And TGLGraphics( t._graphics )
+		Local t:TMax2DGraphics = TMax2DGraphics( g )
+		Assert t And TGLGraphics( t._backendGraphics )
 
-		GLGraphicsDriver().SetGraphics t._graphics
+		GLGraphicsDriver().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:TGLRenderImageFrame = New TGLRenderImageFrame
+		BackBufferRenderImageFrame.width = gw
+		BackBufferRenderImageFrame.height = gh
+	
+		' cache it
+		_BackBufferRenderImageFrame = BackBufferRenderImageFrame
+		_CurrentRenderImageFrame = _BackBufferRenderImageFrame
 	End Method
 	
 	Method Flip:Int( sync:Int ) Override
@@ -645,196 +502,237 @@ Type TGLMax2DDriver Extends TMax2DDriver
 		Return "OpenGL"
 	End Method
 
-	Method CreateRenderImageContext:Object(g:TGraphics) Override
-		Return new TGLRenderImageContext.Create(g, self)
+	Method ApiIdentifier:String() Override
+		Return "BRL.OpenGL"
 	End Method
-	
-	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap,flags:Int ) Override
-		Return TGLImageFrame.CreateFromPixmap( pixmap,flags )
+
+	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
+	Method SetTransform( xx:Float, xy:Float, yx:Float, yy:Float ) Override
+		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 TGLRenderImageFrame.Create(width, height, flags)
+	EndMethod
 	
+	Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override
+		If RenderImageFrame = _CurrentRenderImageFrame
+			Return
+		EndIf
+		
+		glBindFrameBuffer(GL_FRAMEBUFFER, TGLRenderImageFrame(RenderImageFrame).FBO)
+		_CurrentRenderImageFrame = TGLRenderImageFrame(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
glmax2d.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

+ 4 - 0
graphics.mod/graphics.bmx

@@ -101,6 +101,10 @@ Type TGraphicsDriver
 	End Method
 
 	Method ToString:String() Abstract
+	
+	Method ApiIdentifier:String()
+		Return ToString()
+	End Method
 
 	Method GetHandle:Byte Ptr(handleType:EGraphicsHandleType = EGraphicsHandleType.Window)
 		Return Null

+ 12 - 5
max2d.mod/driver.bmx

@@ -19,6 +19,7 @@ Const DYNAMICIMAGE:Int=		$8
 
 'current driver
 Global _max2dDriver:TMax2DDriver
+Global _currentBoundRenderImage:TImageFrame
 
 Type TImageFrame
 
@@ -31,28 +32,34 @@ Type TMax2DDriver Extends TGraphicsDriver
 	'Backend specific!
 	'implement this function in each TMax2D-extending type (OpenGL, DX, ..)
 	Method CreateRenderImageContext:Object(g:TGraphics)
-		Throw "Feature ~qRender2Texture~q not yet implemented in this graphics driver (" + ToString() + ")." 
+		Throw "Feature ~qRender2Texture~q not yet implemented in this graphics driver (" + _max2dDriver.ToString() + ")." 
 		Return Null
 	End Method
 
 	Method CreateFrameFromPixmap:TImageFrame( pixmap:TPixmap,flags:Int ) Abstract
+	Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Abstract
+	Method SetBackBuffer() Abstract
+	Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Abstract
 	
 	Method SetBlend( blend:Int ) Abstract
 	Method SetAlpha( alpha:Float ) Abstract
 	Method SetColor( red:Int,green:Int,blue:Int ) Abstract
-	Method SetClsColor( red:Int,green:Int,blue:Int ) Abstract
+	Method SetClsColor( red:Int, green:Int, blue:Int, alpha:Float ) Abstract
 	Method SetViewport( x:Int,y:Int,width:Int,height:Int ) Abstract
 	Method SetTransform( xx:Float,xy:Float,yx:Float,yy:Float ) Abstract
 	Method SetLineWidth( width:Float ) Abstract
 
-	Method SetColor( color:SColor8 )
+	'these methods rely on the abstract ones - no need to enable overriding
+	'them, so marked as "final"
+	Method SetColor( color:SColor8 ) Final
 		SetColor(color.r, color.g, color.b)
 	End Method
-	Method SetClsColor( color:SColor8)
-		SetClsColor(color.r, color.g, color.b)
+	Method SetClsColor( color:SColor8, alpha:Float) Final
+		SetClsColor(color.r, color.g, color.b, alpha)
 	End Method
 	
 	Method Cls() Abstract
+	
 	Method Plot( x:Float,y:Float ) Abstract
 	Method DrawLine( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float ) Abstract
 	Method DrawRect( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float ) Abstract

+ 51 - 4
max2d.mod/image.bmx

@@ -8,7 +8,7 @@ bbdoc: Max2D Image type
 End Rem
 Type TImage
 
-	Field width:Int,height:Int,flags:Int
+	Field width:UInt,height:UInt,flags:Int
 	Field mask_r:Int,mask_g:Int,mask_b:Int
 	Field handle_x#,handle_y#
 	Field pixmaps:TPixmap[]
@@ -28,6 +28,19 @@ Type TImage
 		Return frames[index]
 	End Method
 	
+	Method Clear(r:UInt, g:UInt, b:UInt, a:Float = 1.0, frameIndex:Int = -1)
+		Local clearColor:Int = Int(int(255*a) * $1000000) + Int(r * $10000) + Int(g * $100) + b
+		If frameIndex < 0
+			For Local i:Int = 0 until pixmaps.length
+				Local p:TPixmap = Lock(i, True, True)
+				p.ClearPixels(clearColor)
+			Next
+		Else
+			Local p:TPixmap = Lock(frameIndex, True, True)
+			p.ClearPixels(clearColor)
+		EndIf
+	End Method
+	
 	Method Lock:TPixmap( index:Int,read:Int,write:Int )
 		Assert index < seqs.length And index < frames.length Else "Index out of bounds"
 		If write
@@ -72,7 +85,7 @@ Type TImage
 	Function Load:TImage( url:Object,flags:Int,mr:Int,mg:Int,mb:Int )
 		Local pixmap:TPixmap=TPixmap(url)
 		If Not pixmap pixmap=LoadPixmap(url)
-		If Not pixmap Return null
+		If Not pixmap Return Null
 		Local t:TImage=Create( pixmap.width,pixmap.height,1,flags,mr,mg,mb )
 		t.SetPixmap 0,pixmap
 		Return t
@@ -82,11 +95,11 @@ Type TImage
 		Assert cell_width > 0 And cell_height > 0 Else "Cell dimensions out of bounds"
 		Local pixmap:TPixmap=TPixmap(url)
 		If Not pixmap pixmap=LoadPixmap(url)
-		If Not pixmap Return null
+		If Not pixmap Return Null
 
 		Local x_cells:Int=pixmap.width/cell_width
 		Local y_cells:Int=pixmap.height/cell_height
-		If first+count>x_cells*y_cells Return null
+		If first+count>x_cells*y_cells Return Null
 		
 		Local t:TImage=Create( cell_width,cell_height,count,flags,mr,mg,mb )
 
@@ -100,3 +113,37 @@ Type TImage
 	End Function
 	
 End Type
+
+Type TRenderImage Extends TImage
+	Method Frame:TImageFrame(index:Int) Override
+		Assert index < seqs.length And index < frames.length Else "Index out of bounds"
+		If seqs[index] = GraphicsSeq
+			Return frames[index]
+		EndIf
+		
+		frames[index] = _max2dDriver.CreateRenderImageFrame(width, height, flags)
+		If frames[index]
+			seqs[index] = GraphicsSeq
+		Else
+			seqs[index] = 0
+		EndIf
+		
+		Return frames[index]
+	End Method
+	
+	Function Create:TRenderImage(width:Int, height:Int, flags:Int, MaskRed:Int, MaskGreen:Int, MaskBlue:Int)
+		Local t:TRenderImage = New TRenderImage
+		t.width = width
+		t.height = height
+		t.flags = flags
+		t.mask_r = MaskRed
+		t.mask_g = MaskGreen
+		t.mask_b = MaskBlue
+		t.pixmaps = New TPixmap[1]
+		t.frames = New TImageFrame[1]
+		t.seqs = New Int[1]
+		t.frameDuration = New Int[1]
+		
+		Return t
+	EndFunction
+EndType

File diff suppressed because it is too large
+ 677 - 195
max2d.mod/max2d.bmx


+ 0 - 44
max2d.mod/renderimage.bmx

@@ -1,44 +0,0 @@
-SuperStrict
-
-Import "driver.bmx"
-Import "image.bmx"
-
-
-Type TRenderImage Extends TImage
-	Field _valid:Int = 1
-
-	'returns wether the content is still valid. Might be blanked
-	'on "appsuspend" if no content persisting happened before
-	Method Valid:Int()
-		Return _valid
-	End Method
-
-	Method SetValid(bool:Int)
-		_valid = bool
-	End Method
-	
-	'ensure the GPU located render image would survive a "appsuspend"
-	'by eg. reading it into a TPixmap
-	Method Persist:Int()
-		Return False
-	End Method
-	
-	Method CreateRenderImage:TRenderImage(width:Int, height:Int) Abstract
-	Method DestroyRenderImage() Abstract
-	Method SetRenderImage() Abstract
-	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0) Abstract
-	Method SetViewport(x:Int, y:Int, width:Int, height:Int) Abstract
-End Type
-
-
-Type TRenderImageContext
-	Method Create:TRenderimageContext(gc:TGraphics, driver:TGraphicsDriver) Abstract
-	Method Destroy() Abstract
-	Method GraphicsContext:TGraphics() Abstract
-
-	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseImageFiltering:Int) Abstract
-	Method DestroyRenderImage(renderImage:TRenderImage) Abstract
-	Method SetRenderImage(renderimage:TRenderImage) Abstract
-	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage) Abstract
-	Method CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, UseImageFiltering:Int) Abstract
-End Type

Some files were not shown because too many files changed in this diff