2
0
Ronny Otto 2 жил өмнө
parent
commit
f874fad0d7

+ 1 - 1
d3d9sdlmax2d.mod/d3d9sdlmax2d.bmx

@@ -398,7 +398,7 @@ Type TD3D9RenderImageFrame Extends TD3D9ImageFrame
 	Method Clear(d3ddev:IDirect3DDevice9, r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
 	Method Clear(d3ddev:IDirect3DDevice9, r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
 		If Not d3ddev Return
 		If Not d3ddev Return
 
 
-		Local c:Int = (int(a*255) Shl 24) | (r Shl 16) | (g Shl 8) | b
+		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)
 		d3ddev.Clear(0, Null, D3DCLEAR_TARGET, c, 0.0, 0)
 	End Method
 	End Method
 	
 	

+ 3 - 1
gl2sdlmax2d.mod/gl2sdlmax2d.bmx

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

+ 209 - 288
gl2sdlmax2d.mod/main.bmx

@@ -2,7 +2,7 @@ SuperStrict
 
 
 Import brl.Max2D
 Import brl.Max2D
 Import SDL.SDLGraphics
 Import SDL.SDLGraphics
-Import brl.StandardIO
+Import brl.Threads
 ?Not opengles
 ?Not opengles
 Import pub.glew
 Import pub.glew
 Import Pub.OpenGL
 Import Pub.OpenGL
@@ -12,8 +12,23 @@ Import Pub.OpenGLES
 
 
 Private
 Private
 
 
+Struct Rect
+	Method New (X:Int, Y:Int, width:Int, height:Int)
+		Self.X = X
+		Self.Y = Y
+		Self.width = width
+		Self.height = height
+	EndMethod
+	
+	Field X:Int, Y:Int
+	Field width:Int, height:Int
+EndStruct
+
 'Const GLMAX2D_USE_LEGACY = False
 'Const GLMAX2D_USE_LEGACY = False
 Global _driver:TGL2Max2DDriver
 Global _driver:TGL2Max2DDriver
+Global _BackbufferRenderImageFrame:TGL2SDLRenderImageFrame
+Global _CurrentRenderImageFrame:TGL2SDLRenderImageFrame
+Global _GLScissor_BMaxViewport:Rect = New Rect
 
 
 'Naughty!
 'Naughty!
 Const GL_BGR:Int = $80E0
 Const GL_BGR:Int = $80E0
@@ -56,45 +71,32 @@ Function Pow2Size:Int( n:Int )
 	Return t
 	Return t
 End Function
 End Function
 
 
-Global dead_texs:Int[],n_dead_texs:Int,dead_tex_seq:Int,n_live_texs:Int
-
-Extern
-	Function bbAtomicAdd:Int( target:Int Ptr,value:Int )="int bbAtomicAdd( int *,int )!"
-End Extern
+Global dead_texs:TDynamicArray = New TDynamicArray(32)
+Global dead_tex_seq:Int
 
 
 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
 Function DeleteTex( name:Int,seq:Int )
 Function DeleteTex( name:Int,seq:Int )
 	If seq<>dead_tex_seq Return
 	If seq<>dead_tex_seq Return
 	
 	
-	Local n:Int = bbAtomicAdd(Varptr n_dead_texs, 1)
-	bbAtomicAdd(Varptr n_live_texs, -1)
-
-	dead_texs[n] = name
+	dead_texs.AddLast(name)
 End Function
 End Function
 
 
-Function _ManageDeadTexArray()
-	If dead_texs.length <= n_live_texs
-		' expand array so it's large enough to hold all the current live textures.
-		dead_texs=dead_texs[..n_live_texs+20]
-	EndIf
-End Function
-
-Function CreateTex:Int( width:Int, height:Int, flags:Int )
+Function CreateTex:Int( width:Int,height:Int,flags:Int,pixmap:TPixmap )
+	If pixmap.dds_fmt<>0 Return pixmap.tex_name ' if dds texture already exists
 
 
 	'alloc new tex
 	'alloc new tex
 	Local name:Int
 	Local name:Int
 	glGenTextures( 1, Varptr name )
 	glGenTextures( 1, Varptr name )
 
 
-	n_live_texs :+ 1
-	_ManageDeadTexArray()
-
 	'flush dead texs
 	'flush dead texs
-	If dead_tex_seq = GraphicsSeq
-		For Local i:Int = 0 Until n_dead_texs
-			glDeleteTextures( 1, Varptr dead_texs[i] )
-		Next
+	If dead_tex_seq=GraphicsSeq
+		Local n:Int = dead_texs.RemoveLast()
+		While n <> $FFFFFFFF
+			glDeleteTextures(1, Varptr n)
+			n = dead_texs.RemoveLast()
+		Wend
 	EndIf
 	EndIf
-	n_dead_texs = 0
+
 	dead_tex_seq = GraphicsSeq
 	dead_tex_seq = GraphicsSeq
 
 
 	'bind new tex
 	'bind new tex
@@ -131,22 +133,20 @@ Function CreateTex:Int( width:Int, height:Int, flags:Int )
 	Forever
 	Forever
 
 
 	Return name
 	Return name
-
 End Function
 End Function
 
 
 'NOTE: Assumes a bound texture.
 'NOTE: Assumes a bound texture.
 Function UploadTex( pixmap:TPixmap, flags:Int )
 Function UploadTex( pixmap:TPixmap, flags:Int )
-
 	Local mip_level:Int
 	Local mip_level:Int
+	If pixmap.dds_fmt <> 0 Then Return ' if dds texture already exists
 	Repeat
 	Repeat
-
 		glTexImage2D( GL_TEXTURE_2D, mip_level, GL_RGBA, pixmap.width, pixmap.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null )
 		glTexImage2D( GL_TEXTURE_2D, mip_level, GL_RGBA, pixmap.width, pixmap.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null )
 		For Local y:Int = 0 Until pixmap.height
 		For Local y:Int = 0 Until pixmap.height
 			Local row:Byte Ptr = pixmap.pixels + ( y * pixmap.width ) * 4
 			Local row:Byte Ptr = pixmap.pixels + ( y * pixmap.width ) * 4
 			glTexSubImage2D( GL_TEXTURE_2D, mip_level, 0, y, pixmap.width, 1, GL_RGBA, GL_UNSIGNED_BYTE, row )
 			glTexSubImage2D( GL_TEXTURE_2D, mip_level, 0, y, pixmap.width, 1, GL_RGBA, GL_UNSIGNED_BYTE, row )
 		Next
 		Next
 
 
-		If Not ( flags & MIPMAPPEDIMAGE ) Exit
+		If Not ( flags & MIPMAPPEDIMAGE ) Then Exit
 		If pixmap.width > 1 And pixmap.height > 1
 		If pixmap.width > 1 And pixmap.height > 1
 			pixmap = ResizePixmap( pixmap, pixmap.width / 2, pixmap.height / 2 )
 			pixmap = ResizePixmap( pixmap, pixmap.width / 2, pixmap.height / 2 )
 		Else If pixmap.width > 1
 		Else If pixmap.width > 1
@@ -168,6 +168,7 @@ Function AdjustTexSize( width:Int Var, height:Int Var )
 	height = Pow2Size( height )
 	height = Pow2Size( height )
 
 
 	Return ' assume this size is fine...
 	Return ' assume this size is fine...
+	Rem
 	Repeat
 	Repeat
 		Local t:Int
 		Local t:Int
 		glTexImage2D( GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null )
 		glTexImage2D( GL_TEXTURE_2D, 0, 4, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null )
@@ -181,9 +182,66 @@ Function AdjustTexSize( width:Int Var, height:Int Var )
 		If width > 1 width :/ 2
 		If width > 1 width :/ 2
 		If height > 1 height :/ 2
 		If height > 1 height :/ 2
 	Forever
 	Forever
-
+	EndRem
 End Function
 End Function
 
 
+Type TDynamicArray
+
+	Private
+
+	Field data:Int Ptr
+	Field size:Size_T
+	Field capacity:Size_T
+
+	Field guard:TMutex
+
+	Public
+
+	Method New(initialCapacity:Int = 8)
+		capacity = initialCapacity
+		data = malloc_(Size_T(initialCapacity * 4))
+		guard = CreateMutex()
+	End Method
+
+	Method AddLast(value:Int)
+		guard.Lock()
+		If size = capacity Then
+			capacity :* 2
+			Local d:Byte Ptr = realloc_(data, capacity * 4)
+			If Not d Then
+				Throw "Failed to allocate more memory"
+			End If
+			data = d
+		End If
+
+		data[size] = value
+		size :+ 1
+		guard.Unlock()
+	End Method
+
+	Method RemoveLast:Int()
+		guard.Lock()
+		Local v:Int
+
+		If size > 0 Then
+			size :- 1
+			v = data[size]
+		Else
+			v = $FFFFFFFF
+		End If
+
+		guard.Unlock()
+
+		Return v
+	End Method
+
+	Method Delete()
+		free_(data)
+		CloseMutex(guard)
+	End Method
+
+End Type
+
 Function DefaultVShaderSource:String()
 Function DefaultVShaderSource:String()
 
 
 	Local str:String = ""
 	Local str:String = ""
@@ -291,137 +349,34 @@ Function DefaultTextureFShaderSource:String()
 
 
 End Function
 End Function
 
 
-
-Global glewIsInit:Int
-
-Type TGL2SDLRenderImageContext Extends TRenderImageContext
-	Field _gc:TGraphics
-	Field _driver:TGraphicsDriver
-	Field _backbuffer:Int
-	Field _width:Int
-	Field _height:Int
-	Field _renderimages:TList
+Type TGL2SDLRenderImageFrame Extends TGLImageFrame
+	Field FBO:Int
+	Field width:Int
+	Field height:Int
 	
 	
-	Field _matrix:TMatrix
-
-	Method Delete()
-		Destroy()
-	EndMethod
-
-	Method Destroy()
-		_gc = Null
-
-		If _renderimages
-			For Local ri:TGL2SDLRenderImage = EachIn _renderimages
-				ri.DestroyRenderImage()
-			Next
-		EndIf
-	EndMethod
+	Method Draw( x0#,y0#,x1#,y1#,tx#,ty#,sx#,sy#,sw#,sh# ) Override
+		Assert seq=GraphicsSeq Else "Image does not exist"
 
 
-	Method Create:TGL2SDLRenderimageContext(gc:TGraphics, driver:TGraphicsDriver)
-		If Not glewIsInit
-			glewInit
-			glewIsInit = True
-		EndIf
-
-		_renderimages = New TList
-		_gc = TMax2DGraphics(gc)
-		_driver = TMax2DDriver(driver)
-		
-		_width = GraphicsWidth()
-		_height = GraphicsHeight()
-
-		' get the backbuffer - usually 0
-		glGetIntegerv(GL_FRAMEBUFFER_BINDING, Varptr _backbuffer)
-		
-		'glGetFloatv(GL_PROJECTION_MATRIX, _matrix)
-		_matrix = TGL2Max2DDriver(driver).u_pmatrix
+		' Note for a TGLRenderImage the V texture coordinate is flipped compared to the regular TImageFrame.Draw method
+		Local u0:Float = sx * uscale
+		Local v0:Float = (sy + sh) * vscale
+		Local u1:Float = (sx + sw) * uscale
+		Local v1:Float = sy * vscale
 		
 		
-		Return Self
-	EndMethod
-
-	Method GraphicsContext:TGraphics()
-		Return _gc
-	EndMethod
-
-	Method CreateRenderImage:TRenderImage(width:Int, height:Int, UseImageFiltering:Int)
-		Local renderimage:TGL2SDLRenderImage = New TGL2SDLRenderImage.CreateRenderImage(width, height)
-		renderimage.Init(_gc, _driver, UseImageFiltering, Null)
-		Return  renderimage
-	EndMethod
-	
-	Method CreateRenderImageFromPixmap:TRenderImage(pixmap:TPixmap, UseImageFiltering:Int)
-		Local renderimage:TGL2SDLRenderImage = New TGL2SDLRenderImage.CreateRenderImage(pixmap.width, pixmap.height)
-		renderimage.Init(_gc, _driver, UseImageFiltering, pixmap)
-		Return  renderimage
+		_driver.DrawTexture( name, u0, v0, u1, v1, x0, y0, x1, y1, tx, ty, Self )
 	EndMethod
 	EndMethod
 	
 	
-	Method DestroyRenderImage(renderImage:TRenderImage)
-		renderImage.DestroyRenderImage()
-		_renderImages.Remove(renderImage)
-	EndMethod
-
-	Method SetRenderImage(renderimage:TRenderimage)
-		Local driver:TGL2Max2DDriver = TGL2Max2DDriver(_driver)
-		driver.Flush()
-			
-		If Not renderimage
-			glBindFramebuffer(GL_FRAMEBUFFER,_backbuffer)
+	Function Create:TGL2SDLRenderImageFrame(width:UInt, height:UInt, flags:Int)
+		' store so that we can restore once the fbo is created
+		Local ScissorTestEnabled:Int = GlIsEnabled(GL_SCISSOR_TEST)
+		glDisable(GL_SCISSOR_TEST)
 		
 		
-			driver.u_pmatrix = _matrix
-			
-			glViewport(0,0,_width,_height)
-		Else
-			renderimage.SetRenderImage()
-		EndIf
-	EndMethod
-	
-	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
-		Return TGL2SDLRenderImage(renderImage).ToPixmap()
-	EndMethod
-EndType
-
-
-
-Type TGL2SDLRenderImageFrame Extends TGLImageFrame
-	Field _fbo:Int
-	
-	Method Delete()
-		DeleteFramebuffer
-	EndMethod
-	
-	Method DeleteFramebuffer()
-		If _fbo
-			glDeleteFramebuffers(1, Varptr _fbo)
-			_fbo = -1 '???
-		EndIf
-	EndMethod
-	
-	Method Clear(r:Int=0, g:Int=0, b:Int=0, a:Float=0.0)
-		'backup current
-		Local c:Float[4]
-		glGetFloatv(GL_COLOR_CLEAR_VALUE, c)		
-
-		glClearColor(r/255.0, g/255.0, b/255.0, a)
-		glClear(GL_COLOR_BUFFER_BIT)
-
-		glClearColor(c[0], c[1], c[2], c[3])
-	End Method
-
-	Method CreateRenderTarget:TGL2SDLRenderImageFrame(width:Int, height:Int, UseImageFiltering:Int, pixmap:TPixmap)
-		If pixmap pixmap = ConvertPixmap(pixmap, PF_RGBA)
+		Local TextureName:Int
+		glGenTextures(1, Varptr TextureName)
+		glBindTexture(GL_TEXTURE_2D, TextureName)
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
 		
 		
-		glDisable(GL_SCISSOR_TEST)
-
-		glGenTextures(1, Varptr name)
-		glBindTexture(GL_TEXTURE_2D, name)
-		If pixmap
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap.pixels)
-		Else
-			glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
-		EndIf
-
-		If UseImageFiltering
+		If flags & FILTEREDIMAGE
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
 		Else
 		Else
@@ -429,113 +384,41 @@ Type TGL2SDLRenderImageFrame Extends TGLImageFrame
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
 			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
 		EndIf
 		EndIf
 		
 		
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
 		
 		
-		glGenFramebuffers(1,Varptr _fbo)
-		glBindFramebuffer GL_FRAMEBUFFER,_fbo
-
-		glBindTexture GL_TEXTURE_2D,name
-		glFramebufferTexture2D GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,name,0
-
-		If Not pixmap
-			Clear()
-		EndIf
-
-		uscale = 1.0 / width
-		vscale = 1.0 / height
-
-		Return Self
-	EndMethod
-	
-	Method DestroyRenderTarget()
-		DeleteFramebuffer()
-	EndMethod
-	
-	Method ToPixmap:TPixmap(width:Int, height:Int)
-		Local prevTexture:Int
-		Local prevFBO:Int
+		Local FrameBufferObject:Int
+		glGenFramebuffers(1, Varptr FrameBufferObject)
+		glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferObject)
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureName, 0)
 		
 		
-		glGetIntegerv(GL_TEXTURE_BINDING_2D,Varptr prevTexture)
-		glBindTexture(GL_TEXTURE_2D,name)
-
-		Local pixmap:TPixmap = CreatePixmap(width, height, PF_RGBA8888)		
-		glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixmap.pixels)
+		Local RenderTarget:TGL2SDLRenderImageFrame = New TGL2SDLRenderImageFrame
+		RenderTarget.name = TextureName
+		RenderTarget.FBO = FrameBufferObject
 		
 		
-		glBindTexture(GL_TEXTURE_2D,prevTexture)
-				
-		Return pixmap
-	EndMethod
-EndType
-
-Type TGL2SDLRenderImage Extends TRenderImage
-	'Field _matrix:Float[16]
-	Field _matrix:TMatrix
-	Field _driver:TGL2Max2DDriver
-
-	Method CreateRenderImage:TGL2SDLRenderImage(width:Int, height:Int)
-		Self.width = width	' TImage.width
-		Self.height = height	' TImage.height
-
-		Return Self
-	EndMethod
-	
-	Method DestroyRenderImage()
-		TGL2SDLRenderImageFrame(frames[0]).DestroyRenderTarget()
-	EndMethod
-	
-	Method Init(g:TGraphics, driver:TGraphicsDriver, UseImageFiltering:Int, pixmap:TPixmap)
-		_driver = TGL2Max2DDriver(driver)
-		_matrix = New TMatrix
-	
-		'_matrix.SetOrthographic( 0, width, 0, height, -1, 1 )
-		_matrix.SetOrthographic( 0, width, height, 0, -1, 1 )
-	
-		Local prevFBO:Int
-		Local prevTexture:Int
-		Local prevScissorTest:Int
-
-		glGetIntegerv(GL_FRAMEBUFFER_BINDING, Varptr prevFBO)
-		glGetIntegerv(GL_TEXTURE_BINDING_2D,Varptr prevTexture)
-		glGetIntegerv(GL_SCISSOR_TEST, Varptr prevScissorTest)
+		RenderTarget.width = width
+		RenderTarget.height = height
+		RenderTarget.uscale = 1.0 / width
+		RenderTarget.vscale = 1.0 / height
+		RenderTarget.u1 = width * RenderTarget.uscale
+		RenderTarget.v1 = height * RenderTarget.vscale
 		
 		
-		frames = New TGL2SDLRenderImageFrame[1]
-		frames[0] = New TGL2SDLRenderImageFrame.CreateRenderTarget(width, height, UseImageFiltering, pixmap)
+		If ScissorTestEnabled
+			glEnable(GL_SCISSOR_TEST)
+		EndIf
 		
 		
-		If prevScissorTest glEnable(GL_SCISSOR_TEST)
-		glBindTexture GL_TEXTURE_2D,prevTexture
-		glBindFramebuffer GL_FRAMEBUFFER,prevFBO
-	EndMethod
-	
-	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
+		Return RenderTarget
+	EndFunction
 	
 	
-	Method SetRenderImage()
-		glBindFrameBuffer(GL_FRAMEBUFFER, TGL2SDLRenderImageFrame(frames[0])._fbo)
-		_driver.u_pmatrix = _matrix
-		glViewport 0,0,width,height 
-	EndMethod
-	
-	Method ToPixmap:TPixmap()
-		Return TGL2SDLRenderImageFrame(frames[0]).ToPixmap(width, height)
+Private
+	Method Delete()
+		glDeleteFrameBuffers(1, Varptr FBO) ' gl ignores 0
 	EndMethod
 	EndMethod
-	
-	Method SetViewport(x:Int, y:Int, width:Int, height:Int)
-		If x = 0 And y = 0 And width = Self.width And height = Self.height
-			glDisable GL_SCISSOR_TEST
-		Else
-			glEnable GL_SCISSOR_TEST
-			glScissor x, y, width, height
-		EndIf
+
+	Method New()
 	EndMethod
 	EndMethod
 EndType
 EndType
 
 
-
 Public
 Public
 
 
 '============================================================================================'
 '============================================================================================'
@@ -602,11 +485,13 @@ Type TGLImageFrame Extends TImageFrame
 				EndIf
 				EndIf
 			EndIf
 			EndIf
 		Else
 		Else
-			If tex.format <> PF_RGBA8888 tex = tex.Convert( PF_RGBA8888 )
+			If tex.dds_fmt = 0 ' not dds
+				If tex.format <> PF_RGBA8888 Then tex = tex.Convert( PF_RGBA8888 )
+			EndIf
 		EndIf
 		EndIf
 		
 		
 		'create tex
 		'create tex
-		Local name:Int = CreateTex( tex_w, tex_h, flags )
+		Local name:Int = CreateTex( tex_w, tex_h, flags, tex )
 		
 		
 		'upload it
 		'upload it
 		UploadTex( tex, flags )
 		UploadTex( tex, flags )
@@ -1009,13 +894,13 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 
 
 		Local t:TMax2DGraphics = TMax2DGraphics( g )
 		Local t:TMax2DGraphics = TMax2DGraphics( g )
 		?Not opengles
 		?Not opengles
-		Assert t And TSDLGraphics( t._graphics )
+		Assert t And TSDLGraphics( t._backendGraphics )
 		?
 		?
 
 
-		SDLGraphicsDriver().SetGraphics t._graphics
+		SDLGraphicsDriver().SetGraphics(t._backendGraphics)
 
 
-		ResetGLContext t
-		t.MakeCurrent
+		ResetGLContext(t)
+		t.MakeCurrent()
 
 
 	End Method
 	End Method
 	
 	
@@ -1044,6 +929,15 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		u_pmatrix = New TMatrix
 		u_pmatrix = New TMatrix
 		u_pmatrix.SetOrthographic( 0, gw, 0, gh, -1, 1 )
 		u_pmatrix.SetOrthographic( 0, gw, 0, gh, -1, 1 )
 
 
+		' Create default back buffer render image - the FBO will be value 0 which is the default for the existing backbuffer
+		Local BackBufferRenderImageFrame:TGL2SDLRenderImageFrame = New TGL2SDLRenderImageFrame
+		BackBufferRenderImageFrame.width = gw
+		BackBufferRenderImageFrame.height = gh
+	
+		' cache it
+		_BackBufferRenderImageFrame = BackBufferRenderImageFrame
+		_CurrentRenderImageFrame = _BackBufferRenderImageFrame
+
 	End Method
 	End Method
 	
 	
 	Method Flip:Int( sync:Int ) Override
 	Method Flip:Int( sync:Int ) Override
@@ -1061,10 +955,6 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 		Return "OpenGL"
 		Return "OpenGL"
 
 
 	End Method
 	End Method
-
-	Method CreateRenderImageContext:Object(g:TGraphics) Override
-		Return new TGL2SDLRenderImageContext.Create(g, self)
-	End Method
 	
 	
 	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap, flags:Int ) Override
 	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap, flags:Int ) Override
 		Local frame:TGLImageFrame
 		Local frame:TGLImageFrame
@@ -1143,43 +1033,28 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 	End Method
 	End Method
 
 
 	Method SetColor( red:Int, green:Int, blue:Int ) Override
 	Method SetColor( red:Int, green:Int, blue:Int ) Override
-
 		color4f[0] = Min( Max( red, 0 ), 255 ) / 255.0
 		color4f[0] = Min( Max( red, 0 ), 255 ) / 255.0
 		color4f[1] = Min( Max( green, 0 ), 255 ) / 255.0
 		color4f[1] = Min( Max( green, 0 ), 255 ) / 255.0
 		color4f[2] = Min( Max( blue, 0 ), 255 ) / 255.0
 		color4f[2] = Min( Max( blue, 0 ), 255 ) / 255.0
-
-	End Method
-
-	Method SetColor( color:SColor8 ) Override
-		color4f[0]=color.r / 255.0
-		color4f[1]=color.g / 255.0
-		color4f[2]=color.b / 255.0
 	End Method
 	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
 	End Method
 	
 	
 	Method SetViewport( x:Int, y:Int, w:Int, h:Int ) Override
 	Method SetViewport( x:Int, y:Int, w:Int, h:Int ) Override
 		'render what has been batched till now
 		'render what has been batched till now
 		FlushTest( PRIMITIVE_VIEWPORT )
 		FlushTest( PRIMITIVE_VIEWPORT )
 
 
-		If x = 0 And y = 0 And w = GraphicsWidth() And h = GraphicsHeight()
-			glDisable( GL_SCISSOR_TEST )
-		Else
-			glEnable( GL_SCISSOR_TEST )
-			glScissor( x, GraphicsHeight() - y - h, w, h )
-		EndIf
-
+		_GLScissor_BMaxViewport.x = x
+		_GLScissor_BMaxViewport.y = y
+		_GLScissor_BMaxViewport.width = w
+		_GLScissor_BMaxViewport.height = h
+		SetScissor(x, y, w, h)
 	End Method
 	End Method
 
 
 	Method SetTransform( xx:Float, xy:Float, yx:Float, yy:Float ) Override
 	Method SetTransform( xx:Float, xy:Float, yx:Float, yy:Float ) Override
@@ -1673,6 +1548,52 @@ Type TGL2Max2DDriver Extends TMax2DDriver
 '
 '
 '	End Method
 '	End Method
 
 
+	Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Override
+		Return TGL2SDLRenderImageFrame.Create(width, height, flags)
+	EndMethod
+	
+	Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override		
+		If RenderImageFrame = _CurrentRenderImageFrame
+			Return
+		EndIf
+		
+		Flush()
+		
+		glBindFrameBuffer(GL_FRAMEBUFFER, TGL2SDLRenderImageFrame(RenderImageFrame).FBO)
+		_CurrentRenderImageFrame = TGL2SDLRenderImageFrame(RenderImageFrame)
+		
+		Local vp:Rect = _GLScissor_BMaxViewport
+		SetScissor(vp.x, vp.y, vp.width, vp.height)
+		SetMatrixAndViewportToCurrentRenderImage()
+	EndMethod
+	
+	Method SetBackbuffer()
+		SetRenderImageFrame(_BackBufferRenderImageFrame)
+	EndMethod
+	
+Private
+	Field _glewIsInitialised:Int = False
+
+	Method SetMatrixAndViewportToCurrentRenderImage()
+		u_pmatrix.SetOrthographic( 0, _CurrentRenderImageFrame.width, 0, _CurrentRenderImageFrame.height, -1, 1 )
+		
+		'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
 End Type
 
 
 Rem
 Rem
@@ -1681,7 +1602,7 @@ about:
 The returned driver can be used with #SetGraphicsDriver to enable OpenGL Max2D rendering.
 The returned driver can be used with #SetGraphicsDriver to enable OpenGL Max2D rendering.
 End Rem
 End Rem
 Function GL2Max2DDriver:TGL2Max2DDriver()
 Function GL2Max2DDriver:TGL2Max2DDriver()
-	Print "GL2 (with shaders) Active"
+	'Print "GL2 (with shaders) Active"
 	Global _done:Int
 	Global _done:Int
 	If Not _done
 	If Not _done
 		_driver = New TGL2Max2DDriver.Create()
 		_driver = New TGL2Max2DDriver.Create()

+ 0 - 63
gl2sdlmax2d.mod/rectnode.bmx

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

+ 272 - 316
glsdlmax2d.mod/glsdlmax2d.bmx

@@ -8,12 +8,14 @@ The OpenGL Max2D module provides an SDL-backend OpenGL driver for #Max2D.
 End Rem
 End Rem
 Module SDL.GLSDLMax2D
 Module SDL.GLSDLMax2D
 
 
-ModuleInfo "Version: 1.15"
+ModuleInfo "Version: 1.16"
 ModuleInfo "Author: Mark Sibly"
 ModuleInfo "Author: Mark Sibly"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "License: zlib/libpng"
 ModuleInfo "Copyright: Blitz Research Ltd"
 ModuleInfo "Copyright: Blitz Research Ltd"
 ModuleInfo "Modserver: BRL"
 ModuleInfo "Modserver: BRL"
 
 
+ModuleInfo "History: 1.16"
+ModuleInfo "History: Added RenderImages / render2texture"
 ModuleInfo "History: 1.15"
 ModuleInfo "History: 1.15"
 ModuleInfo "History: Changed to SuperStrict"
 ModuleInfo "History: Changed to SuperStrict"
 ModuleInfo "History: Extended flags to Long"
 ModuleInfo "History: Extended flags to Long"
@@ -42,10 +44,26 @@ ModuleInfo "History: Added checks to prevent invalid textures deletes"
 
 
 Import BRL.Max2D
 Import BRL.Max2D
 Import SDL.GLSDLGraphics
 Import SDL.GLSDLGraphics
+Import BRL.Threads
 
 
 Private
 Private
 
 
+Struct Rect
+	Method New (X:Int, Y:Int, width:Int, height:Int)
+		Self.X = X
+		Self.Y = Y
+		Self.width = width
+		Self.height = height
+	EndMethod
+	
+	Field X:Int, Y:Int
+	Field width:Int, height:Int
+EndStruct
+
 Global _driver:TGLMax2DDriver
 Global _driver:TGLMax2DDriver
+Global _BackbufferRenderImageFrame:TGLSDLRenderImageFrame
+Global _CurrentRenderImageFrame:TGLSDLRenderImageFrame
+Global _GLScissor_BMaxViewport:Rect = New Rect
 
 
 'Naughty!
 'Naughty!
 Const GL_BGR:Int=$80E0
 Const GL_BGR:Int=$80E0
@@ -87,89 +105,79 @@ Function Pow2Size:Int( n:Int )
 	Return t
 	Return t
 End Function
 End Function
 
 
-Global dead_texs:Int[],n_dead_texs:Int,dead_tex_seq:Int,n_live_texs:Int
-
-Extern
-	Function bbAtomicAdd:Int( target:Int Ptr,value:Int )="int bbAtomicAdd( int *,int )!"
-End Extern
+Global dead_texs:TDynamicArray = New TDynamicArray(32)
+Global dead_tex_seq:Int
 
 
 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
 'Enqueues a texture for deletion, to prevent release textures on wrong thread.
 Function DeleteTex( name:Int,seq:Int )
 Function DeleteTex( name:Int,seq:Int )
 	If seq<>dead_tex_seq Return
 	If seq<>dead_tex_seq Return
-	
-	Local n:Int = bbAtomicAdd(Varptr n_dead_texs, 1)
-	bbAtomicAdd(Varptr n_live_texs, -1)
 
 
-	dead_texs[n] = name
+	dead_texs.AddLast(name)
 End Function
 End Function
 
 
-Function _ManageDeadTexArray()
-	If dead_texs.length <= n_live_texs
-		' expand array so it's large enough to hold all the current live textures.
-		dead_texs=dead_texs[..n_live_texs+20]
-	EndIf
-End Function
-
-Function CreateTex:Int( width:Int,height:Int,flags:Int )
+Function CreateTex:Int( width:Int,height:Int,flags:Int,pixmap:TPixmap )
+	If pixmap.dds_fmt<>0 Then Return pixmap.tex_name ' if dds texture already exists
+	
 	'alloc new tex
 	'alloc new tex
 	Local name:Int
 	Local name:Int
-	glGenTextures 1,Varptr name
-
-	n_live_texs :+ 1
-	_ManageDeadTexArray()
-
+	glGenTextures( 1, Varptr name )
+	
 	'flush dead texs
 	'flush dead texs
 	If dead_tex_seq=GraphicsSeq
 	If dead_tex_seq=GraphicsSeq
-		For Local i:Int=0 Until n_dead_texs
-			glDeleteTextures 1,Varptr dead_texs[i]
-		Next
+		Local n:Int = dead_texs.RemoveLast()
+		While n <> $FFFFFFFF
+			glDeleteTextures(1, Varptr n)
+			n = dead_texs.RemoveLast()
+		Wend
 	EndIf
 	EndIf
-	n_dead_texs=0
-	dead_tex_seq=GraphicsSeq
+
+	dead_tex_seq = GraphicsSeq
 
 
 	'bind new tex
 	'bind new tex
-	BindTex name
-	
+	BindTex( name )
+
 	'set texture parameters
 	'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
 	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
 		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
 		Else
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
+			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )
 		EndIf
 		EndIf
 	Else
 	Else
-		glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
+		glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST )
 		If flags & MIPMAPPEDIMAGE
 		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
 		Else
-			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
+			glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST )
 		EndIf
 		EndIf
 	EndIf
 	EndIf
 
 
 	Local mip_level:Int
 	Local mip_level:Int
-
 	Repeat
 	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
 	Forever
 
 
 	Return name
 	Return name
 End Function
 End Function
 
 
+'NOTE: Assumes a bound texture.
 Function UploadTex( pixmap:TPixmap,flags:Int )
 Function UploadTex( pixmap:TPixmap,flags:Int )
 	Local mip_level:Int
 	Local mip_level:Int
+	If pixmap.dds_fmt <> 0 Then Return ' if dds texture already exists
 	Repeat
 	Repeat
 		glPixelStorei GL_UNPACK_ROW_LENGTH,pixmap.pitch/BytesPerPixel[pixmap.format]
 		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
 		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 Not (flags & MIPMAPPEDIMAGE) Then Exit
 		If pixmap.width>1 And pixmap.height>1
 		If pixmap.width>1 And pixmap.height>1
 			pixmap=ResizePixmap( pixmap,pixmap.width/2,pixmap.height/2 )
 			pixmap=ResizePixmap( pixmap,pixmap.width/2,pixmap.height/2 )
 		Else If pixmap.width>1
 		Else If pixmap.width>1
@@ -186,256 +194,77 @@ End Function
 
 
 Function AdjustTexSize( width:Int Var,height:Int Var )
 Function AdjustTexSize( width:Int Var,height:Int Var )
 	'calc texture size
 	'calc texture size
-	width=Pow2Size( width )
-	height=Pow2Size( height )
+	width = Pow2Size( width )
+	height = Pow2Size( height )
 	Repeat
 	Repeat
 		Local t:Int
 		Local t:Int
 		glTexImage2D GL_PROXY_TEXTURE_2D,0,4,width,height,0,GL_RGBA,GL_UNSIGNED_BYTE,Null
 		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
 		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 Then width :/ 2
+		If height>1 Then height :/ 2
 	Forever
 	Forever
 End Function
 End Function
 
 
+Type TDynamicArray
 
 
-
-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
+	Private
 	
 	
-	Method CreatePixmapFromRenderImage:TPixmap(renderImage:TRenderImage)
-		Return TGLRenderImage(renderImage).ToPixmap()
-	EndMethod
-EndType
-
-
-Type TGLRenderImageFrame Extends TGLImageFrame
-	Field _fbo:Int
+	Field data:Int Ptr
+	Field size:Size_T
+	Field capacity:Size_T
 	
 	
-	Method Delete()
-		DeleteFramebuffer
-	EndMethod
+	Field guard:TMutex
 	
 	
-	Method DeleteFramebuffer()
-		If _fbo
-			glDeleteFramebuffers(1, Varptr _fbo)
-			_fbo = -1 '???
-		EndIf
-	EndMethod
+	Public
 	
 	
-	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])
+	Method New(initialCapacity:Int = 8)
+		capacity = initialCapacity
+		data = malloc_(Size_T(initialCapacity * 4))
+		guard = CreateMutex()
 	End Method
 	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
+	Method AddLast(value:Int)
+		guard.Lock()
+		If size = capacity Then
+			capacity :* 2
+			Local d:Byte Ptr = realloc_(data, capacity * 4)
+			If Not d Then
+				Throw "Failed to allocate more memory"
+			End If
+			data = d
+		End If
 		
 		
-		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
+		data[size] = value
+		size :+ 1
+		guard.Unlock()
+	End Method
 	
 	
-	Method ToPixmap:TPixmap(width:Int, height:Int)
-		Local prevTexture:Int
-		Local prevFBO:Int
+	Method RemoveLast:Int()
+		guard.Lock()
+		Local v: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)
+		If size > 0 Then
+			size :- 1
+			v = data[size]
+		Else
+			v = $FFFFFFFF
+		End If
 		
 		
-		frames = New TGLRenderImageFrame[1]
-		frames[0] = New TGLRenderImageFrame.CreateRenderTarget(width, height, UseImageFiltering, pixmap)
+		guard.Unlock()
 		
 		
-		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)
+		Return v
 	End Method
 	End Method
 
 
-	Method Frame:TImageFrame(index:Int=0)
-		Return frames[0]
-	EndMethod
+	Method Delete()
+		free_(data)
+		CloseMutex(guard)
+	End Method
 	
 	
-	Method SetRenderImage()
-		glBindFrameBuffer(GL_FRAMEBUFFER, TGLRenderImageFrame(frames[0])._fbo)
+End Type
 
 
-		glMatrixMode(GL_PROJECTION)
-		glLoadMatrixf(_matrix)
-	
-		glViewport 0,0,width,height 
-	EndMethod
-	
-	Method ToPixmap:TPixmap()
-		Return TGLRenderImageFrame(frames[0]).ToPixmap(width, height)
-	EndMethod
-	
-	Method SetViewport(x:Int, y:Int, width:Int, height:Int)
-		If x = 0 And y = 0 And width = Self.width And height = Self.height
-			glDisable GL_SCISSOR_TEST
-		Else
-			glEnable GL_SCISSOR_TEST
-			glScissor x, y, width, height
-		EndIf
-	EndMethod
-EndType
+Global glewIsInit:Int
 
 
 Public
 Public
 
 
@@ -458,11 +287,11 @@ Type TGLImageFrame Extends TImageFrame
 	Method Draw( x0:Float,y0:Float,x1:Float,y1:Float,tx:Float,ty:Float,sx:Float,sy:Float,sw:Float,sh:Float ) Override
 	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"
 		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
 		EnableTex name
 		glBegin GL_QUADS
 		glBegin GL_QUADS
 		glTexCoord2f u0,v0
 		glTexCoord2f u0,v0
@@ -504,11 +333,13 @@ Type TGLImageFrame Extends TImageFrame
 				EndIf
 				EndIf
 			EndIf
 			EndIf
 		Else
 		Else
-			If tex.format<>PF_RGBA8888 tex=tex.Convert( PF_RGBA8888 )
+			If tex.dds_fmt=0 ' not dds
+				If tex.format<>PF_RGBA8888 tex=tex.Convert( PF_RGBA8888 )
+			EndIf
 		EndIf
 		EndIf
 		
 		
 		'create tex
 		'create tex
-		Local name:Int=CreateTex( tex_w,tex_h,flags )
+		Local name:Int=CreateTex( tex_w,tex_h,flags,tex )
 		
 		
 		'upload it
 		'upload it
 		UploadTex tex,flags
 		UploadTex tex,flags
@@ -526,8 +357,94 @@ Type TGLImageFrame Extends TImageFrame
 
 
 End Type
 End Type
 
 
-Type TGLMax2DDriver Extends TMax2DDriver
+Type TGLSDLRenderImageFrame Extends TGLImageFrame
+	Field FBO:Int
+	Field width:Int
+	Field height:Int
+	
+	Method Draw( x0:Float, y0:Float, x1:Float, y1:Float, tx:Float, ty:Float, sx:Float, sy:Float, sw:Float, sh:Float ) Override
+		Assert seq=GraphicsSeq Else "Image does not exist"
+
+		' Note for a TGLRenderImage the V texture coordinate is flipped compared to the regular TImageFrame.Draw method
+		Local u0:Float = sx * uscale
+		Local v0:Float = (sy + sh) * vscale
+		Local u1:Float = (sx + sw) * uscale
+		Local v1:Float = sy * vscale	
+		
+		EnableTex name
+		glBegin GL_QUADS
+		glTexCoord2f u0,v0
+		glVertex2f x0*ix+y0*iy+tx,x0*jx+y0*jy+ty
+		glTexCoord2f u1,v0
+		glVertex2f x1*ix+y0*iy+tx,x1*jx+y0*jy+ty
+		glTexCoord2f u1,v1
+		glVertex2f x1*ix+y1*iy+tx,x1*jx+y1*jy+ty
+		glTexCoord2f u0,v1
+		glVertex2f x0*ix+y1*iy+tx,x0*jx+y1*jy+ty
+		glEnd
+	End Method
+	
+	Function Create:TGLSDLRenderImageFrame(width:UInt, height:UInt, flags:Int)
+		' Need this to enable frame buffer objects - glGenFramebuffers
+		Global GlewIsInitialised:Int = False
+		If Not GlewIsInitialised
+			GlewInit()
+			GlewIsInitialised = True
+		EndIf
+		
+		' store so that we can restore once the fbo is created
+		Local ScissorTestEnabled:Int = GlIsEnabled(GL_SCISSOR_TEST)
+		glDisable(GL_SCISSOR_TEST)
+		
+		Local TextureName:Int
+		glGenTextures(1, Varptr TextureName)
+		glBindTexture(GL_TEXTURE_2D, TextureName)
+		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, Null)
+		
+		If flags & FILTEREDIMAGE
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR
+		Else
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST
+			glTexParameteri GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST
+		EndIf
+		
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)
+		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)
+		
+		Local FrameBufferObject:Int
+		glGenFramebuffers(1, Varptr FrameBufferObject)
+		glBindFramebuffer(GL_FRAMEBUFFER, FrameBufferObject)
+		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, TextureName, 0)
+		
+		Local RenderTarget:TGLSDLRenderImageFrame = New TGLSDLRenderImageFrame
+		RenderTarget.name = TextureName
+		RenderTarget.FBO = FrameBufferObject
+		
+		RenderTarget.width = width
+		RenderTarget.height = height
+		RenderTarget.uscale = 1.0 / width
+		RenderTarget.vscale = 1.0 / height
+		RenderTarget.u1 = width * RenderTarget.uscale
+		RenderTarget.v1 = height * RenderTarget.vscale
+		
+		If ScissorTestEnabled
+			glEnable(GL_SCISSOR_TEST)
+		EndIf
+		
+		Return RenderTarget
+	End Function
+	
+Private
+	Method Delete()
+		glDeleteFramebuffers(1, Varptr FBO) ' gl ignores 0
+	End Method
 
 
+	Method New()
+	End Method
+EndType
+
+Type TGLMax2DDriver Extends TMax2DDriver
 	Method Create:TGLMax2DDriver()
 	Method Create:TGLMax2DDriver()
 		If Not SDLGraphicsDriver() Return Null
 		If Not SDLGraphicsDriver() Return Null
 		
 		
@@ -551,19 +468,19 @@ Type TGLMax2DDriver Extends TMax2DDriver
 	
 	
 	Method SetGraphics( g:TGraphics ) Override
 	Method SetGraphics( g:TGraphics ) Override
 		If Not g
 		If Not g
-			TMax2DGraphics.ClearCurrent
+			TMax2DGraphics.ClearCurrent()
 			SDLGraphicsDriver().SetGraphics Null
 			SDLGraphicsDriver().SetGraphics Null
 			Return
 			Return
 		EndIf
 		EndIf
 	
 	
 		Local t:TMax2DGraphics=TMax2DGraphics(g)
 		Local t:TMax2DGraphics=TMax2DGraphics(g)
-		Assert t And TSDLGraphics( t._graphics )
+		Assert t And TSDLGraphics( t._backendGraphics )
 
 
-		SDLGraphicsDriver().SetGraphics t._graphics
+		SDLGraphicsDriver().SetGraphics(t._backendGraphics)
 
 
-		ResetGLContext t
+		ResetGLContext(t)
 		
 		
-		t.MakeCurrent
+		t.MakeCurrent()
 	End Method
 	End Method
 	
 	
 	Method ResetGLContext( g:TGraphics )
 	Method ResetGLContext( g:TGraphics )
@@ -580,6 +497,15 @@ Type TGLMax2DDriver Extends TMax2DDriver
 		glMatrixMode GL_MODELVIEW
 		glMatrixMode GL_MODELVIEW
 		glLoadIdentity
 		glLoadIdentity
 		glViewport 0,0,gw,gh
 		glViewport 0,0,gw,gh
+		
+		' Create default back buffer render image - the FBO will be value 0 which is the default for the existing backbuffer
+		Local BackBufferRenderImageFrame:TGLSDLRenderImageFrame = New TGLSDLRenderImageFrame
+		BackBufferRenderImageFrame.width = gw
+		BackBufferRenderImageFrame.height = gh
+	
+		' cache it
+		_BackBufferRenderImageFrame = BackBufferRenderImageFrame
+		_CurrentRenderImageFrame = _BackBufferRenderImageFrame
 	End Method
 	End Method
 	
 	
 	Method Flip:Int( sync:Int ) Override
 	Method Flip:Int( sync:Int ) Override
@@ -590,15 +516,8 @@ Type TGLMax2DDriver Extends TMax2DDriver
 		Return "OpenGL"
 		Return "OpenGL"
 	End Method
 	End Method
 
 
-	
-	Method CreateRenderImageContext:Object(g:TGraphics) Override
-		Return new TGLRenderImageContext.Create(g, self)
-	End Method
-
 	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap,flags:Int ) Override
 	Method CreateFrameFromPixmap:TGLImageFrame( pixmap:TPixmap,flags:Int ) Override
-		Local frame:TGLImageFrame
-		frame=TGLImageFrame.CreateFromPixmap( pixmap,flags )
-		Return frame
+		Return TGLImageFrame.CreateFromPixmap( pixmap,flags )
 	End Method
 	End Method
 
 
 	Method SetBlend( blend:Int ) Override
 	Method SetBlend( blend:Int ) Override
@@ -648,31 +567,20 @@ Type TGLMax2DDriver Extends TMax2DDriver
 		glColor4ubv color4ub
 		glColor4ubv color4ub
 	End Method
 	End Method
 
 
-	Method SetColor( color:SColor8 ) Override
-		color4ub[0]=color.r
-		color4ub[1]=color.g
-		color4ub[2]=color.b
-		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
 	End Method
 	
 	
 	Method SetViewport( x:Int,y:Int,w:Int,h:Int ) Override
 	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
+		_GLScissor_BMaxViewport.x = x
+		_GLScissor_BMaxViewport.y = y
+		_GLScissor_BMaxViewport.width = w
+		_GLScissor_BMaxViewport.height = h
+		SetScissor(x, y, w, h)
 	End Method
 	End Method
 
 
 	Method SetTransform( xx:Float,xy:Float,yx:Float,yy:Float ) Override
 	Method SetTransform( xx:Float,xy:Float,yx:Float,yy:Float ) Override
@@ -770,6 +678,12 @@ Type TGLMax2DDriver Extends TMax2DDriver
 		Local blend:Int=state_blend
 		Local blend:Int=state_blend
 		SetBlend SOLIDBLEND
 		SetBlend SOLIDBLEND
 		Local p:TPixmap=CreatePixmap( w,h,PF_RGBA8888 )
 		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)
+		
 		glReadPixels x,GraphicsHeight()-h-y,w,h,GL_RGBA,GL_UNSIGNED_BYTE,p.pixels
 		glReadPixels x,GraphicsHeight()-h-y,w,h,GL_RGBA,GL_UNSIGNED_BYTE,p.pixels
 		p=YFlipPixmap( p )
 		p=YFlipPixmap( p )
 		SetBlend blend
 		SetBlend blend
@@ -782,7 +696,49 @@ Type TGLMax2DDriver Extends TMax2DDriver
 		glOrtho 0,width,height,0,-1,1
 		glOrtho 0,width,height,0,-1,1
 		glMatrixMode GL_MODELVIEW
 		glMatrixMode GL_MODELVIEW
 	End Method
 	End Method
+
+	Method CreateRenderImageFrame:TImageFrame(width:UInt, height:UInt, flags:Int) Override
+		Return TGLSDLRenderImageFrame.Create(width, height, flags)
+	EndMethod
 	
 	
+	Method SetRenderImageFrame(RenderImageFrame:TImageFrame) Override
+		If RenderImageFrame = _CurrentRenderImageFrame
+			Return
+		EndIf
+		
+		glBindFrameBuffer(GL_FRAMEBUFFER, TGLSDLRenderImageFrame(RenderImageFrame).FBO)
+		_CurrentRenderImageFrame = TGLSDLRenderImageFrame(RenderImageFrame)
+		
+		Local vp:Rect = _GLScissor_BMaxViewport
+		SetScissor(vp.x, vp.y, vp.width, vp.height)
+		SetMatrixAndViewportToCurrentRenderImage()
+	EndMethod
+	
+	Method SetBackbuffer()
+		SetRenderImageFrame(_BackBufferRenderImageFrame)
+	EndMethod
+	
+Private
+	Field _glewIsInitialised:Int = False
+
+	Method SetMatrixAndViewportToCurrentRenderImage()
+		glMatrixMode(GL_PROJECTION)
+		glLoadIdentity()
+		glOrtho(0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height, 0, -1, 1)
+		glMatrixMode(GL_MODELVIEW)
+		glLoadIdentity()
+		glViewport(0, 0, _CurrentRenderImageFrame.width, _CurrentRenderImageFrame.height)
+	EndMethod
+
+	Method SetScissor(x:Int, y:Int, w:Int, h:Int)
+		Local ri:TImageFrame = _CurrentRenderImageFrame
+		If x = 0 And y = 0 And w = _CurrentRenderImageFrame.width And h = _CurrentRenderImageFrame.height
+			glDisable(GL_SCISSOR_TEST)
+		Else
+			glEnable(GL_SCISSOR_TEST)
+			glScissor(x, _CurrentRenderImageFrame.height - y - h, w, h)
+		EndIf
+	EndMethod
 End Type
 End Type
 
 
 Rem
 Rem

+ 0 - 63
glsdlmax2d.mod/rectnode.bmx

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

+ 77 - 27
sdlrendermax2d.mod/sdlrendermax2d.bmx

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