Kaynağa Gözat

Merge pull request #26 from GWRon/feat_render2texture

[Max2D] Add "render image" support (render2texture)
Brucey 3 yıl önce
ebeveyn
işleme
4862183510

+ 159 - 5
d3d9sdlgraphics.mod/d3d9sdlgraphics.bmx

@@ -10,6 +10,9 @@ Import SDL.SDLGraphics
 Import BRL.LinkedList
 
 Private
+'Extern
+'	Function bbAppIcon:Byte Ptr(inst:Byte Ptr)="HICON bbAppIcon(HINSTANCE)!"
+'End Extern
 
 'Global _wndClass$="BBDX9Device Window Class"
 
@@ -33,6 +36,25 @@ Global _d3dOccQuery:IDirect3DQuery9
 Type TD3D9AutoRelease
 	Field unk:IUnknown_
 End Type
+Rem
+Function D3D9WndProc:Byte Ptr( hwnd:Byte Ptr,msg:UInt,wp:WParam,lp:LParam) "win32"
+
+	bbSystemEmitOSEvent hwnd,msg,wp,lp,Null
+	
+	Select msg
+	Case WM_CLOSE
+		Return Null
+	Case WM_SYSKEYDOWN
+		If wp<>KEY_F4 Return Null
+	Case WM_ACTIVATE
+		If _graphics _graphics.OnWMActivate(wp)
+		Return 0
+	End Select
+
+	Return DefWindowProcW( hwnd,msg,wp,lp )
+
+End Function
+EndRem
 
 Function OpenD3DDevice:Int( hwnd:Byte Ptr,width:Int,height:Int,depth:Int,hertz:Int,flags:Long)
 	If _d3dDevRefs
@@ -60,7 +82,48 @@ Function OpenD3DDevice:Int( hwnd:Byte Ptr,width:Int,height:Int,depth:Int,hertz:I
 	
 	Local cflags:Int=D3DCREATE_FPU_PRESERVE
 	
-	'_d3dDev = New IDirect3DDevice9
+	'_d3dDev' = New IDirect3DDevice9
+
+	Function CheckDepthFormat(format:Int)
+	    Return _d3d.CheckDeviceFormat(0,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,D3DUSAGE_DEPTHSTENCIL,D3DRTYPE_SURFACE,format)=D3D_OK
+	End Function
+
+	If flags&GRAPHICS_DEPTHBUFFER Or flags&GRAPHICS_STENCILBUFFER
+	    pp.EnableAutoDepthStencil = True
+	    If flags&GRAPHICS_STENCILBUFFER
+	        If Not CheckDepthFormat( D3DFMT_D24S8 )
+	            If Not CheckDepthFormat( D3DFMT_D24FS8 )
+	                If Not CheckDepthFormat( D3DFMT_D24X4S4 )
+	                    If Not CheckDepthFormat( D3DFMT_D15S1 )
+	                        Return False
+	                    Else
+	                        pp.AutoDepthStencilFormat = D3DFMT_D15S1
+	                    EndIf
+	                Else
+	                    pp.AutoDepthStencilFormat = D3DFMT_D24X4S4
+	                EndIf
+	            Else
+	                pp.AutoDepthStencilFormat = D3DFMT_D24FS8
+	            EndIf
+	        Else
+	            pp.AutoDepthStencilFormat = D3DFMT_D24S8
+	        EndIf
+	    Else
+	        If Not CheckDepthFormat( D3DFMT_D32 )
+	            If Not CheckDepthFormat( D3DFMT_D24X8 )
+	                If Not CheckDepthFormat( D3DFMT_D16 )
+	                    Return False
+	                Else
+	                    pp.AutoDepthStencilFormat = D3DFMT_D16
+	                EndIf
+	            Else
+	                pp.AutoDepthStencilFormat = D3DFMT_D24X8
+	            EndIf
+	        Else
+	            pp.AutoDepthStencilFormat = D3DFMT_D32
+	        EndIf
+	    EndIf
+	EndIf
 	
 	'OK, try hardware vertex processing...
 	Local tflags:Int=D3DCREATE_PUREDEVICE|D3DCREATE_HARDWARE_VERTEXPROCESSING|cflags
@@ -119,6 +182,9 @@ Function CloseD3DDevice()
 End Function
 
 Function ResetD3DDevice()
+	If _graphics 
+		_graphics.OnDeviceLost()
+	EndIf
 	If _d3dOccQuery
 		_d3dOccQuery.Release_
 		_d3dOccQuery = Null
@@ -126,8 +192,13 @@ Function ResetD3DDevice()
 		'_d3dOccQuery = New IDirect3DQuery9
 	End If
 	
-	If _d3dDev.Reset( _presentParams)<0
-		Throw "_d3dDev.Reset failed"
+	Local result:Int = _d3dDev.Reset( _presentParams)
+	If result < 0
+		Throw "_d3dDev.Reset failed. Code: " + result
+	EndIf
+
+	If _graphics 
+		_graphics.OnDeviceReset()
 	EndIf
 
 	If _d3ddev.CreateQuery(9,_d3dOccQuery)<0
@@ -142,7 +213,24 @@ Public
 
 Global UseDX9RenderLagFix:Int = 0
 
+Type TD3D9SDLDeviceStateCallback
+	Field _fnCallback(obj:Object)
+	Field _obj:Object
+	
+	Method Create:TD3D9SDLDeviceStateCallback(fnCallback(obj:Object), obj:Object)
+		_fnCallback = fnCallback
+		_obj = obj
+
+		Return Self
+	EndMethod
+EndType
+
+
 Type TD3D9SDLGraphics Extends TGraphics
+	Method New()
+		_onDeviceLostCallbacks = New TList
+		_onDeviceResetCallbacks = New TList
+	EndMethod
 
 	Method Attach:TD3D9SDLGraphics( hwnd:Byte Ptr,flags:Long )
 		Local rect:Int[4]
@@ -190,6 +278,56 @@ Type TD3D9SDLGraphics Extends TGraphics
 		Return Self
 	End Method
 	
+	Method OnWMActivate(wp:WParam)
+		' this covers the alt-tab issue for render-texture management
+		Local activate:Short = wp & $FFFF
+		Local state:Short = (wp Shr 16) & $FFFF
+		
+		' only release when fullscreen
+		If activate = 0 And _depth <> 0
+			OnDeviceLost()
+		EndIf
+		' the Flip(sync) method will call into ResetD3DDevice where OnDeviceReset will be called
+	EndMethod
+	
+	Method AddDeviceLostCallback(fnOnDeviceLostCallback(obj:Object), obj:Object)
+		_onDeviceLostCallbacks.AddLast(New TD3D9SDLDeviceStateCallback.Create(fnOnDeviceLostCallback, obj))
+	EndMethod
+	
+	Method AddDeviceResetCallback(fnOnDeviceResetCallback(obj:Object), obj:Object)
+		_onDeviceResetCallbacks.AddLast(New TD3D9SDLDeviceStateCallback.Create(fnOnDeviceResetCallback, obj))
+	EndMethod
+	
+	Method RemoveDeviceLostCallback(fnOnDeviceLostCallback(obj:Object))
+		For Local statecallback:TD3D9SDLDeviceStateCallback = EachIn _onDeviceLostCallbacks
+			If statecallback._fnCallback = fnOnDeviceLostCallback
+				_onDeviceLostCallbacks.Remove(statecallback)
+				Exit
+			EndIf
+		Next
+	EndMethod
+
+	Method RemoveDeviceResetCallback(fnOnDeviceResetCallback(obj:Object))
+		For Local statecallback:TD3D9SDLDeviceStateCallback = EachIn _onDeviceResetCallbacks
+			If statecallback._fnCallback = fnOnDeviceResetCallback
+				_onDeviceResetCallbacks.Remove(statecallback)
+				Exit
+			EndIf
+		Next
+	EndMethod
+
+	Method OnDeviceLost()
+		For Local callback:TD3D9SDLDeviceStateCallback = EachIn _onDeviceLostCallbacks
+			callback._fnCallback(callback._obj)
+		Next
+	EndMethod
+	
+	Method OnDeviceReset()
+		For Local callback:TD3D9SDLDeviceStateCallback = EachIn _onDeviceResetCallbacks
+			callback._fnCallback(callback._obj)
+		Next
+	EndMethod
+		
 	Method GetDirect3DDevice:IDirect3DDevice9()
 		Return _d3dDev
 	End Method
@@ -300,7 +438,8 @@ Type TD3D9SDLGraphics Extends TGraphics
 	Field _attached:Int
 	
 	Field _g:TSDLGraphics
-
+	Field _onDeviceLostCallbacks:TList
+	Field _onDeviceResetCallbacks:TList
 End Type
 
 Type TD3D9SDLGraphicsDriver Extends TGraphicsDriver
@@ -340,7 +479,9 @@ Type TD3D9SDLGraphicsDriver Extends TGraphicsDriver
 			j:+1
 		Next
 		_modes=_modes[..j]
-	
+
+		'RONNY: Listen event
+		AddHook (EmitEventHook, DeviceResetHook, Self, 0)
 	
 '		Local name:Short Ptr = _wndClass.ToWString()
 '		'register wndclass
@@ -348,6 +489,7 @@ Type TD3D9SDLGraphicsDriver Extends TGraphicsDriver
 '		wndclass.SethInstance(GetModuleHandleW( Null ))
 '		wndclass.SetlpfnWndProc(D3D9WndProc)
 '		wndclass.SethCursor(LoadCursorW( Null,Short Ptr IDC_ARROW ))
+'		wndClass.SethIcon(bbAppIcon(GetModuleHandleW( Null )))
 '		wndclass.SetlpszClassName(name)
 '		RegisterClassW wndclass.classPtr
 '		MemFree name
@@ -355,6 +497,18 @@ Type TD3D9SDLGraphicsDriver Extends TGraphicsDriver
 		Return Self
 	End Method
 	
+	Function DeviceResetHook:Object(id:Int, data:Object, context:Object)
+		Local ev:TEvent = TEvent(data)
+		If Not ev Then Return data
+		
+'		Select ev.id
+'			Case SDL_RENDER_DEVICE_RESET
+'				Throw "Device Reset!"
+'		End Select
+		
+		Return data
+	End Function
+	
 	Method GraphicsModes:TGraphicsMode[]() Override
 		Return _modes
 	End Method

+ 1101 - 670
d3d9sdlmax2d.mod/d3d9sdlmax2d.bmx

@@ -1,670 +1,1101 @@
-
-SuperStrict
-
-Rem
-bbdoc: Direct3D9 Max2D with SDL backend
-about:
-The Direct3D9 Max2D module provides a Direct3D9 driver for #Max2D.
-End Rem
-Module SDL.D3D9SDLMax2D
-
-ModuleInfo "Version: 1.01"
-ModuleInfo "License: zlib/libpng"
-ModuleInfo "Copyright: Blitz Research Ltd, Bruce A Henderson"
-
-ModuleInfo "History: 1.01"
-ModuleInfo "History: Changed to SuperStrict"
-ModuleInfo "History: Extended flags to Long"
-ModuleInfo "History: 1.00"
-ModuleInfo "History: Port to bmx-ng."
-
-?win32
-
-Import BRL.Max2D
-Import SDL.D3D9SDLGraphics
-
-Const LOG_ERRS:Int=True'False
-
-Private
-
-Global _gw:Int,_gh:Int,_gd:Int,_gr:Int,_gf:Long,_gx:Int,_gy:Int
-Global _color:Int
-Global _clscolor:Int
-Global _ix#,_iy#,_jx#,_jy#
-Global _fverts#[24]
-Global _iverts:Int Ptr=Int Ptr( Varptr _fverts[0] )
-Global _lineWidth#
-
-Global _bound_texture:IDirect3DTexture9
-Global _texture_enabled:Int
-
-Global _active_blend:Int
-
-Global _driver:TD3D9SDLMax2DDriver
-Global _d3dDev:IDirect3DDevice9
-Global _d3d9Graphics:TD3D9SDLGraphics
-Global _max2dGraphics:TMax2dGraphics
-
-Function Pow2Size:Int( n:Int )
-	Local t:Int=1
-	While t<n
-		t:*2
-	Wend
-	Return t
-End Function
-
-Function DisableTex()
-	If Not _texture_enabled Return
-	_d3dDev.SetTextureStageState 0,D3DTSS_COLOROP,D3DTOP_SELECTARG2
-	_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG2
-	_texture_enabled=False
-End Function
-
-Function d3derr( str$ )
-	If LOG_ERRS WriteStdout "D3DERR: "+str+"~n"
-End Function
-
-Public
-
-Type TD3D9ImageFrame Extends TImageFrame
-
-	Method Delete()
-		If _texture
-			If _seq=GraphicsSeq
-				If _texture=_bound_texture
-					_d3dDev.SetTexture 0,nullBaseTexture9
-					_bound_texture=Null
-				EndIf
-				_d3d9Graphics.ReleaseNow _texture
-			EndIf
-			_texture=Null
-		EndIf
-	End Method
-
-	Method Create:TD3D9ImageFrame( pixmap:TPixmap,flags:Int )
-
-		Local width:Int=pixmap.width,pow2width:Int=Pow2Size( width )
-		Local height:Int=pixmap.height,pow2height:Int=Pow2Size( height )
-		
-		If width<pow2width Or height<pow2height
-			Local src:TPixmap=pixmap
-			pixmap=TPixmap.Create( pow2width,pow2height,PF_BGRA8888 )
-			pixmap.Paste src,0,0
-			If width<pow2width
-				pixmap.Paste pixmap.Window( width-1,0,1,height ),width,0
-			EndIf
-			If height<pow2height
-				pixmap.Paste pixmap.Window( 0,height-1,width,1 ),0,height
-				If width<pow2width 
-					pixmap.Paste pixmap.Window( width-1,height-1,1,1 ),width,height
-				EndIf
-			EndIf
-		Else
-			If pixmap.Format<>PF_BGRA8888 pixmap=pixmap.Convert( PF_BGRA8888 )
-		EndIf
-
-		Local levels:Int=(flags & MIPMAPPEDIMAGE)=0
-		Local format:Int=D3DFMT_A8R8G8B8
-		Local usage:Int=0
-		Local pool:Int=D3DPOOL_MANAGED
-		
-		'_texture = New IDirect3DTexture9
-		If _d3dDev.CreateTexture( pow2width,pow2height,levels,usage,format,pool,_texture,Null )<0
-			d3derr "Unable to create texture~n"
-			_texture = Null
-			Return Null
-		EndIf
-		
-		_d3d9Graphics.AutoRelease _texture
-
-		Local level:Int
-		Local dstsurf:IDirect3DSurface9' = New IDirect3DSurface9
-		Repeat
-			If _texture.GetSurfaceLevel( level,dstsurf )<0
-				If level=0
-					d3derr "_texture.GetSurfaceLevel failed~n"
-				EndIf
-				Exit
-			EndIf
-
-			Local lockedrect:D3DLOCKED_RECT=New D3DLOCKED_RECT
-			If dstsurf.LockRect( lockedrect,Null,0 )<0
-				d3derr "dstsurf.LockRect failed~n"
-			EndIf
-		
-			For Local y:Int=0 Until pixmap.height
-				Local src:Byte Ptr=pixmap.pixels+y*pixmap.pitch
-				Local dst:Byte Ptr=lockedrect.pBits+y*lockedrect.Pitch
-				MemCopy dst,src,Size_T(pixmap.width*4)
-			Next
-		
-			dstsurf.UnlockRect
-			dstsurf.Release_
-			
-			If (flags & MIPMAPPEDIMAGE)=0 Exit
-
-			level:+1
-
-			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 )
-			EndIf
-		Forever
-		
-		_uscale=1.0/pow2width
-		_vscale=1.0/pow2height
-
-		Local u0#,u1#=width * _uscale
-		Local v0#,v1#=height * _vscale
-
-		_fverts[4]=u0
-		_fverts[5]=v0
-		_fverts[10]=u1
-		_fverts[11]=v0
-		_fverts[16]=u1
-		_fverts[17]=v1
-		_fverts[22]=u0
-		_fverts[23]=v1
-		
-		If flags & FILTEREDIMAGE
-			_magfilter=D3DTFG_LINEAR
-			_minfilter=D3DTFG_LINEAR
-			_mipfilter=D3DTFG_LINEAR
-		Else
-			_magfilter=D3DTFG_POINT
-			_minfilter=D3DTFG_POINT
-			_mipfilter=D3DTFG_POINT
-		EndIf
-		
-		_seq=GraphicsSeq
-		
-		Return Self
-	End Method
-	
-	Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
-		Local u0#=sx * _uscale
-		Local v0#=sy * _vscale
-		Local u1#=(sx+sw) * _uscale
-		Local v1#=(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
-		EndIf
-		
-		If Not _texture_enabled
-			_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
-	End Method
-	
-	Field _texture:IDirect3DTexture9,_seq:Int
-	
-	Field _magfilter:Int,_minfilter:Int,_mipfilter:Int,_uscale#,_vscale#
-	
-	Field _fverts#[24],_iverts:Int Ptr=Int Ptr( Varptr _fverts[0] )
-
-End Type
-
-Type TD3D9SDLMax2DDriver Extends TMax2dDriver
-
-	Method ToString$() Override
-		Return "DirectX9"
-	End Method
-
-	Method Create:TD3D9SDLMax2DDriver()
-
-		If Not D3D9SDLGraphicsDriver() Return Null
-
-		Local d3d:IDirect3D9=D3D9SDLGraphicsDriver().GetDirect3D()
-
-		If d3d.CheckDeviceFormat( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,0,D3DRTYPE_TEXTURE,D3DFMT_A8R8G8B8 )<0
-			Return Null
-		EndIf
-
-		Return Self
-	End Method
-
-	'***** TGraphicsDriver *****
-	Method GraphicsModes:TGraphicsMode[]() Override
-		Return D3D9SDLGraphicsDriver().GraphicsModes()
-	End Method
-	
-	Method AttachGraphics:TGraphics( widget:Byte Ptr,flags:Long ) Override
-		Local g:TD3D9SDLGraphics=D3D9SDLGraphicsDriver().AttachGraphics( widget,flags )
-		If g Return TMax2DGraphics.Create( g,Self )
-	End Method
-	
-	Method CreateGraphics:TGraphics( width:Int,height:Int,depth:Int,hertz:Int,flags:Long,x:Int,y:Int ) Override
-		Local g:TD3D9SDLGraphics=D3D9SDLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
-		If Not g Return Null
-		Return TMax2DGraphics.Create( g,Self )
-	End Method
-	
-	Method SetGraphics( g:TGraphics ) Override
-
-		If Not g
-			If _d3dDev
-				_d3dDev.EndScene
-				_d3dDev=Null
-			EndIf
-			_d3d9graphics=Null
-			_max2dGraphics=Null
-			TMax2DGraphics.ClearCurrent
-			D3D9SDLGraphicsDriver().SetGraphics Null
-			Return
-		EndIf
-
-		_max2dGraphics=TMax2dGraphics( g )
-
-		_d3d9graphics=TD3D9SDLGraphics( _max2dGraphics._graphics )
-
-		If Not _max2dGraphics Or Not _d3d9graphics Then
-			Throw "SetGraphics failed for D3D9"
-		End If
-
-		_d3dDev=_d3d9Graphics.GetDirect3DDevice()
-		
-		D3D9SDLGraphicsDriver().SetGraphics _d3d9Graphics
-
-		If _d3dDev.TestCooperativeLevel()<>D3D_OK Return
-		
-		ResetDevice
-
-		_max2dGraphics.MakeCurrent
-		
-	End Method
-	
-	Method Flip:Int( sync:Int ) Override
-		_d3dDev.EndScene
-		If D3D9SDLGraphicsDriver().Flip( sync )
-			_d3dDev.BeginScene
-		Else If _d3dDev.TestCooperativeLevel()=D3D_OK
-			ResetDevice
-			_max2dGraphics.MakeCurrent
-		EndIf
-
-	End Method
-	
-	Method ResetDevice()
-		_d3d9graphics.ValidateSize
-		_d3d9graphics.GetSettings _gw,_gh,_gd,_gr,_gf,_gx,_gy
-	
-		Local viewport:D3DVIEWPORT9
-		viewport.X = 0
-		viewport.Y = 0
-		viewport.Width = _gw
-		viewport.Height = _gh
-		viewport.MinZ = 0.0
-		viewport.MaxZ = 1.0
-		_d3dDev.SetViewport viewport
-
-		_d3dDev.SetRenderState D3DRS_ALPHAREF,$80
-		_d3dDev.SetRenderState D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL
-
-		_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
-		_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,False
-		_active_blend=SOLIDBLEND
-		
-		_d3dDev.SetRenderState D3DRS_LIGHTING,False
-		_d3dDev.SetRenderState D3DRS_CULLMODE,D3DCULL_NONE	
-		
-		_d3dDev.SetTexture 0,nullBaseTexture9
-		_bound_texture=Null
-
-		_d3dDev.SetFVF D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1
-		
-		_d3dDev.SetTextureStageState 0,D3DTSS_COLORARG1,D3DTA_TEXTURE		
-		_d3dDev.SetTextureStageState 0,D3DTSS_COLORARG2,D3DTA_DIFFUSE		
-		_d3dDev.SetTextureStageState 0,D3DTSS_COLOROP,D3DTOP_SELECTARG2
-		_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE
-		_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE
-		_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG2
-		_texture_enabled=False
-		
-		_d3dDev.SetTextureStageState 0,D3DTSS_ADDRESS,D3DTADDRESS_CLAMP
-	
-		_d3dDev.SetTextureStageState 0,D3DTSS_MAGFILTER,D3DTFG_POINT
-		_d3dDev.SetTextureStageState 0,D3DTSS_MINFILTER,D3DTFN_POINT
-		_d3dDev.SetTextureStageState 0,D3DTSS_MIPFILTER,D3DTFP_POINT
-		
-		_d3dDev.BeginScene
-
-	End Method
-
-	'***** TMax2DDriver *****
-	Method CreateFrameFromPixmap:TImageFrame( pixmap:TPixmap,flags:Int ) Override
-		Return New TD3D9ImageFrame.Create( pixmap,flags )
-	End Method
-	
-	Method SetBlend( blend:Int ) Override
-		If blend=_active_blend Return
-		Select blend
-		Case SOLIDBLEND
-			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
-			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,False
-		Case MASKBLEND
-			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,True
-			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,False
-		Case ALPHABLEND
-			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
-			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True
-			_d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
-			_d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA
-		Case LIGHTBLEND
-			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
-			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True
-			_d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
-			_d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_ONE
-		Case SHADEBLEND		
-			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
-			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True
-			_d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_ZERO
-			_d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR
-		End Select
-		_active_blend=blend
-	End Method
-	
-	Method SetAlpha( alpha# ) Override
-		alpha=Max(Min(alpha,1),0)
-		_color=(Int(255*alpha) Shl 24)|(_color&$ffffff)
-		_iverts[3]=_color
-		_iverts[9]=_color
-		_iverts[15]=_color
-		_iverts[21]=_color
-	End Method
-	
-	Method SetColor( 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)
-		_color=(_color&$ff000000)|(red Shl 16)|(green Shl 8)|blue		
-		_iverts[3]=_color
-		_iverts[9]=_color
-		_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()
-	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
-	End Method
-	
-	Method SetTransform( xx#,xy#,yx#,yy# ) Override
-		_ix=xx
-		_iy=xy
-		_jx=yx
-		_jy=yy		
-	End Method
-	
-	Method SetLineWidth( width# ) Override
-		_lineWidth=width
-	End Method
-	
-	Method Cls() Override
-		_d3dDev.Clear 0,Null,D3DCLEAR_TARGET,_clscolor,0,0
-	End Method
-	
-	Method Plot( x#,y# ) Override
-		_fverts[0]=x+.5
-		_fverts[1]=y+.5
-		DisableTex
-		_d3dDev.DrawPrimitiveUP D3DPT_POINTLIST,1,_fverts,24
-	End Method
-	
-	Method DrawLine( x0#,y0#,x1#,y1#,tx#,ty# ) Override
-		Local lx0# = x0*_ix + y0*_iy + tx
-		Local ly0# = x0*_jx + y0*_jy + ty
-		Local lx1# = x1*_ix + y1*_iy + tx
-		Local ly1# = x1*_jx + y1*_jy + ty
-		If _lineWidth<=1
-			_fverts[0]=lx0+.5
-			_fverts[1]=ly0+.5
-			_fverts[6]=lx1+.5
-			_fverts[7]=ly1+.5
-			DisableTex
-			_d3dDev.DrawPrimitiveUP D3DPT_LINELIST,1,_fverts,24
-			Return
-		EndIf
-		Local lw#=_lineWidth*.5
-		If Abs(ly1-ly0)>Abs(lx1-lx0)
-			_fverts[0]=lx0-lw
-			_fverts[1]=ly0
-			_fverts[6]=lx0+lw
-			_fverts[7]=ly0
-			_fverts[12]=lx1-lw
-			_fverts[13]=ly1
-			_fverts[18]=lx1+lw
-			_fverts[19]=ly1
-		Else
-			_fverts[0]=lx0
-			_fverts[1]=ly0-lw
-			_fverts[6]=lx0
-			_fverts[7]=ly0+lw
-			_fverts[12]=lx1
-			_fverts[13]=ly1-lw
-			_fverts[18]=lx1
-			_fverts[19]=ly1+lw
-		EndIf
-		DisableTex
-		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLESTRIP,2,_fverts,24
-	End Method
-	
-	Method DrawRect( x0#,y0#,x1#,y1#,tx#,ty# ) Override
-		_fverts[0]  = x0*_ix + y0*_iy + tx
-		_fverts[1]  = x0*_jx + y0*_jy + ty
-		_fverts[6]  = x1*_ix + y0*_iy + tx
-		_fverts[7]  = x1*_jx + y0*_jy + ty
-		_fverts[12] = x0*_ix + y1*_iy + tx
-		_fverts[13] = x0*_jx + y1*_jy + ty
-		_fverts[18] = x1*_ix + y1*_iy + tx
-		_fverts[19] = x1*_jx + y1*_jy + ty
-		DisableTex
-		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLESTRIP,2,_fverts,24
-	End Method
-	
-	Method DrawOval( x0#,y0#,x1#,y1#,tx#,ty# ) Override
-		Local xr#=(x1-x0)*.5
-		Local yr#=(y1-y0)*.5
-		Local segs:Int=Abs(xr)+Abs(yr)
-		segs=Max(segs,12)&~3
-		x0:+xr
-		y0:+yr
-		Local fverts#[segs*6]
-		Local iverts:Int Ptr=Int Ptr( Varptr fverts[0] )
-		For Local i:Int=0 Until segs
-			Local th#=-i*360#/segs
-			Local x#=x0+Cos(th)*xr
-			Local y#=y0-Sin(th)*yr
-			fverts[i*6+0]=x*_ix+y*_iy+tx
-			fverts[i*6+1]=x*_jx+y*_jy+ty			
-			iverts[i*6+3]=_color
-		Next
-		DisableTex
-		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLEFAN,segs-2,fverts,24
-	End Method
-	
-	Method DrawPoly( verts#[],handlex#,handley#,tx#,ty# ) Override
-		If verts.length<6 Or (verts.length&1) Return
-		Local segs:Int=verts.length/2
-		Local fverts#[segs*6]
-		Local iverts:Int Ptr=Int Ptr( Varptr fverts[0] )
-		For Local i:Int=0 Until segs
-			Local x#=verts[i*2+0]+handlex
-			Local y#=verts[i*2+1]+handley
-			fverts[i*6+0]= x*_ix + y*_iy + tx
-			fverts[i*6+1]= x*_jx + y*_jy + ty
-			iverts[i*6+3]=_color
-		Next
-		DisableTex
-		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLEFAN,segs-2,fverts,24
-	End Method
-		
-	'GetDC/BitBlt MUCH faster than locking backbuffer!	
-	Method DrawPixmap( pixmap:TPixmap,x:Int,y:Int ) Override
-		Local width:Int=pixmap.width,height:Int=pixmap.height
-	
-		Local dstsurf:IDirect3DSurface9' = New IDirect3DSurface9
-		If _d3dDev.GetRenderTarget( 0,dstsurf )<0
-			d3derr "GetRenderTarget failed~n"
-			Return
-		EndIf
-		
-		Local desc:D3DSURFACE_DESC
-		If dstsurf.GetDesc( desc )<0
-			d3derr "GetDesc failed~n"
-		EndIf
-		
-		Local rect:Int[]=[x,y,x+width,y+height]
-		Local lockedrect:D3DLOCKED_RECT=New D3DLOCKED_RECT
-		If dstsurf.LockRect( lockedrect,rect,0 )<0
-			d3derr "Unable to lock render target surface~n"
-			dstsurf.Release_
-			Return
-		EndIf
-		
-		Local dstpixmap:TPixmap=CreateStaticPixmap( lockedrect.pBits,width,height,lockedrect.Pitch,PF_BGRA8888 );
-		
-		dstpixmap.Paste pixmap,0,0
-		
-		dstsurf.UnlockRect
-		dstsurf.Release_
-	End Method
-
-	'GetDC/BitBlt MUCH faster than locking backbuffer!	
-	Method GrabPixmap:TPixmap( x:Int,y:Int,width:Int,height:Int ) Override
-	
-		Local srcsurf:IDirect3DSurface9
-		If _d3dDev.GetRenderTarget( 0,srcsurf )<0
-			d3derr "GetRenderTarget failed~n"
-		EndIf
-
-		Local dstsurf:IDirect3DSurface9
-		If _d3dDev.CreateOffscreenPlainSurface( width,height,D3DFMT_X8R8G8B8,D3DPOOL_SYSTEMMEM,dstsurf,Null )<0
-			d3derr "CreateOffscreenPlainSurface failed~n"
-		EndIf
-		
-		Local srcdc:Byte Ptr
-		If srcsurf.GetDC( srcdc )<0
-			d3derr "srcsurf.GetDC failed~n"
-		EndIf
-		
-		Local dstdc:Byte Ptr
-		If dstsurf.GetDC( dstdc )<0
-			d3derr "dstsurf.GetDC failed~n"
-		EndIf
-		
-		BitBlt dstdc,0,0,width,height,srcdc,x,y,ROP_SRCCOPY
-		
-		srcsurf.ReleaseDC srcdc
-		dstsurf.ReleaseDC dstdc
-		
-		Local lockedrect:D3DLOCKED_RECT=New D3DLOCKED_RECT
-		If dstsurf.LockRect( lockedrect,Null,D3DLOCK_READONLY )<0
-			d3derr "dstsurf.LockRect failed~n"
-		EndIf
-		
-		Local pixmap:TPixmap=CreatePixmap( width,height,PF_BGRA8888 )
-		
-		'Copy and set alpha in the process...
-		For Local y:Int=0 Until height
-			Local src:Int Ptr=Int Ptr( lockedrect.pBits+y*lockedrect.Pitch )
-			Local dst:Int Ptr=Int Ptr( pixmap.PixelPtr( 0,y ) )
-			For Local x:Int=0 Until width
-				dst[x]=src[x] | $ff000000
-			Next
-		Next
-		
-		srcsurf.Release_
-		dstsurf.Release_
-		
-		Return pixmap
-	End Method
-	
-	Method SetResolution( width#,height# ) Override
-		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
-	End Method
-	
-End Type
-
-Rem
-bbdoc: Get Direct3D9 SDL Max2D Driver
-about:
-The returned driver can be used with #SetGraphicsDriver to enable Direct3D9 Max2D rendering.
-End Rem
-Function D3D9SDLMax2DDriver:TD3D9SDLMax2DDriver()
-	Global _done:Int
-	If Not _done
-		_driver=New TD3D9SDLMax2DDriver.Create()
-		_done=True
-	EndIf
-	Return _driver
-End Function
-
-Local driver:TD3D9SDLMax2DDriver=D3D9SDLMax2DDriver()
-If driver SetGraphicsDriver driver
-
-?
+
+SuperStrict
+
+Rem
+bbdoc: Direct3D9 Max2D with SDL backend
+about:
+The Direct3D9 Max2D module provides a Direct3D9 driver for #Max2D.
+End Rem
+Module SDL.D3D9SDLMax2D
+
+ModuleInfo "Version: 1.01"
+ModuleInfo "License: zlib/libpng"
+ModuleInfo "Copyright: Blitz Research Ltd, Bruce A Henderson"
+
+ModuleInfo "History: 1.01"
+ModuleInfo "History: Changed to SuperStrict"
+ModuleInfo "History: Extended flags to Long"
+ModuleInfo "History: 1.00"
+ModuleInfo "History: Port to bmx-ng."
+
+?win32
+
+Import BRL.Max2D
+Import SDL.D3D9SDLGraphics
+
+Const LOG_ERRS:Int=True'False
+
+Private
+
+Global _gw:Int,_gh:Int,_gd:Int,_gr:Int,_gf:Long,_gx:Int,_gy:Int
+Global _color:Int
+Global _clscolor:Int
+Global _ix#,_iy#,_jx#,_jy#
+Global _fverts#[24]
+Global _iverts:Int Ptr=Int Ptr( Varptr _fverts[0] )
+Global _lineWidth#
+
+Global _bound_texture:IDirect3DTexture9
+Global _texture_enabled:Int
+
+Global _active_blend:Int
+
+Global _driver:TD3D9SDLMax2DDriver
+Global _d3dDev:IDirect3DDevice9
+Global _d3d9Graphics:TD3D9SDLGraphics
+Global _max2dGraphics:TMax2dGraphics
+
+Function Pow2Size:Int( n:Int )
+	Local t:Int=1
+	While t<n
+		t:*2
+	Wend
+	Return t
+End Function
+
+Function DisableTex()
+	If Not _texture_enabled Return
+	_d3dDev.SetTextureStageState 0,D3DTSS_COLOROP,D3DTOP_SELECTARG2
+	_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG2
+	_texture_enabled=False
+End Function
+
+Function d3derr( str$ )
+	If LOG_ERRS WriteStdout "D3DERR: "+str+"~n"
+End Function
+
+Public
+
+Type TD3D9ImageFrame Extends TImageFrame
+
+	Method Delete()
+		If _texture
+			If _seq=GraphicsSeq
+				If _texture=_bound_texture
+					_d3dDev.SetTexture 0,nullBaseTexture9
+					_bound_texture=Null
+				EndIf
+				_d3d9Graphics.ReleaseNow _texture
+			EndIf
+			_texture=Null
+		EndIf
+	End Method
+
+	Method Create:TD3D9ImageFrame( pixmap:TPixmap,flags:Int )
+
+		Local width:Int=pixmap.width,pow2width:Int=Pow2Size( width )
+		Local height:Int=pixmap.height,pow2height:Int=Pow2Size( height )
+		
+		If width<pow2width Or height<pow2height
+			Local src:TPixmap=pixmap
+			pixmap=TPixmap.Create( pow2width,pow2height,PF_BGRA8888 )
+			pixmap.Paste src,0,0
+			If width<pow2width
+				pixmap.Paste pixmap.Window( width-1,0,1,height ),width,0
+			EndIf
+			If height<pow2height
+				pixmap.Paste pixmap.Window( 0,height-1,width,1 ),0,height
+				If width<pow2width 
+					pixmap.Paste pixmap.Window( width-1,height-1,1,1 ),width,height
+				EndIf
+			EndIf
+		Else
+			If pixmap.Format<>PF_BGRA8888 pixmap=pixmap.Convert( PF_BGRA8888 )
+		EndIf
+
+		Local levels:Int=(flags & MIPMAPPEDIMAGE)=0
+		Local format:Int=D3DFMT_A8R8G8B8
+		Local usage:Int=0
+		Local pool:Int=D3DPOOL_MANAGED
+		
+		'_texture = New IDirect3DTexture9
+		If _d3dDev.CreateTexture( pow2width,pow2height,levels,usage,format,pool,_texture,Null )<0
+			d3derr "Unable to create texture~n"
+			_texture = Null
+			Return Null
+		EndIf
+		
+		_d3d9Graphics.AutoRelease _texture
+
+		Local level:Int
+		Local dstsurf:IDirect3DSurface9' = New IDirect3DSurface9
+		Repeat
+			If _texture.GetSurfaceLevel( level,dstsurf )<0
+				If level=0
+					d3derr "_texture.GetSurfaceLevel failed~n"
+				EndIf
+				Exit
+			EndIf
+
+			Local lockedrect:D3DLOCKED_RECT=New D3DLOCKED_RECT
+			If dstsurf.LockRect( lockedrect,Null,0 )<0
+				d3derr "dstsurf.LockRect failed~n"
+			EndIf
+		
+			For Local y:Int=0 Until pixmap.height
+				Local src:Byte Ptr=pixmap.pixels+y*pixmap.pitch
+				Local dst:Byte Ptr=lockedrect.pBits+y*lockedrect.Pitch
+				MemCopy dst,src,Size_T(pixmap.width*4)
+			Next
+		
+			dstsurf.UnlockRect
+			dstsurf.Release_
+			
+			If (flags & MIPMAPPEDIMAGE)=0 Exit
+
+			level:+1
+
+			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 )
+			EndIf
+		Forever
+		
+		_uscale=1.0/pow2width
+		_vscale=1.0/pow2height
+
+		Local u0#,u1#=width * _uscale
+		Local v0#,v1#=height * _vscale
+
+		_fverts[4]=u0
+		_fverts[5]=v0
+		_fverts[10]=u1
+		_fverts[11]=v0
+		_fverts[16]=u1
+		_fverts[17]=v1
+		_fverts[22]=u0
+		_fverts[23]=v1
+		
+		If flags & FILTEREDIMAGE
+			_magfilter=D3DTFG_LINEAR
+			_minfilter=D3DTFG_LINEAR
+			_mipfilter=D3DTFG_LINEAR
+		Else
+			_magfilter=D3DTFG_POINT
+			_minfilter=D3DTFG_POINT
+			_mipfilter=D3DTFG_POINT
+		EndIf
+		
+		_seq=GraphicsSeq
+		
+		Return Self
+	End Method
+	
+	Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
+		Local u0#=sx * _uscale
+		Local v0#=sy * _vscale
+		Local u1#=(sx+sw) * _uscale
+		Local v1#=(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
+		EndIf
+		
+		If Not _texture_enabled
+			_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
+	End Method
+	
+	Field _texture:IDirect3DTexture9,_seq:Int
+	
+	Field _magfilter:Int,_minfilter:Int,_mipfilter:Int,_uscale#,_vscale#
+	
+	Field _fverts#[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
+
+	Method Delete()
+		ReleaseNow()
+	EndMethod
+	
+	Method ReleaseNow()
+		If _surface
+			_surface.Release_
+			_surface = Null
+		EndIf
+		If _texture
+			_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
+		
+		_magfilter = D3DTFG_LINEAR
+		_minfilter = D3DTFG_LINEAR
+		_mipfilter = D3DTFG_LINEAR
+
+		_uscale = 1.0 / width
+		_vscale = 1.0 / height
+
+		Return Self
+	EndMethod
+	
+	Method DestroyRenderImage()
+		ReleaseNow()
+	EndMethod
+
+	Method OnDeviceLost(d3ddev:IDirect3DDevice9, width:Int, height:Int)
+		_persistpixmap = ToPixmap(d3ddev, width, height)
+		ReleaseNow()
+	EndMethod
+
+	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)
+			EndIf
+
+			FromPixmap(d3ddev, _persistpixmap)
+		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 lockedrect:D3DLOCKED_RECT = New D3DLOCKED_RECT
+		stage.LockRect(lockedrect, Null, 0)
+
+		' copy the pixel data across
+		For Local y:Int = 0 Until pixmap.height
+			Local srcptr:Byte Ptr = pixmap.pixels + y * pixmap.pitch
+			Local dstptr:Byte Ptr = lockedrect.pBits + y * lockedrect.Pitch
+			MemCopy dstptr, srcptr, pixmap.width * 4
+		Next
+		stage.UnlockRect()
+
+		' copy from the staging surface to the render surface
+		d3ddev.UpdateSurface(stage, Null, _surface, Null)
+
+		' cleanup
+		stage.release_
+	EndMethod
+	
+	Method ToPixmap:TPixmap(d3ddev:IDirect3DDevice9, width:Int, height:Int)
+		Local pixmap:TPixmap = CreatePixmap(width, height, PF_RGBA8888)
+
+		' 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
+		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"
+
+		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)
+				Local dstptr:Int Ptr = Int Ptr (pixmap.pixels + x * 4 + y * pixmap.pitch)
+				dstptr[0] = ((srcptr[0] & $ff) Shl 16) | ((srcptr[0] & $ff0000) Shr 16)| (srcptr[0] & $ff00) | (srcptr[0] & $ff000000)
+			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
+		
+		' 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)
+	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[] = [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
+
+
+Type TD3D9SDLMax2DDriver Extends TMax2dDriver
+
+	Method ToString$() Override
+		Return "DirectX9"
+	End Method
+
+	Method Create:TD3D9SDLMax2DDriver()
+
+		If Not D3D9SDLGraphicsDriver() Return Null
+
+		Local d3d:IDirect3D9=D3D9SDLGraphicsDriver().GetDirect3D()
+
+		If d3d.CheckDeviceFormat( D3DADAPTER_DEFAULT,D3DDEVTYPE_HAL,D3DFMT_X8R8G8B8,0,D3DRTYPE_TEXTURE,D3DFMT_A8R8G8B8 )<0
+			Return Null
+		EndIf
+
+		Return Self
+	End Method
+
+	'***** TGraphicsDriver *****
+	Method GraphicsModes:TGraphicsMode[]() Override
+		Return D3D9SDLGraphicsDriver().GraphicsModes()
+	End Method
+	
+	Method AttachGraphics:TGraphics( widget:Byte Ptr,flags:Long ) Override
+		Local g:TD3D9SDLGraphics=D3D9SDLGraphicsDriver().AttachGraphics( widget,flags )
+		If g Return TMax2DGraphics.Create( g,Self )
+	End Method
+	
+	Method CreateGraphics:TGraphics( width:Int,height:Int,depth:Int,hertz:Int,flags:Long,x:Int,y:Int ) Override
+		Local g:TD3D9SDLGraphics=D3D9SDLGraphicsDriver().CreateGraphics( width,height,depth,hertz,flags,x,y )
+		If Not g Return Null
+		Return TMax2DGraphics.Create( g,Self )
+	End Method
+	
+	Method SetGraphics( g:TGraphics ) Override
+
+		If Not g
+			If _d3dDev
+				_d3dDev.EndScene
+				_d3dDev=Null
+			EndIf
+			_d3d9graphics=Null
+			_max2dGraphics=Null
+			TMax2DGraphics.ClearCurrent
+			D3D9SDLGraphicsDriver().SetGraphics Null
+			Return
+		EndIf
+
+		_max2dGraphics=TMax2dGraphics( g )
+
+		_d3d9graphics=TD3D9SDLGraphics( _max2dGraphics._graphics )
+
+		If Not _max2dGraphics Or Not _d3d9graphics Then
+			Throw "SetGraphics failed for D3D9"
+		End If
+
+		_d3dDev=_d3d9Graphics.GetDirect3DDevice()
+		
+		D3D9SDLGraphicsDriver().SetGraphics _d3d9Graphics
+
+		If _d3dDev.TestCooperativeLevel()<>D3D_OK Return
+		
+		ResetDevice
+
+		_max2dGraphics.MakeCurrent
+		
+	End Method
+	
+	Method Flip:Int( sync:Int ) Override
+		_d3dDev.EndScene
+		If D3D9SDLGraphicsDriver().Flip( sync )
+			_d3dDev.BeginScene
+		Else If _d3dDev.TestCooperativeLevel()=D3D_OK
+			ResetDevice
+			_max2dGraphics.MakeCurrent
+		EndIf
+
+	End Method
+	
+	Method ResetDevice()
+		_d3d9graphics.ValidateSize
+		_d3d9graphics.GetSettings _gw,_gh,_gd,_gr,_gf,_gx,_gy
+	
+		Local viewport:D3DVIEWPORT9
+		viewport.X = 0
+		viewport.Y = 0
+		viewport.Width = _gw
+		viewport.Height = _gh
+		viewport.MinZ = 0.0
+		viewport.MaxZ = 1.0
+		_d3dDev.SetViewport viewport
+
+		_d3dDev.SetRenderState D3DRS_ALPHAREF,$80
+		_d3dDev.SetRenderState D3DRS_ALPHAFUNC,D3DCMP_GREATEREQUAL
+
+		_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
+		_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,False
+		_active_blend=SOLIDBLEND
+		
+		_d3dDev.SetRenderState D3DRS_LIGHTING,False
+		_d3dDev.SetRenderState D3DRS_CULLMODE,D3DCULL_NONE	
+		
+		_d3dDev.SetTexture 0,nullBaseTexture9
+		_bound_texture=Null
+
+		_d3dDev.SetFVF D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1
+		
+		_d3dDev.SetTextureStageState 0,D3DTSS_COLORARG1,D3DTA_TEXTURE		
+		_d3dDev.SetTextureStageState 0,D3DTSS_COLORARG2,D3DTA_DIFFUSE		
+		_d3dDev.SetTextureStageState 0,D3DTSS_COLOROP,D3DTOP_SELECTARG2
+		_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAARG1,D3DTA_TEXTURE
+		_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAARG2,D3DTA_DIFFUSE
+		_d3dDev.SetTextureStageState 0,D3DTSS_ALPHAOP,D3DTOP_SELECTARG2
+		_texture_enabled=False
+		
+		_d3dDev.SetTextureStageState 0,D3DTSS_ADDRESS,D3DTADDRESS_CLAMP
+	
+		_d3dDev.SetTextureStageState 0,D3DTSS_MAGFILTER,D3DTFG_POINT
+		_d3dDev.SetTextureStageState 0,D3DTSS_MINFILTER,D3DTFN_POINT
+		_d3dDev.SetTextureStageState 0,D3DTSS_MIPFILTER,D3DTFP_POINT
+		
+		_d3dDev.BeginScene
+
+	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
+	
+	Method SetBlend( blend:Int ) Override
+		If blend=_active_blend Return
+		Select blend
+		Case SOLIDBLEND
+			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
+			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,False
+		Case MASKBLEND
+			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,True
+			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,False
+		Case ALPHABLEND
+			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
+			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True
+			_d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
+			_d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA
+		Case LIGHTBLEND
+			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
+			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True
+			_d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_SRCALPHA
+			_d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_ONE
+		Case SHADEBLEND		
+			_d3dDev.SetRenderState D3DRS_ALPHATESTENABLE,False
+			_d3dDev.SetRenderState D3DRS_ALPHABLENDENABLE,True
+			_d3dDev.SetRenderState D3DRS_SRCBLEND,D3DBLEND_ZERO
+			_d3dDev.SetRenderState D3DRS_DESTBLEND,D3DBLEND_SRCCOLOR
+		End Select
+		_active_blend=blend
+	End Method
+	
+	Method SetAlpha( alpha# ) Override
+		alpha=Max(Min(alpha,1),0)
+		_color=(Int(255*alpha) Shl 24)|(_color&$ffffff)
+		_iverts[3]=_color
+		_iverts[9]=_color
+		_iverts[15]=_color
+		_iverts[21]=_color
+	End Method
+	
+	Method SetColor( 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)
+		_color=(_color&$ff000000)|(red Shl 16)|(green Shl 8)|blue		
+		_iverts[3]=_color
+		_iverts[9]=_color
+		_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()
+	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
+	End Method
+	
+	Method SetTransform( xx#,xy#,yx#,yy# ) Override
+		_ix=xx
+		_iy=xy
+		_jx=yx
+		_jy=yy		
+	End Method
+	
+	Method SetLineWidth( width# ) Override
+		_lineWidth=width
+	End Method
+	
+	Method Cls() Override
+		_d3dDev.Clear 0,Null,D3DCLEAR_TARGET,_clscolor,0,0
+	End Method
+	
+	Method Plot( x#,y# ) Override
+		_fverts[0]=x+.5
+		_fverts[1]=y+.5
+		DisableTex
+		_d3dDev.DrawPrimitiveUP D3DPT_POINTLIST,1,_fverts,24
+	End Method
+	
+	Method DrawLine( x0#,y0#,x1#,y1#,tx#,ty# ) Override
+		Local lx0# = x0*_ix + y0*_iy + tx
+		Local ly0# = x0*_jx + y0*_jy + ty
+		Local lx1# = x1*_ix + y1*_iy + tx
+		Local ly1# = x1*_jx + y1*_jy + ty
+		If _lineWidth<=1
+			_fverts[0]=lx0+.5
+			_fverts[1]=ly0+.5
+			_fverts[6]=lx1+.5
+			_fverts[7]=ly1+.5
+			DisableTex
+			_d3dDev.DrawPrimitiveUP D3DPT_LINELIST,1,_fverts,24
+			Return
+		EndIf
+		Local lw#=_lineWidth*.5
+		If Abs(ly1-ly0)>Abs(lx1-lx0)
+			_fverts[0]=lx0-lw
+			_fverts[1]=ly0
+			_fverts[6]=lx0+lw
+			_fverts[7]=ly0
+			_fverts[12]=lx1-lw
+			_fverts[13]=ly1
+			_fverts[18]=lx1+lw
+			_fverts[19]=ly1
+		Else
+			_fverts[0]=lx0
+			_fverts[1]=ly0-lw
+			_fverts[6]=lx0
+			_fverts[7]=ly0+lw
+			_fverts[12]=lx1
+			_fverts[13]=ly1-lw
+			_fverts[18]=lx1
+			_fverts[19]=ly1+lw
+		EndIf
+		DisableTex
+		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLESTRIP,2,_fverts,24
+	End Method
+	
+	Method DrawRect( x0#,y0#,x1#,y1#,tx#,ty# ) Override
+		_fverts[0]  = x0*_ix + y0*_iy + tx
+		_fverts[1]  = x0*_jx + y0*_jy + ty
+		_fverts[6]  = x1*_ix + y0*_iy + tx
+		_fverts[7]  = x1*_jx + y0*_jy + ty
+		_fverts[12] = x0*_ix + y1*_iy + tx
+		_fverts[13] = x0*_jx + y1*_jy + ty
+		_fverts[18] = x1*_ix + y1*_iy + tx
+		_fverts[19] = x1*_jx + y1*_jy + ty
+		DisableTex
+		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLESTRIP,2,_fverts,24
+	End Method
+	
+	Method DrawOval( x0#,y0#,x1#,y1#,tx#,ty# ) Override
+		Local xr#=(x1-x0)*.5
+		Local yr#=(y1-y0)*.5
+		Local segs:Int=Abs(xr)+Abs(yr)
+		segs=Max(segs,12)&~3
+		x0:+xr
+		y0:+yr
+		Local fverts#[segs*6]
+		Local iverts:Int Ptr=Int Ptr( Varptr fverts[0] )
+		For Local i:Int=0 Until segs
+			Local th#=-i*360#/segs
+			Local x#=x0+Cos(th)*xr
+			Local y#=y0-Sin(th)*yr
+			fverts[i*6+0]=x*_ix+y*_iy+tx
+			fverts[i*6+1]=x*_jx+y*_jy+ty			
+			iverts[i*6+3]=_color
+		Next
+		DisableTex
+		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLEFAN,segs-2,fverts,24
+	End Method
+	
+	Method DrawPoly( verts#[],handlex#,handley#,tx#,ty# ) Override
+		If verts.length<6 Or (verts.length&1) Return
+		Local segs:Int=verts.length/2
+		Local fverts#[segs*6]
+		Local iverts:Int Ptr=Int Ptr( Varptr fverts[0] )
+		For Local i:Int=0 Until segs
+			Local x#=verts[i*2+0]+handlex
+			Local y#=verts[i*2+1]+handley
+			fverts[i*6+0]= x*_ix + y*_iy + tx
+			fverts[i*6+1]= x*_jx + y*_jy + ty
+			iverts[i*6+3]=_color
+		Next
+		DisableTex
+		_d3dDev.DrawPrimitiveUP D3DPT_TRIANGLEFAN,segs-2,fverts,24
+	End Method
+		
+	'GetDC/BitBlt MUCH faster than locking backbuffer!	
+	Method DrawPixmap( pixmap:TPixmap,x:Int,y:Int ) Override
+		Local width:Int=pixmap.width,height:Int=pixmap.height
+	
+		Local dstsurf:IDirect3DSurface9' = New IDirect3DSurface9
+		If _d3dDev.GetRenderTarget( 0,dstsurf )<0
+			d3derr "GetRenderTarget failed~n"
+			Return
+		EndIf
+		
+		Local desc:D3DSURFACE_DESC
+		If dstsurf.GetDesc( desc )<0
+			d3derr "GetDesc failed~n"
+		EndIf
+		
+		Local rect:Int[]=[x,y,x+width,y+height]
+		Local lockedrect:D3DLOCKED_RECT=New D3DLOCKED_RECT
+		If dstsurf.LockRect( lockedrect,rect,0 )<0
+			d3derr "Unable to lock render target surface~n"
+			dstsurf.Release_
+			Return
+		EndIf
+		
+		Local dstpixmap:TPixmap=CreateStaticPixmap( lockedrect.pBits,width,height,lockedrect.Pitch,PF_BGRA8888 );
+		
+		dstpixmap.Paste pixmap,0,0
+		
+		dstsurf.UnlockRect
+		dstsurf.Release_
+	End Method
+
+	'GetDC/BitBlt MUCH faster than locking backbuffer!	
+	Method GrabPixmap:TPixmap( x:Int,y:Int,width:Int,height:Int ) Override
+	
+		Local srcsurf:IDirect3DSurface9
+		If _d3dDev.GetRenderTarget( 0,srcsurf )<0
+			d3derr "GetRenderTarget failed~n"
+		EndIf
+
+		Local dstsurf:IDirect3DSurface9
+		If _d3dDev.CreateOffscreenPlainSurface( width,height,D3DFMT_X8R8G8B8,D3DPOOL_SYSTEMMEM,dstsurf,Null )<0
+			d3derr "CreateOffscreenPlainSurface failed~n"
+		EndIf
+		
+		Local srcdc:Byte Ptr
+		If srcsurf.GetDC( srcdc )<0
+			d3derr "srcsurf.GetDC failed~n"
+		EndIf
+		
+		Local dstdc:Byte Ptr
+		If dstsurf.GetDC( dstdc )<0
+			d3derr "dstsurf.GetDC failed~n"
+		EndIf
+		
+		BitBlt dstdc,0,0,width,height,srcdc,x,y,ROP_SRCCOPY
+		
+		srcsurf.ReleaseDC srcdc
+		dstsurf.ReleaseDC dstdc
+		
+		Local lockedrect:D3DLOCKED_RECT=New D3DLOCKED_RECT
+		If dstsurf.LockRect( lockedrect,Null,D3DLOCK_READONLY )<0
+			d3derr "dstsurf.LockRect failed~n"
+		EndIf
+		
+		Local pixmap:TPixmap=CreatePixmap( width,height,PF_BGRA8888 )
+		
+		'Copy and set alpha in the process...
+		For Local y:Int=0 Until height
+			Local src:Int Ptr=Int Ptr( lockedrect.pBits+y*lockedrect.Pitch )
+			Local dst:Int Ptr=Int Ptr( pixmap.PixelPtr( 0,y ) )
+			For Local x:Int=0 Until width
+				dst[x]=src[x] | $ff000000
+			Next
+		Next
+		
+		srcsurf.Release_
+		dstsurf.Release_
+		
+		Return pixmap
+	End Method
+	
+	Method SetResolution( width#,height# ) Override
+		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
+	End Method
+	
+End Type
+
+Rem
+bbdoc: Get Direct3D9 SDL Max2D Driver
+about:
+The returned driver can be used with #SetGraphicsDriver to enable Direct3D9 Max2D rendering.
+End Rem
+Function D3D9SDLMax2DDriver:TD3D9SDLMax2DDriver()
+	Global _done:Int
+	If Not _done
+		_driver=New TD3D9SDLMax2DDriver.Create()
+		_done=True
+	EndIf
+	Return _driver
+End Function
+
+Local driver:TD3D9SDLMax2DDriver=D3D9SDLMax2DDriver()
+If driver SetGraphicsDriver driver
+
+?

+ 250 - 2
gl2sdlmax2d.mod/main.bmx

@@ -291,6 +291,251 @@ 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
+	
+	Field _matrix:TMatrix
+
+	Method Delete()
+		Destroy()
+	EndMethod
+
+	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
+		
+		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
+	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)
+		
+			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)
+		
+		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()
+		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 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)
+		
+		frames = New TGL2SDLRenderImageFrame[1]
+		frames[0] = New TGL2SDLRenderImageFrame.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 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)
+	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
+
+
 Public
 
 '============================================================================================'
@@ -817,14 +1062,17 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 
 	End Method
 
+	Method CreateRenderImageContext:Object(g:TGraphics) Override
+		Return new TGL2SDLRenderImageContext.Create(g, self)
+	End Method
+	
 	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap, flags:Int ) Override
-
 		Local frame:TGLImageFrame
 		frame = TGLImageFrame.CreateFromPixmap( pixmap, flags )
 		Return frame
 
 	End Method
-
+	
 	Method SetBlend( blend:Int ) Override
 
 		If state_blend = blend Return

+ 243 - 0
glsdlmax2d.mod/glsdlmax2d.bmx

@@ -199,6 +199,244 @@ Function AdjustTexSize( width:Int Var,height:Int Var )
 	Forever
 End Function
 
+
+
+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
+
+	Method Create:TGLRenderimageContext(gc:TGraphics, driver:TGraphicsDriver)
+		If Not glewIsInit
+			glewInit()
+			glewIsInit = True
+		EndIf
+
+		_renderimages = New TList
+		_gc = TSDLGraphics(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
+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)		
+
+		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
+			' 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
+
 Public
 
 Type TGLImageFrame Extends TImageFrame
@@ -352,6 +590,11 @@ Type TGLMax2DDriver Extends TMax2DDriver
 		Return "OpenGL"
 	End Method
 
+	
+	Method CreateRenderImageContext:Object(g:TGraphics) Override
+		Return new TGLRenderImageContext.Create(g, self)
+	End Method
+
 	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap,flags:Int ) Override
 		Local frame:TGLImageFrame
 		frame=TGLImageFrame.CreateFromPixmap( pixmap,flags )