Procházet zdrojové kódy

Scary update of core mojo.graphics in preparation for mojo3d!

Mark Sibly před 8 roky
rodič
revize
83b31c3cd0

+ 110 - 100
modules/mojo/graphics/canvas.monkey2

@@ -19,17 +19,20 @@ Drawing does not occur immediately. Drawing commands are 'buffered' to reduce th
 
 #end
 Class Canvas
-
-	#rem monkeydoc Creates a canvas that renders to an image.
+	
+	#rem monkeydoc Creates a canvas that renders to an image
 	#end
-	Method New( renderTarget:Image )
-		Init( renderTarget,New GraphicsDevice )
+	Method New( image:Image )
+		
+		Local rtarget:=New RenderTarget( New Texture[]( image.Texture ),Null )
+		
+		image.OnDiscarded+=rtarget.Discard
 		
-		Local texture:=renderTarget.Texture
+		Init( rtarget,New GraphicsDevice )
 		
-		BeginRender( New Recti( 0,0,texture.Rect.Size ),AffineMat3f.Translation( texture.Rect.Origin ) )
+		BeginRender( New Recti( 0,0,image.Rect.Size ),AffineMat3f.Translation( image.Rect.Origin ) )
 	End
-	
+
 	#rem monkeydoc @hidden Creates a canvas that renders to the backbuffer.
 	#end	
 	Method New( width:Int,height:Int )
@@ -58,7 +61,6 @@ Class Canvas
 		Scissor=New Recti( 0,0,bounds.Size )
 		AmbientLight=Color.Black
 		BlendMode=BlendMode.Alpha
-		TextureFilter=graphics.TextureFilter.Mipmap
 		PointSize=0
 		LineWidth=0
 		LineSmoothing=False
@@ -78,16 +80,9 @@ Class Canvas
 		_rmatrix=_rmatrixStack.Pop()
 	End
 	
-	#rem monkeydoc @hidden
-	#end	
-	Property Device:GraphicsDevice()
-	
-		Return _device
-	End
-
 	#rem monkeydoc The current render target.
 	#end	
-	Property RenderTarget:Image()
+	Property RenderTarget:RenderTarget()
 	
 		Return _rtarget
 	End
@@ -169,31 +164,20 @@ Class Canvas
 		_blendMode=blendMode
 	End
 	
-	#rem monkeydoc The current texture filter.
-	#end
-	Property TextureFilter:TextureFilter()
-	
-		Return _textureFilter
-	
-	Setter( filter:TextureFilter )
+	#rem monkeydoc TODO! Texture filtering enabled state.
 	
-		_textureFilter=filter
-	End
-
-	#rem monkeydoc Deprecated - use TextureFilter instead.
+	Set to true for normal behavior.
 	
-	Use TextureFilter instead.
+	Set to false for a groovy retro effect.
 	
 	#end	
 	Property TextureFilteringEnabled:Bool()
-	
-		Return TextureFilter=TextureFilter.Mipmap
-	
+		
+		Return True
+		
 	Setter( enabled:Bool )
 	
-		TextureFilter=enabled ? TextureFilter.Mipmap Else TextureFilter.Nearest
-
-	End
+	End	
 	
 	#rem monkeydoc The current point size for use with DrawPoint.
 	#end
@@ -392,13 +376,13 @@ Class Canvas
 	Method DrawPoint( x:Float,y:Float )
 	
 		If _pointSize<=0
-			AddDrawOp( _shader,_material,_blendMode,_textureFilter,1,1 )
+			AddDrawOp( _shader,_material,_blendMode,1,1 )
 			AddPointVertex( x,y,0,0 )
 			Return
 		Endif
 		
 		Local d:=_pointSize/2
-		AddDrawOp( _shader,_material,_blendMode,_textureFilter,4,1 )
+		AddDrawOp( _shader,_material,_blendMode,4,1 )
 		AddVertex( x-d,y-d,0,0 )
 		AddVertex( x+d,y-d,1,0 )
 		AddVertex( x+d,y+d,1,1 )
@@ -431,7 +415,7 @@ Class Canvas
 	Method DrawLine( x0:Float,y0:Float,x1:Float,y1:Float )
 
 		If _lineWidth<=0
-			AddDrawOp( _shader,_material,_blendMode,_textureFilter,2,1 )
+			AddDrawOp( _shader,_material,_blendMode,2,1 )
 			AddPointVertex( x0,y0,0,0 )
 			AddPointVertex( x1,y1,1,1 )
 			Return
@@ -447,7 +431,7 @@ Class Canvas
 		dx*=sc;dy*=sc
 		
 		If Not _lineSmoothing
-			AddDrawOp( _shader,_material,_blendMode,_textureFilter,4,1 )
+			AddDrawOp( _shader,_material,_blendMode,4,1 )
 			AddPointVertex( x0-dx,y0-dy,0,0 )
 			AddPointVertex( x0+dx,y0+dy,0,0 )
 			AddPointVertex( x1+dx,y1+dy,0,0 )
@@ -457,7 +441,7 @@ Class Canvas
 		
 		Local pmcolor:=_pmcolor
 		
-		AddDrawOp( _shader,_material,_blendMode,_textureFilter,4,2 )
+		AddDrawOp( _shader,_material,_blendMode,4,2 )
 
 		AddPointVertex( x0,y0,0,0 )
 		AddPointVertex( x1,y1,0,0 )
@@ -484,7 +468,7 @@ Class Canvas
 
 	#End
 	Method DrawTriangle( x0:Float,y0:Float,x1:Float,y1:Float,x2:Float,y2:Float )
-		AddDrawOp( _shader,_material,_blendMode,_textureFilter,3,1 )
+		AddDrawOp( _shader,_material,_blendMode,3,1 )
 		AddVertex( x0,y0,0,0 )
 		AddVertex( x1,y1,1,0 )
 		AddVertex( x2,y2,1,1 )
@@ -502,7 +486,7 @@ Class Canvas
 
 	#end
 	Method DrawQuad( x0:Float,y0:Float,x1:Float,y1:Float,x2:Float,y2:Float,x3:Float,y3:Float )
-		AddDrawOp( _shader,_material,_blendMode,_textureFilter,4,1 )
+		AddDrawOp( _shader,_material,_blendMode,4,1 )
 		AddVertex( x0,y0,0,0 )
 		AddVertex( x1,y1,1,0 )
 		AddVertex( x2,y2,1,1 )
@@ -524,7 +508,7 @@ Class Canvas
 	
 		Local x0:=x,y0:=y,x1:=x+w,y1:=y+h
 		
-		AddDrawOp( _shader,_material,_blendMode,_textureFilter,4,1 )
+		AddDrawOp( _shader,_material,_blendMode,4,1 )
 		
 		AddVertex( x0,y0,0,0 )
 		AddVertex( x1,y0,1,0 )
@@ -538,7 +522,7 @@ Class Canvas
 	
 	Method DrawRect( rect:Rectf,srcImage:Image )
 		Local tc:=srcImage.TexCoords
-		AddDrawOp( srcImage.Shader,srcImage.Material,srcImage.BlendMode,srcImage.TextureFilter,4,1 )
+		AddDrawOp( srcImage.Shader,srcImage.Material,srcImage.BlendMode,4,1 )
 		AddVertex( rect.min.x,rect.min.y,tc.min.x,tc.min.y )
 		AddVertex( rect.max.x,rect.min.y,tc.max.x,tc.min.y )
 		AddVertex( rect.max.x,rect.max.y,tc.max.x,tc.max.y )
@@ -554,7 +538,7 @@ Class Canvas
 		Local t0:=Float(srcImage.Rect.min.y+srcRect.min.y)/srcImage.Texture.Height
 		Local s1:=Float(srcImage.Rect.min.x+srcRect.max.x)/srcImage.Texture.Width
 		Local t1:=Float(srcImage.Rect.min.y+srcRect.max.y)/srcImage.Texture.Height
-		AddDrawOp( srcImage.Shader,srcImage.Material,srcImage.BlendMode,srcImage.TextureFilter,4,1 )
+		AddDrawOp( srcImage.Shader,srcImage.Material,srcImage.BlendMode,4,1 )
 		AddVertex( rect.min.x,rect.min.y,s0,t0 )
 		AddVertex( rect.max.x,rect.min.y,s1,t0 )
 		AddVertex( rect.max.x,rect.max.y,s1,t1 )
@@ -599,7 +583,7 @@ Class Canvas
 		
 		Local x0:=x+xr,y0:=y+yr
 		
-		AddDrawOp( _shader,_material,_blendMode,_textureFilter,n,1 )
+		AddDrawOp( _shader,_material,_blendMode,n,1 )
 		
 		For Local i:=0 Until n
 			Local th:=(i+.5)*Pi*2/n
@@ -654,7 +638,7 @@ Class Canvas
 		Local order:=vertices.Length/2
 		DebugAssert( order>0,"Invalid polygon" )
 		
-		AddDrawOp( _shader,_material,_blendMode,_textureFilter,order,1 )
+		AddDrawOp( _shader,_material,_blendMode,order,1 )
 		
 		For Local i:=0 Until order*2 Step 2
 			AddVertex( vertices[i],vertices[i+1],0,0 )
@@ -675,7 +659,7 @@ Class Canvas
 	Method DrawPolys( order:Int,count:Int,vertices:Float[] )
 		DebugAssert( order>0 And count>0 And order*count<=vertices.Length,"Invalid polyon" )
 
-		AddDrawOp( _shader,_material,_blendMode,_textureFilter,order,count )
+		AddDrawOp( _shader,_material,_blendMode,order,count )
 		
 		For Local i:=0 Until order*count*2 Step 2
 			AddVertex( vertices[i],vertices[i+1],0,0 )
@@ -711,9 +695,9 @@ Class Canvas
 		DebugAssert( order>0 And count>0,"Illegal primitive" )
 
 		If image
-			AddDrawOp( image.Shader,image.Material,image.BlendMode,image.TextureFilter,order,count )
+			AddDrawOp( image.Shader,image.Material,image.BlendMode,order,count )
 		Else		
-			AddDrawOp( _shader,_material,_blendMode,_textureFilter,order,count )
+			AddDrawOp( _shader,_material,_blendMode,order,count )
 		Endif
 		
 		Local n:=order*count
@@ -801,7 +785,7 @@ Class Canvas
 		Local vs:=image.Vertices
 		Local ts:=image.TexCoords
 		
-		AddDrawOp( image.Shader,image.Material,image.BlendMode,image.TextureFilter,4,1 )
+		AddDrawOp( image.Shader,image.Material,image.BlendMode,4,1 )
 		
 		AddVertex( vs.min.x+tx,vs.min.y+ty,ts.min.x,ts.min.y )
 		AddVertex( vs.max.x+tx,vs.min.y+ty,ts.max.x,ts.min.y )
@@ -885,7 +869,7 @@ Class Canvas
 			Local image:=gpage.image
 			sx=image.Rect.min.x;sy=image.Rect.min.y
 			tw=image.Texture.Width;th=image.Texture.Height
-			AddDrawOp( image.Shader,image.Material,image.BlendMode,image.TextureFilter,4,i1-i0 )
+			AddDrawOp( image.Shader,image.Material,image.BlendMode,4,i1-i0 )
 			
 			For Local i:=i0 Until i1
 			
@@ -928,13 +912,12 @@ Class Canvas
 		Local lx:=_matrix.i.x * tx + _matrix.j.x * ty + _matrix.t.x
 		Local ly:=_matrix.i.y * tx + _matrix.j.y * ty + _matrix.t.y
 		
-		_vp=_lightVB.AddVertices( 4 )
+		_vp=Cast<Vertex2f Ptr>( _lightVB.AddVertices( 4 ) )
 		If Not _vp Return
 
 		Local op:=New LightOp
 		op.light=light
 		op.lightPos=New Vec2f( lx,ly )
-		op.textureFilter=light.TextureFilter<>TextureFilter.None ? light.TextureFilter Else _textureFilter
 		op.primOffset=_lightVB.Length-4
 		_lightOps.Push( op )
 		
@@ -1083,20 +1066,19 @@ Class Canvas
 
 			'render diffuse gbuffer
 			'
-			_device.RenderTarget=_gbuffers[0]
+			_device.RenderTarget=_gbrtargets[0]
 			
 			RenderDrawOps( 1 )
 			
 			'render normal gbuffer
 			'
-			_device.RenderTarget=_gbuffers[1]
+			_device.RenderTarget=_gbrtargets[1]
 			
 			RenderDrawOps( 2 )
 
 			'back to rendertarget
 			'			
-			_device.RenderTarget=_rtarget ? _rtarget.Texture Else Null
-		
+			_device.RenderTarget=_rtarget
 		Endif
 		
 		_drawVB.Clear()
@@ -1135,27 +1117,29 @@ Class Canvas
 
 			Local gbufferSize:=New Vec2i( 1920,1080 )
 			Local gbufferScale:=New Vec2f( 1 )/Cast<Vec2f>( gbufferSize )
-		
-			_gbuffers[0]=New Texture( gbufferSize.x,gbufferSize.y,PixelFormat.RGBA32,TextureFlags.Dynamic )
-			_gbuffers[1]=New Texture( gbufferSize.x,gbufferSize.y,PixelFormat.RGBA32,TextureFlags.Dynamic )
+			
+			For Local i:=0 Until 2
+				_gbuffers[i]=New Texture( gbufferSize.x,gbufferSize.y,PixelFormat.RGBA32,TextureFlags.Dynamic )
+				_gbrtargets[i]=New RenderTarget( New Texture[]( _gbuffers[i] ),Null )
+			Next
 
-			_uniforms.SetVector( "mx2_GBufferScale",gbufferScale )
-			_uniforms.SetTexture( "mx2_GBuffer0",_gbuffers[0] )
-			_uniforms.SetTexture( "mx2_GBuffer1",_gbuffers[1] )
+			_uniforms.SetVec2f( "GBufferScale",gbufferScale )
+			_uniforms.SetTexture( "GBuffer0",_gbuffers[0] )
+			_uniforms.SetTexture( "GBuffer1",_gbuffers[1] )
 			
 		Endif
 		
 		Validate()
 		
-		_uniforms.SetVector( "mx2_AmbientLight",_ambientLight )
+		_uniforms.SetVec4f( "AmbientLight",_ambientLight )
 		
-		_device.RenderTarget=_gbuffers[0]
+		_device.RenderTarget=_gbrtargets[0]
 		_device.Clear( Color.Black )
 			
-		_device.RenderTarget=_gbuffers[1]
+		_device.RenderTarget=_gbrtargets[1]
 		_device.Clear( New Color( .5,.5,0 ) )
 		
-		_device.RenderTarget=_rtarget ? _rtarget.Texture Else Null
+		_device.RenderTarget=_rtarget
 	End
 	
 	#rem monkeydoc Renders lighting and ends lighting mode.
@@ -1184,6 +1168,33 @@ Class Canvas
 		_lighting=False
 	End
 	
+	'***** INTERNAL *****
+	
+	#rem monkeydoc @hidden
+	#end	
+	Property GraphicsDevice:GraphicsDevice()
+		
+		If _lighting Return Null
+		
+		Flush()
+	
+		Return _device
+	End
+
+	#rem monkeydoc @hidden
+	#end
+	Property RenderMatrix:AffineMat3f()
+		
+		Return _rmatrix
+	End
+	
+	#rem monkeydoc @hidden
+	#end
+	Property RenderBounds:Recti()
+		
+		Return _rbounds
+	End
+	
 	Private
 	
 	Enum Dirty
@@ -1196,7 +1207,6 @@ Class Canvas
 		Field shader:Shader
 		Field material:UniformBlock
 		Field blendMode:BlendMode
-		Field textureFilter:TextureFilter
 		Field primOrder:Int
 		Field primCount:Int
 		Field primOffset:Int
@@ -1205,7 +1215,6 @@ Class Canvas
 	Class LightOp
 		Field light:Image
 		Field lightPos:Vec2f
-		Field textureFilter:TextureFilter
 		Field primOrder:Int
 		Field primOffset:Int
 	End
@@ -1221,8 +1230,9 @@ Class Canvas
 
 	Global _lighting:Bool=False
 	Global _gbuffers:=New Texture[2]
+	Global _gbrtargets:=New RenderTarget[2]
 
-	Field _rtarget:Image
+	Field _rtarget:RenderTarget
 	Field _device:GraphicsDevice
 	Field _uniforms:UniformBlock
 	
@@ -1234,7 +1244,6 @@ Class Canvas
 	Field _ambientLight:Color
 	
 	Field _blendMode:BlendMode
-	Field _textureFilter:TextureFilter
 	Field _font:Font
 	Field _alpha:Float
 	Field _color:Color
@@ -1279,8 +1288,8 @@ Class Canvas
 		inited=True
 
 		Local nquads:=MaxVertices/4
-		_quadIndices=New IndexBuffer( nquads*6 )
-		Local ip:=_quadIndices.AddIndices( nquads*6 )
+		_quadIndices=New IndexBuffer( IndexFormat.UINT16,nquads*6 )
+		Local ip:=Cast<UShort Ptr>( _quadIndices.AddIndices( nquads*6 ) )
 		For Local i:=0 Until nquads*4 Step 4
 			ip[0]=i
 			ip[1]=i+1
@@ -1291,30 +1300,34 @@ Class Canvas
 			ip+=6
 		Next
 		
-		_shadowVB=New VertexBuffer( MaxShadowVertices )
+		_shadowVB=New VertexBuffer( Vertex2fFormat.Instance,MaxShadowVertices )
 
 		_defaultFont=mojo.graphics.Font.Load( "font::DejaVuSans.ttf",16 )
 	End
 	
-	Method Init( rtarget:Image,device:GraphicsDevice )
+	Method Init( rtarget:RenderTarget,device:GraphicsDevice )
 		Init2()
 		
 		_rtarget=rtarget
 		_device=device
 
-		_device.RenderTarget=_rtarget ? _rtarget.Texture Else Null
+		_device.RenderTarget=_rtarget
 		
-		_uniforms=New UniformBlock
-		_device.SetUniformBlock( 0,_uniforms )
+		_device.CullMode=CullMode.None
+		_device.DepthFunc=DepthFunc.Always
+		_device.DepthMask=False
+		
+		_uniforms=New UniformBlock( 1 )
+		_device.BindUniformBlock( _uniforms )
 
-		_drawVB=New VertexBuffer( MaxVertices )
-		_lightVB=New VertexBuffer( MaxLights*4 )
-		_shadowVB=New VertexBuffer( 65536 )
+		_drawVB=New VertexBuffer( Vertex2fFormat.Instance,MaxVertices )
+		_lightVB=New VertexBuffer( Vertex2fFormat.Instance,MaxLights*4 )
+		_shadowVB=New VertexBuffer( Vertex2fFormat.Instance,65536 )
 		
 		_device.IndexBuffer=_quadIndices
 
 		_shader=Shader.GetShader( "null" )
-		_material=New UniformBlock
+		_material=New UniformBlock( 2 )
 		
 		_viewport=New Recti( 0,0,640,480 )
 		_ambientLight=Color.Black
@@ -1390,7 +1403,7 @@ Class Canvas
 	
 	'Drawing
 	'	
-	Method AddDrawOp( shader:Shader,material:UniformBlock,blendMode:BlendMode,textureFilter:TextureFilter,primOrder:int,primCount:Int )
+	Method AddDrawOp( shader:Shader,material:UniformBlock,blendMode:BlendMode,primOrder:int,primCount:Int )
 	
 		If _drawVB.Length+primCount*primOrder>_drawVB.Capacity
 			Flush()
@@ -1398,18 +1411,17 @@ Class Canvas
 		
 		If blendMode=BlendMode.None blendMode=_blendMode
 		
-		If textureFilter=TextureFilter.None textureFilter=_textureFilter
-		
-		If shader<>_drawOp.shader Or material<>_drawOp.material Or blendMode<>_drawOp.blendMode Or textureFilter<>_drawOp.textureFilter Or primOrder<>_drawOp.primOrder
+		If shader<>_drawOp.shader Or material<>_drawOp.material Or blendMode<>_drawOp.blendMode Or primOrder<>_drawOp.primOrder
 		
 			'pad quads so primOffset always on a 4 vert boundary
-			If primOrder=4 And _drawVB.Length & 3 _drawVB.AddVertices( 4-(_drawVB.Length&3) )
+			If primOrder=4 And _drawVB.Length & 3 
+				_drawVB.AddVertices( 4-(_drawVB.Length&3) )
+			Endif
 			
 			_drawOp=New DrawOp
 			_drawOp.shader=shader
 			_drawOp.material=material
 			_drawOp.blendMode=blendMode
-			_drawOp.textureFilter=textureFilter
 			_drawOp.primOrder=primOrder
 			_drawOp.primCount=primCount
 			_drawOp.primOffset=_drawVB.Length
@@ -1418,7 +1430,7 @@ Class Canvas
 			_drawOp.primCount+=primCount
 		Endif
 		
-		_vp=_drawVB.AddVertices( primOrder*primCount )
+		_vp=Cast<Vertex2f Ptr>( _drawVB.AddVertices( primOrder*primCount ) )
 	End
 	
 	Method Validate()
@@ -1443,13 +1455,13 @@ Class Canvas
 				_projMatrix=Mat4f.Ortho( 0,_rviewport.Width,_rviewport.Height,0,-1,1 ) * rmatrix
 			Endif
 			
-			_uniforms.SetMatrix( "mx2_ModelViewProjectionMatrix",_projMatrix )
+			_uniforms.SetMat4f( "ModelViewProjectionMatrix",_projMatrix )
 			
-			_uniforms.SetVector( "mx2_ViewportOrigin",_rviewport.Origin )
+			_uniforms.SetVec2f( "ViewportOrigin",_rviewport.Origin )
 			
-			_uniforms.SetVector( "mx2_ViewportSize",_rviewport.Size )
+			_uniforms.SetVec2f( "ViewportSize",_rviewport.Size )
 	
-			_uniforms.SetVector( "mx2_ViewportClip",_rviewportClip )
+			_uniforms.SetVec2f( "ViewportClip",_rviewportClip )
 			
 			_device.Viewport=_rviewport
 		
@@ -1481,8 +1493,7 @@ Class Canvas
 		
 			_device.Shader=shader
 			_device.BlendMode=op.blendMode
-			_device.TextureFilter=op.textureFilter
-			_device.SetUniformBlock( 1,op.material )
+			_device.BindUniformBlock( op.material )
 
 			Select op.primOrder
 			Case 4
@@ -1525,7 +1536,7 @@ Class Canvas
 				Local d:=lv.Dot( nv )+pd
 				If d<0 Continue
 				
-				Local tp:=_shadowVB.AddVertices( 9 )
+				Local tp:=Cast<Vertex2f Ptr>( _shadowVB.AddVertices( 9 ) )
 				If Not tp Exit
 			
 				Local hv:=(pv+tv)/2
@@ -1568,7 +1579,7 @@ Class Canvas
 				Continue
 #end				
 				_device.RenderPass=4
-				_device.RenderTarget=_gbuffers[0]
+				_device.RenderTarget=_gbrtargets[0]
 				_device.BlendMode=BlendMode.Opaque
 				_device.ColorMask=ColorMask.Alpha
 				_device.VertexBuffer=_shadowVB
@@ -1578,7 +1589,7 @@ Class Canvas
 				_device.Render( 3,_shadowVB.Length/3,0 )
 				
 				_device.RenderPass=5				
-				_device.RenderTarget=_rtarget ? _rtarget.Texture Else Null
+				_device.RenderTarget=_rtarget
 				_device.BlendMode=BlendMode.Additive
 				_device.ColorMask=ColorMask.All
 				_device.VertexBuffer=_lightVB
@@ -1590,8 +1601,7 @@ Class Canvas
 			Local light:=op.light
 			
 			_device.Shader=light.Shader
-			_device.TextureFilter=op.textureFilter
-			_device.SetUniformBlock( 1,light.Material )
+			_device.BindUniformBlock( light.Material )
 			
 			_device.Render( 4,1,op.primOffset )
 		

+ 167 - 0
modules/mojo/graphics/glexts/exts.txt

@@ -0,0 +1,167 @@
+/*
+
+Vendor: Google Inc.
+Version: OpenGL ES 2.0 (ANGLE 2.1.0.4b4cdff894f4)
+Renderer: ANGLE (NVIDIA Corporation GeForce GTX 970/PCIe/SSE2 OpenGL 4.5 compatibility)
+
+GL_OES_element_index_uint
+GL_OES_packed_depth_stencil
+GL_OES_get_program_binary
+GL_OES_rgb8_rgba8
+GL_EXT_texture_format_BGRA8888
+GL_EXT_read_format_bgra
+GL_OES_mapbuffer
+GL_EXT_map_buffer_range
+GL_EXT_color_buffer_half_float
+GL_OES_texture_half_float
+GL_OES_texture_half_float_linear
+GL_OES_texture_float
+GL_OES_texture_float_linear
+GL_EXT_texture_rg
+GL_EXT_texture_compression_dxt1
+GL_ANGLE_texture_compression_dxt3
+GL_ANGLE_texture_compression_dxt5
+GL_OES_compressed_ETC1_RGB8_texture
+GL_EXT_sRGB
+GL_ANGLE_depth_texture
+GL_OES_depth32
+GL_EXT_texture_storage
+GL_OES_texture_npot
+GL_EXT_draw_buffers
+GL_EXT_texture_filter_anisotropic
+GL_EXT_occlusion_query_boolean
+GL_NV_fence
+GL_EXT_disjoint_timer_query
+GL_EXT_blend_minmax
+GL_ANGLE_framebuffer_blit
+GL_ANGLE_framebuffer_multisample
+GL_ANGLE_instanced_arrays
+GL_OES_standard_derivatives
+GL_EXT_shader_texture_lod
+GL_EXT_frag_depth
+GL_OES_fbo_render_mipmap
+GL_EXT_debug_marker
+GL_EXT_unpack_subimage
+GL_NV_pack_subimage
+GL_OES_vertex_array_object
+GL_KHR_debug
+GL_CHROMIUM_bind_uniform_location
+GL_EXT_multisample_compatibility
+GL_CHROMIUM_framebuffer_mixed_samples
+
+*/
+
+/*
+
+Chrome Version 58.0.3029.110 (64-bit)
+
+Vendor: WebKit
+Version: OpenGL ES 2.0 (WebGL 1.0 (OpenGL ES 2.0 Chromium))
+Renderer: WebKit WebGL
+
+ANGLE_instanced_arrays
+GL_ANGLE_instanced_arrays
+EXT_blend_minmax
+GL_EXT_blend_minmax
+EXT_disjoint_timer_query
+GL_EXT_disjoint_timer_query
+EXT_frag_depth
+GL_EXT_frag_depth
+EXT_shader_texture_lod
+GL_EXT_shader_texture_lod
+EXT_sRGB
+GL_EXT_sRGB
+EXT_texture_filter_anisotropic
+GL_EXT_texture_filter_anisotropic
+WEBKIT_EXT_texture_filter_anisotropic
+GL_WEBKIT_EXT_texture_filter_anisotropic
+OES_element_index_uint
+GL_OES_element_index_uint
+OES_standard_derivatives
+GL_OES_standard_derivatives
+OES_texture_float
+GL_OES_texture_float
+OES_texture_float_linear
+GL_OES_texture_float_linear
+OES_texture_half_float
+GL_OES_texture_half_float
+OES_texture_half_float_linear
+GL_OES_texture_half_float_linear
+OES_vertex_array_object
+GL_OES_vertex_array_object
+WEBGL_compressed_texture_s3tc
+GL_WEBGL_compressed_texture_s3tc
+WEBKIT_WEBGL_compressed_texture_s3tc
+GL_WEBKIT_WEBGL_compressed_texture_s3tc
+WEBGL_debug_renderer_info
+GL_WEBGL_debug_renderer_info
+WEBGL_debug_shaders
+GL_WEBGL_debug_shaders
+WEBGL_depth_texture
+GL_WEBGL_depth_texture
+WEBKIT_WEBGL_depth_texture
+GL_WEBKIT_WEBGL_depth_texture
+WEBGL_draw_buffers
+GL_WEBGL_draw_buffers
+WEBGL_lose_context
+GL_WEBGL_lose_context
+WEBKIT_WEBGL_lose_context
+GL_WEBKIT_WEBGL_lose_context
+*/
+
+/*
+
+Firefox Nightly: 55.0a1 (2017-05-11) (64-bit)
+
+Vendor: Mozilla
+Version: OpenGL ES 2.0 (WebGL 1.0)
+Renderer: Mozilla
+
+ANGLE_instanced_arrays
+GL_ANGLE_instanced_arrays
+EXT_blend_minmax
+GL_EXT_blend_minmax
+EXT_color_buffer_half_float
+GL_EXT_color_buffer_half_float
+EXT_frag_depth
+GL_EXT_frag_depth
+EXT_shader_texture_lod
+GL_EXT_shader_texture_lod
+EXT_texture_filter_anisotropic
+GL_EXT_texture_filter_anisotropic
+EXT_disjoint_timer_query
+GL_EXT_disjoint_timer_query
+OES_element_index_uint
+GL_OES_element_index_uint
+OES_standard_derivatives
+GL_OES_standard_derivatives
+OES_texture_float
+GL_OES_texture_float
+OES_texture_float_linear
+GL_OES_texture_float_linear
+OES_texture_half_float
+GL_OES_texture_half_float
+OES_texture_half_float_linear
+GL_OES_texture_half_float_linear
+OES_vertex_array_object
+GL_OES_vertex_array_object
+WEBGL_color_buffer_float
+GL_WEBGL_color_buffer_float
+WEBGL_compressed_texture_s3tc
+GL_WEBGL_compressed_texture_s3tc
+WEBGL_debug_renderer_info
+GL_WEBGL_debug_renderer_info
+WEBGL_depth_texture
+GL_WEBGL_depth_texture
+WEBGL_draw_buffers
+GL_WEBGL_draw_buffers
+WEBGL_lose_context
+GL_WEBGL_lose_context
+MOZ_WEBGL_lose_context
+GL_MOZ_WEBGL_lose_context
+MOZ_WEBGL_compressed_texture_s3tc
+GL_MOZ_WEBGL_compressed_texture_s3tc
+MOZ_WEBGL_depth_texture
+GL_MOZ_WEBGL_depth_texture
+*/
+

+ 50 - 0
modules/mojo/graphics/glexts/glexts.cpp

@@ -0,0 +1,50 @@
+
+#include "glexts.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <EGL/egl.h>
+
+namespace bbGLexts{
+
+	bool GL_draw_buffers;
+	bool GL_texture_float;
+	bool GL_texture_half_float;
+	bool GL_depth_texture;
+
+	void(*glDrawBuffers)( int n,const GLint *bufs );
+	
+	void init(){
+	
+		const char *exts=(const char*)glGetString( GL_EXTENSIONS );
+		char *buf=(char*)malloc( strlen( exts )+3 );
+
+		buf[0]=' ';		
+		strcpy( buf+1,exts );
+		strcat( buf+1," " );
+		
+		if( GL_draw_buffers=strstr( buf," GL_EXT_draw_buffers " ) ){
+			
+			glDrawBuffers=(void(*)(int,const GLint*)) eglGetProcAddress( "glDrawBuffersEXT" );
+			
+		}else if( GL_draw_buffers=strstr( buf," WEBGL_draw_buffers " ) ){
+		
+			glDrawBuffers=(void(*)(int,const GLint*)) eglGetProcAddress( "glDrawBuffersWEBGL" );
+		}
+		
+		GL_texture_float=strstr( buf,"_texture_float" );
+		
+		GL_texture_half_float=strstr( buf,"_texture_half_float" );
+		
+		GL_depth_texture=strstr( buf,"_depth_texture" );
+			
+		printf( "GL_draw_buffers=%i\n",int( GL_draw_buffers ) );
+		printf( "GL_texture_float=%i\n",int( GL_texture_float ) );
+		printf( "GL_texture_half_float=%i\n",int( GL_texture_half_float ) );
+		printf( "GL_depth_texture=%i\n",int( GL_depth_texture ) );
+		
+		fflush( stdout );
+	}
+	
+}

+ 15 - 0
modules/mojo/graphics/glexts/glexts.h

@@ -0,0 +1,15 @@
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+namespace bbGLexts{
+
+	extern bool GL_draw_buffers;
+	extern bool GL_texture_float;
+	extern bool GL_texture_half_float;
+	extern bool GL_depth_texture;
+
+	extern void(*glDrawBuffers)( int n,const GLint *bufs );
+
+	void init();
+}

+ 58 - 0
modules/mojo/graphics/glexts/glexts.monkey2

@@ -0,0 +1,58 @@
+
+Namespace mojo.graphics.glexts
+
+#If __TARGET__="windows" Or __TARGET__="emscripten"
+
+#Import "glexts.cpp"
+#Import "glexts.h"
+
+#Endif
+
+Const GL_HALF_FLOAT:Int=$8D61
+
+Const GL_MAX_COLOR_ATTACHMENTS:=$8CDF
+
+'Const GL_COLOR_ATTACHMENT0:Int=$8cE0
+Const GL_COLOR_ATTACHMENT1:Int=$8CE1
+Const GL_COLOR_ATTACHMENT2:Int=$8CE2
+Const GL_COLOR_ATTACHMENT3:Int=$8CE3
+Const GL_COLOR_ATTACHMENT4:Int=$8CE4
+Const GL_COLOR_ATTACHMENT5:Int=$8CE5
+Const GL_COLOR_ATTACHMENT6:Int=$8CE6
+Const GL_COLOR_ATTACHMENT7:Int=$8CE7
+Const GL_COLOR_ATTACHMENT8:Int=$8CE8
+Const GL_COLOR_ATTACHMENT9:Int=$8CE9
+Const GL_COLOR_ATTACHMENT10:Int=$8CEA
+Const GL_COLOR_ATTACHMENT11:Int=$8CEB
+Const GL_COLOR_ATTACHMENT12:Int=$8CEC
+Const GL_COLOR_ATTACHMENT13:Int=$8CED
+Const GL_COLOR_ATTACHMENT14:Int=$8CEE
+Const GL_COLOR_ATTACHMENT15:Int=$8CEF
+
+#If __TARGET__="windows" Or __TARGET__="emscripten"
+
+Extern
+
+Const GL_draw_buffers:Bool="bbGLexts::GL_draw_buffers"
+Const GL_texture_float:Bool="bbGLexts::GL_texture_float"
+Const GL_texture_half_float:bool="bbGLexts::GL_texture_half_float"
+Const GL_depth_texture:bool="bbGLexts::GL_depth_texture"
+
+Function InitGLexts()="bbGLexts::init"
+Function glDrawBuffers( n:Int,bufs:GLenum Ptr )="bbGLexts::glDrawBuffers"
+
+#Else
+
+Const GL_draw_buffers:Bool=False
+Const GL_texture_float:Bool=False
+Const GL_texture_half_float:bool=False
+Const GL_depth_texture:bool=False
+
+Function InitGLexts()
+End
+
+Function glDrawBuffers( n:Int,bufs:GLenum Ptr )
+	RuntimeError( "glDrawBuffers unsupported" )
+End
+
+#Endif

+ 124 - 0
modules/mojo/graphics/glexts/test.monkey2

@@ -0,0 +1,124 @@
+
+Namespace myapp
+
+#Import "<std>"
+#Import "<mojo>"
+
+Using std..
+Using mojo..
+
+Class MyWindow Extends GLWindow
+
+	Method New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=Null )
+
+		Super.New( title,width,height,flags )
+		
+		BeginGL()
+		
+		Print glGetString( GL_VENDOR )
+		Print glGetString( GL_VERSION )
+		Print glGetString( GL_RENDERER )
+		Print glGetString( GL_EXTENSIONS ).Replace( " ","~n" )
+		
+		Print ""
+
+		InitGLexts()
+		
+		glCheck()
+		
+		Local gltexs:=New GLuint[4]
+		
+		glGenTextures( gltexs.Length,gltexs.Data )
+		
+		glBindTexture( GL_TEXTURE_2D,gltexs[0] )
+		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST )
+		glTexImage2D( GL_TEXTURE_2D,0,GL_RGBA,640,480,0,GL_RGBA,GL_HALF_FLOAT,Null )
+'		glTexImage2D( GL_TEXTURE_2D,0,GL_RGBA,640,480,0,GL_RGBA,GL_UNSIGNED_BYTE,Null )
+		Print "texture[0]="+gltexs[0]
+		glCheck()
+		
+		glBindTexture( GL_TEXTURE_2D,gltexs[1] )
+		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST )
+		glTexImage2D( GL_TEXTURE_2D,0,GL_RGBA,640,480,0,GL_RGBA,GL_HALF_FLOAT,Null )
+'		glTexImage2D( GL_TEXTURE_2D,0,GL_RGBA,640,480,0,GL_RGBA,GL_UNSIGNED_BYTE,Null )
+		Print "texture[1]="+gltexs[1]
+		glCheck()
+		
+		glBindTexture( GL_TEXTURE_2D,gltexs[2] )
+		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST )
+		glTexImage2D( GL_TEXTURE_2D,0,GL_RGBA,640,480,0,GL_RGBA,GL_HALF_FLOAT,Null )
+'		glTexImage2D( GL_TEXTURE_2D,0,GL_RGBA,640,480,0,GL_RGBA,GL_UNSIGNED_BYTE,Null )
+		Print "texture[2]="+gltexs[2]
+		glCheck()
+		
+		glBindTexture( GL_TEXTURE_2D,gltexs[3] )
+		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+		glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST )
+		glTexImage2D( GL_TEXTURE_2D,0,GL_DEPTH_COMPONENT,640,480,0,GL_DEPTH_COMPONENT,GL_UNSIGNED_INT,Null )
+		Print "texture[3]="+gltexs[3]
+		glCheck()
+		
+		glBindTexture( GL_TEXTURE_2D,0 )
+		
+		Local glfb:GLuint
+		
+		glGenFramebuffers( 1,Varptr glfb )
+		glCheck()
+		
+		glBindFramebuffer( GL_FRAMEBUFFER,glfb )
+		glCheck()
+		
+		Local i:Int
+		glGetIntegerv( GL_MAX_COLOR_ATTACHMENTS,Varptr i )
+		Print "MAX_COLOR_ATTACHMENTS="+i
+		
+		glFramebufferTexture2D( GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,gltexs[0],0 )
+		glFramebufferTexture2D( GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT1,GL_TEXTURE_2D,gltexs[1],0 )
+		glFramebufferTexture2D( GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT2,GL_TEXTURE_2D,gltexs[2],0 )
+		glFramebufferTexture2D( GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,gltexs[3],0 )
+		glCheck()
+		
+		Assert( glCheckFramebufferStatus( GL_FRAMEBUFFER )=GL_FRAMEBUFFER_COMPLETE,"Incomplete framebuffer" )
+		
+		glCheck()
+		
+		glBindFramebuffer( GL_FRAMEBUFFER,0 )
+		
+		glCheck()
+		
+		Print "TEST COMPLETE!"
+		
+		EndGL()
+	End
+
+	Method OnRender( canvas:Canvas ) Override
+	
+		App.RequestRender()
+	
+		canvas.DrawText( "Hello World!",Width/2,Height/2,.5,.5 )
+	End
+	
+End
+
+Function Main()
+
+'	libc.setenv( "SDL_ANGLE_RENDERER","OPENGL",0 )
+	libc.setenv( "SDL_ANGLE_RENDERER","D3D11",0 )
+
+	Local config:=New StringMap<String>
+	
+	config["GL_context_profile"]="es"
+	config["GL_context_major_version"]=2
+	config["GL_context_minor_version"]=0
+
+	config["GL_depth_buffer_enabled"]=1
+
+	New AppInstance( config )
+	
+	New MyWindow
+	
+	App.Run()
+End

+ 64 - 45
modules/mojo/graphics/glutil.monkey2

@@ -3,7 +3,7 @@ Namespace mojo.graphics.glutil
 
 Private
 
-Global tmpi:Int
+Global bindings:=New IntStack
 
 Public
 
@@ -16,73 +16,82 @@ Global glGraphicsSeq:Int=1
 Function glCheck()
 	Local err:=glGetError()
 	If err=GL_NO_ERROR Return
-	Assert( False,"GL ERROR! err="+err )
+	RuntimeError( "GL ERROR! err="+err )
 End
 
 #rem monkeydoc @hidden
 #end
-Function glFormat:GLenum( format:PixelFormat )
-	Select format
-	Case PixelFormat.A8 Return GL_ALPHA
-	Case PixelFormat.I8 Return GL_LUMINANCE
-	Case PixelFormat.IA16 Return GL_LUMINANCE_ALPHA
-	Case PixelFormat.RGB24 Return GL_RGB
-	Case PixelFormat.RGBA32 Return GL_RGBA
-	End
-	Assert( False,"Invalidate PixelFormat" )
-	Return GL_RGBA
-End
-
-#rem monkeydoc @hidden
-#end
-Function glPushTexture2d:Void( tex:Int )
-	glGetIntegerv( GL_TEXTURE_BINDING_2D,Varptr tmpi )
-	glBindTexture( GL_TEXTURE_2D,tex )
-End
+Function glPushTexture:Void( target:GLenum,texture:GLuint )
 
-#rem monkeydoc @hidden
-#end
-Function glPopTexture2d:Void()
-	glBindTexture( GL_TEXTURE_2D,tmpi )
-End
+	Assert( target=GL_TEXTURE_2D Or target=GL_TEXTURE_CUBE_MAP )
+	
+	Local binding:Int
+	glGetIntegerv( target=GL_TEXTURE_2D ? GL_TEXTURE_BINDING_2D Else GL_TEXTURE_BINDING_CUBE_MAP,Varptr binding )
 
-#rem monkeydoc @hidden
-#end
-Function glPushArrayBuffer( buf:Int )
-	glGetIntegerv( GL_ARRAY_BUFFER_BINDING,Varptr tmpi )
-	glBindBuffer( GL_ARRAY_BUFFER,buf )
+	bindings.Push( binding )
+	bindings.Push( target )
+	
+	glBindTexture( target,texture )
 End
 
 #rem monkeydoc @hidden
 #end
-Function glPopArrayBuffer()
-	glBindBuffer( GL_ARRAY_BUFFER,tmpi )
+Function glPopTexture:Void()
+	
+	Local target:=bindings.Pop()
+	Assert( target=GL_TEXTURE_2D Or target=GL_TEXTURE_CUBE_MAP )
+	
+	glBindTexture( target,bindings.Pop() )
 End
 
 #rem monkeydoc @hidden
 #end
-Function glPushElementArrayBuffer( buf:Int )
-	glGetIntegerv( GL_ELEMENT_ARRAY_BUFFER_BINDING,Varptr tmpi )
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,buf )
+Function glPushBuffer( target:GLenum,buf:GLuint )
+	
+	Assert( target=GL_ARRAY_BUFFER Or target=GL_ELEMENT_ARRAY_BUFFER )
+	
+	Local binding:Int
+	glGetIntegerv( target=GL_ARRAY_BUFFER ? GL_ARRAY_BUFFER_BINDING Else GL_ELEMENT_ARRAY_BUFFER_BINDING,Varptr binding )
+	
+	bindings.Push( binding )
+	bindings.Push( target )
+	
+	glBindBuffer( target,buf )
 End
 
 #rem monkeydoc @hidden
 #end
-Function glPopElementArrayBuffer()
-	glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,tmpi )
+Function glPopBuffer()
+	
+	Local target:=bindings.Pop()
+	Assert( target=GL_ARRAY_BUFFER Or target=GL_ELEMENT_ARRAY_BUFFER )
+	
+	glBindBuffer( target,bindings.Pop() )
 End
 
 #rem monkeydoc @hidden
 #end
-Function glPushFramebuffer:Void( framebuf:Int )
-	glGetIntegerv( GL_FRAMEBUFFER_BINDING,Varptr tmpi )
-	glBindFramebuffer( GL_FRAMEBUFFER,framebuf )
+Function glPushFramebuffer:Void( target:GLenum,framebuf:GLuint )
+	
+	Assert( target=GL_FRAMEBUFFER )
+	
+	Local binding:Int
+	glGetIntegerv( GL_FRAMEBUFFER_BINDING,Varptr binding )
+	
+	bindings.Push( framebuf )
+	bindings.Push( target )
+	
+	glBindFramebuffer( target,framebuf )
 End
 
 #rem monkeydoc @hidden
 #end
 Function glPopFramebuffer:Void()
-	glBindFramebuffer( GL_FRAMEBUFFER,tmpi )
+	
+	Local target:=bindings.Pop()
+	Assert( target=GL_FRAMEBUFFER )
+	
+	glBindFramebuffer( target,bindings.Pop() )
 End
 
 #rem monkeydoc @hidden
@@ -90,6 +99,7 @@ End
 Function glCompile:Int( type:Int,source:String )
 
 	source="
+	#extension GL_EXT_draw_buffers : require	
 	#ifdef GL_ES
 	#ifdef GL_FRAGMENT_PRECISION_HIGH
 	precision highp float;
@@ -102,12 +112,17 @@ Function glCompile:Int( type:Int,source:String )
 	Local shader:=glCreateShader( type )
 	glShaderSourceEx( shader,source )
 	glCompileShader( shader )
-	glGetShaderiv( shader,GL_COMPILE_STATUS,Varptr tmpi )
-	If Not tmpi
+	
+	Local status:Int
+	glGetShaderiv( shader,GL_COMPILE_STATUS,Varptr status )
+	If Not status
+		
 		Local lines:=source.Split( "~n" )
+		
 		For Local i:=0 Until lines.Length
 			Print (i+1)+":~t"+lines[i]
 		Next
+		
 		RuntimeError( "Failed to compile fragment shader:"+glGetShaderInfoLogEx( shader ) )
 	Endif
 	Return shader
@@ -117,6 +132,10 @@ End
 #end
 Function glLink:Void( program:Int )
 	glLinkProgram( program )
-	glGetProgramiv( program,GL_LINK_STATUS,Varptr tmpi )
-	If Not tmpi RuntimeError( "Failed to link program:"+glGetProgramInfoLogEx( program ) )
+
+	Local status:Int
+	glGetProgramiv( program,GL_LINK_STATUS,Varptr status )
+	If Not status
+		RuntimeError( "Failed to link program:"+glGetProgramInfoLogEx( program ) )
+	Endif
 End

+ 222 - 72
modules/mojo/graphics/graphicsdevice.monkey2

@@ -15,10 +15,10 @@ Blend modes are used with the [[Canvas.BlendMode]] property.
 #end
 Enum BlendMode
 	None=0
-	Opaque
-	Alpha
-	Additive
-	Multiply
+	Opaque=1
+	Alpha=2
+	Additive=3
+	Multiply=4
 End
 
 #rem monkeydoc @hidden Color mask values.
@@ -41,6 +41,23 @@ Enum ColorMask
 	All=15
 End
 
+Enum DepthFunc
+	Never=0
+	Less=1
+	Equal=2
+	LessEqual=3
+	Greater=4
+	NotEqual=5
+	GreaterEqual=6
+	Always=7
+End
+
+Enum CullMode
+	None=0
+	Back=1
+	Front=2
+End
+
 #rem monkeydoc @hidden
 #end
 Class GraphicsDevice
@@ -71,17 +88,17 @@ Class GraphicsDevice
 	
 	'***** PUBLIC *****
 	
-	Property RenderTarget:Texture()
+	Property RenderTarget:RenderTarget()
 
 		Return _rtarget
 	
-	Setter( renderTarget:Texture )
+	Setter( renderTarget:RenderTarget )
 
 		FlushTarget()
 	
 		_rtarget=renderTarget
 		
-		_rtargetSize=_rtarget ? _rtarget.Rect.Size Else _deviceSize
+		_rtargetSize=_rtarget ? _rtarget.Size Else _deviceSize
 		
 		_dirty|=Dirty.RenderTarget|Dirty.Viewport|Dirty.Scissor
 	End
@@ -123,6 +140,28 @@ Class GraphicsDevice
 		_dirty|=Dirty.ColorMask
 	End
 	
+	Property DepthMask:Bool()
+		
+		Return _depthMask
+	
+	Setter( depthMask:Bool )
+		
+		_depthMask=depthMask
+		
+		_dirty|=Dirty.DepthMask
+	End
+	
+	Property DepthFunc:DepthFunc()
+		
+		Return _depthFunc
+	
+	Setter( depthFunc:DepthFunc )
+		
+		_depthFunc=depthFunc
+		
+		_dirty2|=Dirty.DepthFunc
+	End
+	
 	Property BlendMode:BlendMode()
 	
 		Return _blendMode
@@ -134,17 +173,17 @@ Class GraphicsDevice
 		_dirty2|=Dirty.BlendMode
 	End
 	
-	Property TextureFilter:TextureFilter()
-	
-		return _textureFilter
-	
-	Setter( filter:TextureFilter )
+	Property CullMode:CullMode()
+		
+		Return _cullMode
 	
-		_textureFilter=filter
+	Setter( cullMode:CullMode )
+		
+		_cullMode=cullMode
 		
-		_dirty2|=Dirty.TextureFilter
+		_dirty2|=Dirty.CullMode
 	End
-	
+
 	Property VertexBuffer:VertexBuffer()
 	
 		Return _vertexBuffer
@@ -189,14 +228,14 @@ Class GraphicsDevice
 		_dirty2|=Dirty.Shader
 	End
 	
-	Method SetUniformBlock( id:Int,ublock:UniformBlock )
+	Method BindUniformBlock( ublock:UniformBlock )
 	
-		_ublocks[id]=ublock
+		_ublocks[ublock.Name]=ublock
 	End
 	
-	Method GetUniformBlock:UniformBlock( id:Int )
+	Method GetUniformBlock:UniformBlock( block:Int )
 	
-		Return _ublocks[id]
+		Return _ublocks[block]
 	End
 	
 	Method CopyPixmap:Pixmap( rect:Recti )
@@ -212,24 +251,44 @@ Class GraphicsDevice
 		Return pixmap
 	End
 
-	Method Clear( color:Color )
+	Method Clear( color:Color,depth:Float=1 )',clearColor:Bool=True,clearDepth:Bool=True )
+		
+		glCheck()
 	
 		Validate()
 		
-		glClearColor( color.r,color.g,color.b,color.a )
+		glCheck()
 		
 		If Not _scissorTest glEnable( GL_SCISSOR_TEST )
 		
-		glClear( GL_COLOR_BUFFER_BIT )
+		Local mask:GLbitfield
+		
+		If _colorMask
+			glClearColor( color.r,color.g,color.b,color.a )
+			mask|=GL_COLOR_BUFFER_BIT
+		Endif
+		
+		If _depthMask
+			glClearDepthf( depth )
+			mask|=GL_DEPTH_BUFFER_BIT
+		Endif
+		
+		glClear( mask )
 		
 		If Not _scissorTest glDisable( GL_SCISSOR_TEST )
 		
 		_modified=true
+
+		glCheck()
 	End
 	
 	Method Render( order:Int,count:Int,offset:Int=0 )
+		
+		glCheck()
 	
 		Validate2()
+		
+		glCheck()
 	
 		Local n:=order*count
 	
@@ -244,44 +303,76 @@ Class GraphicsDevice
 		End
 		
 		_modified=true
+
+		glCheck()
 	End
-	
+
 	Method RenderIndexed( order:Int,count:Int,offset:Int=0 )
-	
+		
+		glCheck()
+		
 		Validate2()
-
+		
+		glCheck()
+		
 		Local n:=order*count
+		
+		Local gltype:GLenum,pitch:Int
+		
+		Select _indexBuffer.Format
+		Case IndexFormat.UINT16
+'			For Local i:=0 Until n
+'				If Cast<UShort Ptr>( _indexBuffer.Data )[i]>=_vertexBuffer.Length DebugStop()
+'			Next
+			gltype=GL_UNSIGNED_SHORT
+			pitch=2
+		Case IndexFormat.UINT32
+'			For Local i:=0 Until n
+'				If Cast<UInt Ptr>( _indexBuffer.Data )[i]>=_vertexBuffer.Length DebugStop()
+'			Next
+			gltype=GL_UNSIGNED_INT
+			pitch=4
+		Default 
+			RuntimeError( "Invalid index format" )
+		End
 
-		Local p:=Cast<UShort Ptr>( offset*2 )
+		Local p:=Cast<UByte Ptr>( offset * pitch )
 		
 		Select order
-		Case 1 glDrawElements( GL_POINTS,n,GL_UNSIGNED_SHORT,p )
-		Case 2 glDrawElements( GL_LINES,n,GL_UNSIGNED_SHORT,p )
-		Case 3 glDrawElements( GL_TRIANGLES,n,GL_UNSIGNED_SHORT,p )
+		Case 1 glDrawElements( GL_POINTS,n,gltype,p )
+		Case 2 glDrawElements( GL_LINES,n,gltype,p )
+		Case 3 glDrawElements( GL_TRIANGLES,n,gltype,p )
 		Default
 			For Local i:=0 Until count
-				glDrawElements( GL_TRIANGLE_FAN,order,GL_UNSIGNED_SHORT,p+i*order )
+				glDrawElements( GL_TRIANGLE_FAN,order,gltype,p+i*order*pitch )
 			Next
 		End
+
+		_modified=True
 		
-		_modified=true
+		glCheck()
 	End
 	
 	Private
 	
 	Enum Dirty
 		'
+		'stuff that affects Clear()
 		RenderTarget=		$0001
 		Viewport=			$0002
 		Scissor=			$0004
 		ColorMask=			$0008
+		DepthMask=			$0010
 		'
-		BlendMode=			$0010
-		VertexBuffer=		$0020
-		IndexBuffer=		$0040
-		Shader=				$0080
-		TextureFilter=		$0100
-		All=				$01ff
+		'stuff that affects Render()
+		DepthFunc=			$0100
+		BlendMode=			$0200
+		CullMode=			$0400
+		VertexBuffer=		$0800
+		IndexBuffer=		$1000
+		Shader=				$2000
+		'
+		All=				$ffff
 		'
 	End
 	
@@ -289,32 +380,37 @@ Class GraphicsDevice
 	Field _dirty2:Dirty
 	Field _modified:Bool
 	
-	Field _rtarget:Texture
+	Field _rtarget:RenderTarget
 	Field _rtargetSize:Vec2i
 	Field _deviceSize:Vec2i
 	Field _viewport:Recti
 	Field _scissor:Recti
 	Field _scissorTest:Bool
 	Field _colorMask:ColorMask
+	Field _depthMask:Bool
+	Field _depthFunc:DepthFunc
 	Field _blendMode:BlendMode
-	Field _textureFilter:TextureFilter
+	Field _cullMode:CullMode
 	Field _vertexBuffer:VertexBuffer
 	Field _indexBuffer:IndexBuffer
 	Field _ublocks:=New UniformBlock[4]
 	Field _shader:Shader
 	Field _rpass:Int
 	
-	Global _seq:Int
+	Global _glSeq:Int
 	Global _current:GraphicsDevice
 	Global _defaultFbo:GLint
 	
 	Method Init()
+		_depthFunc=DepthFunc.Less
+		_blendMode=BlendMode.Alpha
+		_cullMode=CullMode.Back
 		_colorMask=ColorMask.All
+		_depthMask=True
 	End
 	
-	Function InitGLState()
-		glDisable( GL_CULL_FACE )
-		glDisable( GL_DEPTH_TEST )
+	Function InitGL()
+		InitGLexts()
 		glGetIntegerv( GL_FRAMEBUFFER_BINDING,Varptr _defaultFbo )
 	End
 	
@@ -323,38 +419,42 @@ Class GraphicsDevice
 		_modified=False
 		If _rtarget
 			Validate()
-			_rtarget.Modified( _viewport & _scissor )
+'			_rtarget.Modified( _viewport & _scissor )
 		Endif
 	End
 	
 	Method Validate()
 
-		If _seq<>glGraphicsSeq
-			_seq=glGraphicsSeq
+		If _glSeq<>glGraphicsSeq
+			_glSeq=glGraphicsSeq
 			_current=Null
-			InitGLState()
+			InitGL()
 		Endif
 		
-		If _current=Self 
-			If Not _dirty Return
-		Else
+		If _current<>Self
 			If _current _current.FlushTarget()
 			_current=Self
 			_dirty=Dirty.All
+			_dirty2=Dirty.All
+		Else
+			If Not _dirty Return
 		Endif
 		
 		If _dirty & Dirty.RenderTarget
-		
+			
 			If _rtarget
-				glBindFramebuffer( GL_FRAMEBUFFER,_rtarget.GLFramebuffer )
+				_rtarget.Bind()
 			Else
 				glBindFramebuffer( GL_FRAMEBUFFER,_defaultFbo )
+				Local bufs:GLenum=GL_BACK
+				glDrawBuffers( 1,Varptr bufs )
+'				glReadBuffer( GL_BACK )
 			Endif
 
 		Endif
 	
 		If _dirty & Dirty.Viewport
-		
+			
 			If _rtarget
 				glViewport( _viewport.X,_viewport.Y,_viewport.Width,_viewport.Height )
 			Else
@@ -368,6 +468,7 @@ Class GraphicsDevice
 			Local scissor:=_scissor & _viewport
 			
 			_scissorTest=scissor<>_viewport
+			
 			If _scissorTest glEnable( GL_SCISSOR_TEST ) Else glDisable( GL_SCISSOR_TEST )
 			
 			If _rtarget
@@ -389,56 +490,105 @@ Class GraphicsDevice
 		
 		Endif
 		
+		If _dirty & Dirty.DepthMask
+			
+			glDepthMask( _depthMask )
+			
+		Endif
+		
 		_dirty=Null
 	End
 	
 	Method Validate2()
-	
+		
 		Validate()
 		
+		If _dirty2 & Dirty.DepthFunc
+			
+			If _depthFunc=DepthFunc.Always
+				glDisable( GL_DEPTH_TEST )
+			Else
+				glEnable( GL_DEPTH_TEST )
+				Select _depthFunc
+				Case DepthFunc.Never
+					glDepthFunc( GL_NEVER )
+				Case DepthFunc.Less
+					glDepthFunc( GL_LESS )
+				Case DepthFunc.Equal
+					glDepthFunc( GL_EQUAL )
+				Case DepthFunc.LessEqual
+					glDepthFunc( GL_LEQUAL )
+				Case DepthFunc.Greater
+					glDepthFunc( GL_GREATER )
+				Case DepthFunc.NotEqual
+					glDepthFunc( GL_NOTEQUAL )
+				Case DepthFunc.GreaterEqual
+					glDepthFunc( GL_GEQUAL )
+				Default
+					RuntimeError( "Invalid DepthFunc" )
+				End
+			Endif
+		
+		Endif
+		
 		If _dirty2 & Dirty.BlendMode
-
-			Select _blendMode
-			Case BlendMode.Opaque
+			
+			If _blendMode=BlendMode.Opaque
 				glDisable( GL_BLEND )
-			Case BlendMode.Alpha
-				glEnable( GL_BLEND )
-				glBlendFunc( GL_ONE,GL_ONE_MINUS_SRC_ALPHA )
-			Case BlendMode.Additive
-				glEnable( GL_BLEND )
-				glBlendFunc( GL_ONE,GL_ONE )
-			Case BlendMode.Multiply
+			Else
 				glEnable( GL_BLEND )
-				glBlendFunc( GL_DST_COLOR,GL_ONE_MINUS_SRC_ALPHA )
-			Default
-				glDisable( GL_BLEND )
-			End
+				Select _blendMode
+				Case BlendMode.Alpha
+					glBlendFunc( GL_ONE,GL_ONE_MINUS_SRC_ALPHA )
+				Case BlendMode.Additive
+					glBlendFunc( GL_ONE,GL_ONE )
+				Case BlendMode.Multiply
+					glBlendFunc( GL_DST_COLOR,GL_ONE_MINUS_SRC_ALPHA )
+				Default
+					RuntimeError( "Invalid BlendMode" )
+				End
+			Endif
 
 		Endif
 		
+		If _dirty2 & Dirty.CullMode
+			
+			If _cullMode=CullMode.None
+				glDisable( GL_CULL_FACE )
+			Else
+				glEnable( GL_CULL_FACE )
+				Select _cullMode
+				Case CullMode.Back
+					glCullFace( GL_FRONT )
+				Case CullMode.Front
+					glCullFace( GL_BACK )
+				Default
+					RuntimeError( "Invalid CullMode" )
+				End
+			Endif
+		
+		Endif
+		
 		If _dirty2 & Dirty.VertexBuffer
 		
 			 _vertexBuffer.Bind()
-			
 		Endif
 
 		If _dirty2 & Dirty.IndexBuffer
 		
 			If _indexBuffer _indexBuffer.Bind()
-			
 		Endif
 		
 		If _dirty2 & Dirty.Shader
 		
 			_shader.Bind( _rpass )
-
 		Endif
 		
 		_vertexBuffer.Validate()
 		
 		If _indexBuffer _indexBuffer.Validate()
 
-		_shader.ValidateUniforms( _rpass,_ublocks,_textureFilter )
+		_shader.ValidateUniforms( _rpass,_ublocks )
 		
 		_dirty2=Null
 	End

+ 34 - 38
modules/mojo/graphics/image.monkey2

@@ -23,12 +23,17 @@ Images also have several properties that affect how they are rendered, including
 * Scale - a fixed scale factor for the image.
 * BlendMode - controls how the image is blended with the contents of the canvas. If this is null, this property is ignored and the current canvas blendmode is used to render the image instead.
 * Color - when rendering an image to a canvas, this property is multiplied by the current canvas color and the result is multiplied by actual image pixel colors to achieve the final color to be rendered.
-* TextureFilter - controls how image texels are sampled. Set to TextureFilter.None for coolio retro style graphics, or TextureFilter.Mipmap for fullon super smoothing.
-
 
 #end
 Class Image Extends Resource
 
+	#rem Default texture flags
+	
+	Default texture flags to use when TextureFlags.UseDefaults is specified as a parameter.
+	
+	#end
+	Global DefaultTextureFlags:TextureFlags=TextureFlags.Filter|TextureFlags.Mipmap
+
 	#rem monkeydoc Creates a new Image.
 	
 	New( pixmap,... ) Creates an image from an existing pixmap.
@@ -54,29 +59,35 @@ Class Image Extends Resource
 	@param width,height Image size.
 	
 	#end	
-	Method New( pixmap:Pixmap,textureFlags:TextureFlags=Null,shader:Shader=Null )
+	Method New( pixmap:Pixmap,textureFlags:TextureFlags=TextureFlags.UseDefault,shader:Shader=Null )
+	
+		If textureFlags=TextureFlags.UseDefault textureFlags=DefaultTextureFlags
 	
 		Local texture:=New Texture( pixmap,textureFlags )
 		
-		Init( texture,texture.Rect,shader )
+		Init( texture,shader )
 		
 		AddDependancy( texture )
 	End
 
-	Method New( width:Int,height:Int,textureFlags:TextureFlags=Null,shader:Shader=Null )
+	Method New( width:Int,height:Int,textureFlags:TextureFlags=TextureFlags.UseDefault,shader:Shader=Null )
+	
+		If textureFlags=TextureFlags.UseDefault textureFlags=DefaultTextureFlags
 	
 		Local texture:=New Texture( width,height,PixelFormat.RGBA32,textureFlags )
 		
-		Init( texture,texture.Rect,shader )
+		Init( texture,shader )
 		
 		AddDependancy( texture )
 	End
 
-	Method New( width:Int,height:Int,format:PixelFormat,textureFlags:TextureFlags=Null,shader:Shader=Null )
+	Method New( width:Int,height:Int,format:PixelFormat,textureFlags:TextureFlags=TextureFlags.UseDefault,shader:Shader=Null )
+	
+		If textureFlags=TextureFlags.UseDefault textureFlags=DefaultTextureFlags
 	
 		Local texture:=New Texture( width,height,format,textureFlags )
 		
-		Init( texture,texture.Rect,shader )
+		Init( texture,shader )
 		
 		AddDependancy( texture )
 	End
@@ -92,7 +103,6 @@ Class Image Extends Resource
 		Next
 		
 		BlendMode=image.BlendMode
-		TextureFilter=image.TextureFilter
 		LightDepth=image.LightDepth
 		Handle=image.Handle
 		Scale=image.Scale
@@ -110,7 +120,6 @@ Class Image Extends Resource
 		Next
 		
 		BlendMode=image.BlendMode
-		TextureFilter=image.TextureFilter
 		LightDepth=image.LightDepth
 		Handle=image.Handle
 		Scale=image.Scale
@@ -126,7 +135,7 @@ Class Image Extends Resource
 	#end
 	Method New( texture:Texture,shader:Shader=Null )
 
-		Init( texture,texture.Rect,shader )
+		Init( texture,shader )
 	End
 	
 	#rem monkeydoc @hidden
@@ -209,24 +218,6 @@ Class Image Extends Resource
 		_blendMode=blendMode
 	End
 	
-	#rem monkeydoc The image texture filter.
-	
-	The texture flags used to draw the image.
-	
-	If set to TextureFilter.None, the canvas texture filter is used instead.
-	
-	Defaults to TextureFilter.None
-	
-	#end	
-	Property TextureFilter:TextureFilter()
-	
-		Return _textureFilter
-		
-	Setter( filter:TextureFilter )
-	
-		_textureFilter=filter
-	End
-	
 	#rem monkeydoc The image color.
 	
 	The color used to draw the image.
@@ -244,7 +235,7 @@ Class Image Extends Resource
 	
 		_color=color
 		
-		_material.SetVector( "mx2_ImageColor",_color )
+		_material.SetVec4f( "ImageColor",_color )
 	End
 
 	#rem monkeydoc The image light depth.
@@ -257,7 +248,7 @@ Class Image Extends Resource
 	
 		_lightDepth=depth
 		
-		_material.SetScalar( "mx2_LightDepth",_lightDepth )
+		_material.SetFloat( "LightDepth",_lightDepth )
 	End
 
 	#rem monkeydoc Shadow caster attached to image.
@@ -338,7 +329,7 @@ Class Image Extends Resource
 	
 		_textures[index]=texture
 		
-		_material.SetTexture( "mx2_ImageTexture"+index,texture )
+		_material.SetTexture( "ImageTexture"+index,texture )
 	End
 	
 	#rem monkeydoc @hidden gets an image texture.
@@ -350,14 +341,16 @@ Class Image Extends Resource
 	
 	#rem monkeydoc Loads an image from file.
 	#end
-	Function Load:Image( path:String,shader:Shader=Null )
+	Function Load:Image( path:String,shader:Shader=Null,textureFlags:TextureFlags=TextureFlags.UseDefault )
+		
+		If textureFlags=TextureFlags.UseDefault textureFlags=DefaultTextureFlags
 	
 		Local pixmap:=Pixmap.Load( path,Null,True )
 		If Not pixmap Return Null
 
 		If Not shader shader=mojo.graphics.Shader.GetShader( "sprite" )
 		
-		Local image:=New Image( pixmap,Null,shader )
+		Local image:=New Image( pixmap,textureFlags,shader )
 			
 		image.OnDiscarded+=Lambda()
 			pixmap.Discard()
@@ -388,7 +381,7 @@ Class Image Extends Resource
 		
 		If Not shader shader=graphics.Shader.GetShader( "bump" )
 		
-		Local image:=New Image( texture0,texture0.Rect,shader )
+		Local image:=New Image( texture0,shader )
 		image.SetTexture( 1,texture1 )
 		
 		image.OnDiscarded+=Lambda()
@@ -478,7 +471,6 @@ Class Image Extends Resource
 
 	Field _textures:=New Texture[4]
 	Field _blendMode:BlendMode
-	Field _textureFilter:TextureFilter
 	Field _color:Color
 	Field _lightDepth:Float
 	Field _shadowCaster:ShadowCaster
@@ -492,20 +484,24 @@ Class Image Extends Resource
 	Field _bounds:Rectf
 	Field _radius:Float
 	
+	Method Init( texture:Texture,shader:Shader )
+		
+		Init( texture,New Recti( New Vec2i(0),texture.Size ),shader )
+	End
+	
 	Method Init( texture:Texture,rect:Recti,shader:Shader )
 	
 		If Not shader shader=Shader.GetShader( "sprite" )
 	
 		_rect=rect
 		_shader=shader
-		_material=New UniformBlock
+		_material=New UniformBlock( 2 )
 		
 		AddDependancy( _material )
 		
 		SetTexture( 0,texture )
 		
 		BlendMode=BlendMode.None
-		TextureFilter=TextureFilter.None
 		Color=Color.White
 		LightDepth=100
 		Handle=New Vec2f( 0 )

+ 91 - 36
modules/mojo/graphics/indexbuffer.monkey2

@@ -1,16 +1,55 @@
 
 Namespace mojo.graphics
 
+Enum IndexFormat
+	UINT16=1
+	UINT32=2
+End
 
 #rem monkeydoc @hidden
 #end	
 Class IndexBuffer
 
-	Method New( capacity:Int )
-	
+	Method New( format:IndexFormat,capacity:Int )
+
+		_format=format
 		_capacity=capacity
+		_pitch=_format=IndexFormat.UINT16 ? 2 Else 4
+		_length=0
+		_clean=0
+		_data=New UByte[_capacity*_pitch]
+	End
+	
+	Method New( indices:IndexBuffer )
+
+		_format=indices._format
+		_capacity=indices._capacity
+		_pitch=indices._pitch
+		_length=indices._length
+		_clean=0
+		_data=indices._data.Slice( 0 )
+	End
+	
+	Method New( indices:UInt[] )
+		Self.New( IndexFormat.UINT32,indices.Length )
+		
+		libc.memcpy( AddIndices( indices.Length ),indices.Data,_capacity*_pitch )
+	End
+	
+	Method New( indices:UShort[] )
+		Self.New( IndexFormat.UINT16,indices.Length )
 		
-		_data=New UShort[_capacity]
+		libc.memcpy( AddIndices( indices.Length ),indices.Data,_capacity*_pitch )
+	End
+	
+	Property Data:UByte Ptr()
+		
+		Return _data.Data
+	End
+	
+	Property Format:IndexFormat()
+		
+		Return _format
 	End
 	
 	Property Capacity:Int()
@@ -18,26 +57,30 @@ Class IndexBuffer
 		Return _capacity
 	End
 
-	Property Length:Int()
-	
-		Return _length
+	Property Pitch:Int()
+		
+		Return _pitch
 	End
 	
-	Property Pitch:Int()
+	Property Length:Int()
 	
-		Return 2
+		Return _length
 	End
 	
 	Method Clear()
-	
 		_length=0
 		_clean=0
 	End
 	
-	Method AddIndices:UShort Ptr( count:Int )
-		If _length+count>_capacity Return Null
+	Method Invalidate()
+		_clean=0
+	End
+	
+	Method AddIndices:UByte Ptr( count:Int )
+		Reserve( _length+count )
+		
+		Local p:=_data.Data+_length*_pitch
 		
-		Local p:=_data.Data+_length
 		_length+=count
 		
 		Return p
@@ -47,45 +90,57 @@ Class IndexBuffer
 	
 	Method Bind()
 	
-		If _seq<>glGraphicsSeq
-			_seq=glGraphicsSeq
+		If _glSeq<>glGraphicsSeq
+			
+			glGenBuffers( 1,Varptr _glBuffer )
+			glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,_glBuffer )
+			
+			glBufferData( GL_ELEMENT_ARRAY_BUFFER,_capacity*_pitch,Null,GL_DYNAMIC_DRAW )
+'			Print "bound ib "+_glBuffer
+		
+			_glSeq=glGraphicsSeq
 			_clean=0
-			glGenBuffers( 1,Varptr _glvbo )
-			glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,_glvbo )
-			glBufferData( GL_ELEMENT_ARRAY_BUFFER,_capacity * Pitch,Null,GL_STATIC_DRAW )
 		Else
-			glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,_glvbo )
+			glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,_glBuffer )
+'			Print "bound ib "+_glBuffer
 		Endif
 
 	End
 	
 	Method Validate()
-	
-		If _clean=_length Return
 		
-		_clean=_length
+		If _length=_clean Return
 		
-		'mythical 'orphaning'...
-'		glBufferData( GL_ELEMENT_ARRAY_BUFFER,_capacity * Pitch,Null,GL_STATIC_DRAW )
-
-'		glBufferSubData( GL_ELEMENT_ARRAY_BUFFER,0,_length*Pitch,_data.Data )
-
-		'lazy - but fastest?
-		glBufferData( GL_ELEMENT_ARRAY_BUFFER,_length*Pitch,_data.Data,GL_STATIC_DRAW )
+		glBufferData( GL_ELEMENT_ARRAY_BUFFER,_length*_pitch,_data.Data,GL_DYNAMIC_DRAW )
+'		Print "updated ib "+_glBuffer
+		
+		_clean=_length
 	End
 		
 	Private
 	
+	Field _format:IndexFormat
 	Field _capacity:Int
-	
+	Field _pitch:Int
 	Field _length:Int
-	
 	Field _clean:Int
-	
-	Field _data:UShort[]
-	
-	Field _glvbo:GLuint
-	
-	Field _seq:Int
+	Field _data:UByte[]
+
+	Field _glSeq:Int
+	Field _glBuffer:GLuint
+
+	Method Reserve( capacity:Int )
+		
+		If _capacity>=capacity Return
+		
+		_capacity=Max( _length*2+_length,capacity )
+		
+		Local data:=New UByte[_capacity*_pitch]
+		
+		libc.memcpy( data.Data,_data.Data,_length*_pitch )
+		
+		_data=data
+		
+	End
 
 End

+ 76 - 0
modules/mojo/graphics/rendertarget.monkey2

@@ -0,0 +1,76 @@
+
+Namespace mojo.graphics
+
+Class RenderTarget Extends Resource
+	
+	Method New( colorTextures:Texture[],depthTexture:Texture )
+		
+		_colorTextures=colorTextures.Slice( 0 )
+		
+		_depthTexture=depthTexture
+		
+		_drawBufs=New GLenum[ _colorTextures.Length]
+		
+		For Local i:=0 Until _colorTextures.Length
+			_drawBufs[i]=_colorTextures[i] ? GL_COLOR_ATTACHMENT0+i Else GL_NONE
+		Next
+	End
+	
+	Property Size:Vec2i()
+		
+		Return _colorTextures ? _colorTextures[0].Size Else _depthTexture.Size
+	End
+	
+	'***** INTERNAL *****
+	
+	Method Bind()
+		
+		glBindFramebuffer( GL_FRAMEBUFFER,ValidateGLFramebuffer() )
+		
+		glDrawBuffers( _drawBufs.Length,_drawBufs.Data )
+		
+'		glReadBuffer( GL_NONE )
+	End
+	
+	Private
+	
+	Field _colorTextures:Texture[]
+	Field _depthTexture:Texture
+	
+	Field _drawBufs:GLenum[]
+	
+	Field _glFramebuffer:GLuint
+	Field _glSeq:Int
+	
+	Method ValidateGLFramebuffer:GLuint()
+		
+		If _glSeq=glGraphicsSeq Return _glFramebuffer
+		
+		glGenFramebuffers( 1,Varptr _glFramebuffer )
+		
+		glPushFramebuffer( GL_FRAMEBUFFER,_glFramebuffer )
+		
+		For Local i:=0 Until _colorTextures.Length
+			
+			Local texture:=_colorTextures[i]
+			
+			glFramebufferTexture2D( GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0+i,GL_TEXTURE_2D,texture.ValidateGLTexture(),0 )
+			
+		Next
+		
+		If _depthTexture
+			
+			glFramebufferTexture2D( GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,_depthTexture.ValidateGLTexture(),0 )
+			
+		Endif
+
+		Assert( glCheckFramebufferStatus( GL_FRAMEBUFFER )=GL_FRAMEBUFFER_COMPLETE,"Incomplete framebuffer" )
+			
+		_glSeq=glGraphicsSeq
+
+		glPopFramebuffer()
+		
+		Return _glFramebuffer
+	End
+	
+End

+ 66 - 39
modules/mojo/graphics/shader.monkey2

@@ -3,7 +3,14 @@ Namespace mojo.graphics
 
 #Import "shaders/@/shaders"
 
-Private
+Const A_POSITION:=0
+Const A_TEXCOORD0:=1
+Const A_TEXCOORD1:=2
+Const A_COLOR:=3
+Const A_NORMAL:=4
+Const A_TANGENT:=5
+Const A_WEIGHTS:=6
+Const A_BONES:=7
 
 Class GLUniform
 
@@ -12,8 +19,8 @@ Class GLUniform
 	Field texunit:Int
 	Field size:Int
 	Field type:Int
+	Field block:Int
 	Field uniformId:Int
-	Field blockId:Int
 
 	Method New( name:String,location:Int,texunit:Int,size:Int,type:Int )
 		Self.name=name
@@ -22,8 +29,15 @@ Class GLUniform
 		Self.size=size
 		Self.type=type
 		
-		Self.uniformId=UniformBlock.GetUniformId( name )
-		Self.blockId=UniformBlock.GetUniformBlockId( name )
+		If name.StartsWith( "r_" )
+			name=name.Slice( 2 )
+			block=1
+		Else If name.StartsWith( "m_" )
+			name=name.Slice( 2 )
+			block=2
+		Endif
+		
+		uniformId=UniformBlock.GetUniformId( name,block )
 	End
 	
 End
@@ -62,11 +76,11 @@ Class GLProgram
 			
 			Local uniform:=New GLUniform( name,location,texunit,size,type )
 			
-			uniforms[uniform.blockId].Push( uniform )
+			uniforms[uniform.block].Push( uniform )
 			
 			Select type
-			Case GL_SAMPLER_2D
-				textures[uniform.blockId].Push( uniform )
+			Case GL_SAMPLER_2D,GL_SAMPLER_CUBE
+				textures[uniform.block].Push( uniform )
 				texunit+=1
 			End
 			
@@ -84,7 +98,7 @@ Class GLProgram
 		Return _glprogram
 	End
 
-	Method ValidateUniforms( ublocks:UniformBlock[],textureFilter:TextureFilter )
+	Method ValidateUniforms( ublocks:UniformBlock[] )',textureFilter:TextureFilter )
 
 		For Local i:=0 Until 4
 
@@ -99,28 +113,31 @@ Class GLProgram
 				Select u.type
 				Case GL_FLOAT
 				
-					glUniform1f( u.location,ublock.GetScalar( u.uniformId ) )
+					glUniform1f( u.location,ublock.GetFloat( u.uniformId ) )
 					
 				Case GL_FLOAT_VEC2
 				
-					glUniform2fv( u.location,1,ublock.GetVector4fv( u.uniformId ) )
+					glUniform2fv( u.location,1,ublock.GetVec2fv( u.uniformId ) )
 					
 				Case GL_FLOAT_VEC3
 				
-					glUniform3fv( u.location,1,ublock.GetVector4fv( u.uniformId ) )
+					glUniform3fv( u.location,1,ublock.GetVec3fv( u.uniformId ) )
 					
 				Case GL_FLOAT_VEC4
 				
-					glUniform4fv( u.location,1,ublock.GetVector4fv( u.uniformId ) )
+					glUniform4fv( u.location,1,ublock.GetVec4fv( u.uniformId ) )
+					
+				Case GL_FLOAT_MAT3
+				
+					glUniformMatrix3fv( u.location,1,False,ublock.GetMat3fv( u.uniformId ) )
 					
 				Case GL_FLOAT_MAT4
 				
-					glUniformMatrix4fv( u.location,1,False,ublock.GetMatrix4fv( u.uniformId ) )
+					glUniformMatrix4fv( u.location,1,False,ublock.GetMat4fv( u.uniformId ) )
 					
-				Case GL_SAMPLER_2D
+				Case GL_SAMPLER_2D,GL_SAMPLER_CUBE
 				
 					glUniform1i( u.location,u.texunit )
-				
 				End
 			
 			Next
@@ -132,14 +149,14 @@ Class GLProgram
 			If Not _textures[i] Continue
 			
 			For Local u:=Eachin _textures[i]
-
+				
 				Local tex:=ublocks[i].GetTexture( u.uniformId )
 				If tex
-					tex.Bind( u.texunit,textureFilter )
+					tex.Bind( u.texunit )',textureFilter )
 				Else
 					Print( "Can't bind shader texture uniform '"+u.name+"' - no texture!" )
 				Endif
-			
+				
 			Next
 		
 		Next
@@ -147,7 +164,7 @@ Class GLProgram
 		glActiveTexture( GL_TEXTURE0 )
 	
 	End
-
+	
 End
 
 Public
@@ -160,14 +177,10 @@ Class Shader
 	#end
 	Method New( name:String,source:String )
 	
-		Assert( Not _shaders.Contains( name ),"Shader with name '"+name+"' already exists" )
-		
 		_name=name
 	
 		_source=source
 		
-		_shaders[name]=Self
-		
 		EnumPasses()
 	End
 	
@@ -215,27 +228,36 @@ Class Shader
 	
 	#rem monkeydoc @hidden
 	#end
-	Method ValidateUniforms( renderPass:Int,ublocks:UniformBlock[],textureFilter:TextureFilter )
+	Method ValidateUniforms( renderPass:Int,ublocks:UniformBlock[] )',textureFilter:TextureFilter )
 	
-		_programs[renderPass].ValidateUniforms( ublocks,textureFilter )
+		_programs[renderPass].ValidateUniforms( ublocks )',textureFilter )
 	End
 
 	#rem monkeydoc Gets a shader with a given name.
 	#end	
 	Function GetShader:Shader( name:String )
-	
-		Local shader:=_shaders[name]
-		If shader Return shader
 		
-		Local source:=LoadString( "asset::shaders/"+name+".glsl" )
-		If Not source Return Null
+		If _cache.Contains( name ) Return _cache[name]
 		
-		Return New Shader( name,source )
+		local source:=LoadString( "asset::shaders/"+name+".glsl" )
+		
+		Local shader:=source ? New Shader( name,source ) Else Null
+		
+		_cache[name]=shader
+		
+		Return shader
 	End
-
+	
+	#rem monkeydoc Gets a shader with a given name.
+	#end	
+	Function Open:Shader( name:String )
+		
+		Return GetShader( name )
+	End
+	
 	Private
 	
-	Global _shaders:=New StringMap<Shader>
+	Global _cache:=New StringMap<Shader>
 
 	Field _name:String	
 	Field _source:String
@@ -270,7 +292,7 @@ Class Shader
 	End
 	
 	Method Rebuild()
-	
+		
 		'Get renderpasses
 		'
 		Local tag:="//@renderpasses"
@@ -325,10 +347,14 @@ Class Shader
 			glDeleteShader( vshader )
 			glDeleteShader( fshader )
 				
-			glBindAttribLocation( glprogram,0,"mx2_Vertex" )
-			glBindAttribLocation( glprogram,1,"mx2_TexCoord0" )
-			glBindAttribLocation( glprogram,2,"mx2_TexCoord1" )
-			glBindAttribLocation( glprogram,3,"mx2_Color" )
+			glBindAttribLocation( glprogram,A_POSITION,"a_Position" )
+			glBindAttribLocation( glprogram,A_TEXCOORD0,"a_TexCoord0" )
+			glBindAttribLocation( glprogram,A_TEXCOORD1,"a_TexCoord1" )
+			glBindAttribLocation( glprogram,A_COLOR,"a_Color" )
+			glBindAttribLocation( glprogram,A_NORMAL,"a_Normal" )
+			glBindAttribLocation( glprogram,A_TANGENT,"a_Tangent" )
+			glBindAttribLocation( glprogram,A_WEIGHTS,"a_Weights" )
+			glBindAttribLocation( glprogram,A_BONES,"a_Bones" )
 			
 			glLink( glprogram )
 			
@@ -336,7 +362,8 @@ Class Shader
 			
 			_programs[rpass]=program
 		Next
-
+		
+		glCheck()
 	End
 
 End

+ 26 - 20
modules/mojo/graphics/shaders/bump.glsl

@@ -1,49 +1,55 @@
 
 //@renderpasses 0,1,2
 
-varying vec2 texCoord0;
-varying mat2 tanMatrix;
-varying vec4 color;
+varying vec2 v_TexCoord0;
+varying mat2 v_TanMatrix;
+varying vec4 v_Color;
 
 //@vertex
 
-attribute vec4 mx2_Vertex;
-attribute vec2 mx2_TexCoord0;
-attribute vec2 mx2_TexCoord1;
-attribute vec4 mx2_Color;
+attribute vec4 a_Position;
+attribute vec2 a_TexCoord0;
+attribute vec2 a_TexCoord1;
+attribute vec4 a_Color;
 
-uniform mat4 mx2_ModelViewProjectionMatrix;
+uniform mat4 r_ModelViewProjectionMatrix;
 
-uniform vec4 mx2_AmbientLight;
+uniform vec4 r_AmbientLight;
 
-uniform vec4 mx2_ImageColor;
+uniform vec4 m_ImageColor;
 
 void main(){
 
-	texCoord0=mx2_TexCoord0;
+	v_TexCoord0=a_TexCoord0;
 
 #if MX2_RENDERPASS==2
-	tanMatrix=mat2( mx2_TexCoord1.x,mx2_TexCoord1.y,-mx2_TexCoord1.y,mx2_TexCoord1.x );
+
+	v_TanMatrix=mat2( a_TexCoord1.x,a_TexCoord1.y,-a_TexCoord1.y,a_TexCoord1.x );
+	
 #endif
 
 #if MX2_RENDERPASS==0
-	color=mx2_AmbientLight * mx2_ImageColor * mx2_Color;
+
+	v_Color=r_AmbientLight * m_ImageColor * a_Color;
+	
 #else
-	color=mx2_ImageColor * mx2_Color;
+
+	v_Color=m_ImageColor * a_Color;
+	
 #endif
 	
-	gl_Position=mx2_ModelViewProjectionMatrix * mx2_Vertex;
+	gl_Position=r_ModelViewProjectionMatrix * a_Position;
 }
 
 //@fragment
 
-uniform sampler2D mx2_ImageTexture0;
+uniform sampler2D m_ImageTexture0;
 
-uniform sampler2D mx2_ImageTexture1;
+uniform sampler2D m_ImageTexture1;
 
 void main(){
 
-	vec4 diffuse=texture2D( mx2_ImageTexture0,texCoord0 ) * color;
+	vec4 diffuse=texture2D( m_ImageTexture0,v_TexCoord0 ) * v_Color;
 
 #if MX2_RENDERPASS==0		//ambient
 
@@ -55,9 +61,9 @@ void main(){
 	
 #elif MX2_RENDERPASS==2		//normal
 
-	vec3 normal=texture2D( mx2_ImageTexture1,texCoord0 ).xyz;
+	vec3 normal=texture2D( m_ImageTexture1,v_TexCoord0 ).xyz;
 	
-	normal.xy=tanMatrix * (normal.xy * 2.0 - 1.0) * 0.5 + 0.5;
+	normal.xy=v_TanMatrix * (normal.xy * 2.0 - 1.0) * 0.5 + 0.5;
 
 	gl_FragColor=vec4( normal*diffuse.a,diffuse.a );
 

+ 14 - 14
modules/mojo/graphics/shaders/font.glsl

@@ -1,43 +1,43 @@
 
 //@renderpasses 0,1,2
 
-varying vec2 texCoord0;
-varying vec4 color;
+varying vec2 v_TexCoord0;
+varying vec4 v_Color;
 
 //@vertex
 
-attribute vec4 mx2_Vertex;
-attribute vec2 mx2_TexCoord0;
-attribute vec4 mx2_Color;
+attribute vec4 a_Position;
+attribute vec2 a_TexCoord0;
+attribute vec4 a_Color;
 
-uniform mat4 mx2_ModelViewProjectionMatrix;
+uniform mat4 r_ModelViewProjectionMatrix;
 
-uniform vec4 mx2_ImageColor;
+uniform vec4 m_ImageColor;
 
 void main(){
 
-	texCoord0=mx2_TexCoord0;
+	v_TexCoord0=a_TexCoord0;
 
-	color=mx2_ImageColor * mx2_Color;
+	v_Color=m_ImageColor * a_Color;
 	
-	gl_Position=mx2_ModelViewProjectionMatrix * mx2_Vertex;
+	gl_Position=r_ModelViewProjectionMatrix * a_Position;
 }
 
 //@fragment
 
-uniform sampler2D mx2_ImageTexture0;
+uniform sampler2D m_ImageTexture0;
 
 void main(){
 
-	float alpha=texture2D( mx2_ImageTexture0,texCoord0 ).a;
+	float alpha=texture2D( m_ImageTexture0,v_TexCoord0 ).a;
 
 #if MX2_RENDERPASS==0
 
-	gl_FragColor=vec4( alpha ) * color;
+	gl_FragColor=vec4( alpha ) * v_Color;
 
 #else
 
-	gl_FragColor=vec4( 0.0,0.0,0.0,alpha * color.a );
+	gl_FragColor=vec4( 0.0,0.0,0.0,alpha * v_Color.a );
 	
 #endif
 

+ 33 - 33
modules/mojo/graphics/shaders/light.glsl

@@ -1,58 +1,58 @@
 
 //@renderpasses 4,5
 
-varying vec2 texCoord0;
-varying vec2 lightPos;
-varying vec4 color;
+varying vec2 v_TexCoord0;
+varying vec2 v_LightPos;
+varying vec4 v_Color;
 
-varying vec2 gbufferCoords;
-varying vec2 fragPos;
+varying vec2 v_GBufferCoords;
+varying vec2 v_FragPos;
 
 //@vertex
 
-attribute vec4 mx2_Vertex;
-attribute vec2 mx2_TexCoord0;
-attribute vec2 mx2_TexCoord1;
-attribute vec4 mx2_Color;
+attribute vec4 a_Position;
+attribute vec2 a_TexCoord0;
+attribute vec2 a_TexCoord1;
+attribute vec4 a_Color;
 
-uniform mat4 mx2_ModelViewProjectionMatrix;
+uniform mat4 r_ModelViewProjectionMatrix;
 
-uniform vec2 mx2_ViewportOrigin;
-uniform vec2 mx2_ViewportSize;
-uniform vec2 mx2_ViewportClip;
+uniform vec2 r_ViewportOrigin;
+uniform vec2 r_ViewportSize;
+uniform vec2 r_ViewportClip;
 
-uniform vec2 mx2_GBufferScale;
+uniform vec2 r_GBufferScale;
 
-uniform vec4 mx2_ImageColor;
+uniform vec4 m_ImageColor;
 
 void main(){
 
-	texCoord0=mx2_TexCoord0;
-	lightPos=mx2_TexCoord1;
-	color=mx2_ImageColor * mx2_Color;
+	v_TexCoord0=a_TexCoord0;
+	v_LightPos=a_TexCoord1;
+	v_Color=m_ImageColor * a_Color;
 
-	gl_Position=mx2_ModelViewProjectionMatrix * mx2_Vertex;
+	gl_Position=r_ModelViewProjectionMatrix * a_Position;
 	
-	vec2 vpcoords=(gl_Position.xy * 0.5 + 0.5) * mx2_ViewportSize;
+	vec2 vpcoords=(gl_Position.xy * 0.5 + 0.5) * r_ViewportSize;
 	
-	gbufferCoords=(vpcoords + mx2_ViewportOrigin) * mx2_GBufferScale;
+	v_GBufferCoords=(vpcoords + r_ViewportOrigin) * r_GBufferScale;
 
-	fragPos=vpcoords;
-	fragPos.y=mx2_ViewportSize.y-fragPos.y;
-	fragPos-=mx2_ViewportClip;
+	v_FragPos=vpcoords;
+	v_FragPos.y=r_ViewportSize.y-v_FragPos.y;
+	v_FragPos-=r_ViewportClip;
 }
 
 //@fragment
 
-uniform sampler2D mx2_ImageTexture0;			//image texture
-uniform float mx2_LightDepth;
+uniform sampler2D m_ImageTexture0;			//image texture
+uniform float m_LightDepth;
 
-uniform sampler2D mx2_GBuffer0;					//gbuffer diffuse
-uniform sampler2D mx2_GBuffer1;					//gbuffer normal
+uniform sampler2D r_GBuffer0;					//gbuffer diffuse
+uniform sampler2D r_GBuffer1;					//gbuffer normal
 
 void main(){
 
-	vec3 normal=texture2D( mx2_GBuffer1,gbufferCoords ).xyz;
+	vec3 normal=texture2D( r_GBuffer1,v_GBufferCoords ).xyz;
 	
 	float gloss=normal.z;
 	
@@ -62,13 +62,13 @@ void main(){
 	
 	//diffuse...
 	//	
-	vec3 lvec=normalize( vec3( lightPos-fragPos,mx2_LightDepth ) );
+	vec3 lvec=normalize( vec3( v_LightPos-v_FragPos,m_LightDepth ) );
 	
 	float ndotl=max( dot( normal,lvec ),0.0 );
 	
-	vec4 tcolor=texture2D( mx2_ImageTexture0,texCoord0 ) * color;
+	vec4 tcolor=texture2D( m_ImageTexture0,texCoord0 ) * v_Color;
 
-	vec4 diffuse=texture2D( mx2_GBuffer0,gbufferCoords ) * tcolor * ndotl;
+	vec4 diffuse=texture2D( r_GBuffer0,v_GBufferCoords ) * tcolor * ndotl;
 	
 	//specular...
 	//
@@ -80,7 +80,7 @@ void main(){
 	
 #if MX2_RENDERPASS==5
 
-	float shadow=texture2D( mx2_GBuffer0,gbufferCoords ).a;
+	float shadow=texture2D( r_GBuffer0,v_GBufferCoords ).a;
 	diffuse*=shadow;
 	specular*=shadow;
 

+ 7 - 7
modules/mojo/graphics/shaders/null.glsl

@@ -1,20 +1,20 @@
 
 //@renderpasses 0
 
-varying vec4 color;
+varying vec4 v_Color;
 
 //@vertex
 
-attribute vec4 mx2_Vertex;
-attribute vec4 mx2_Color;
+attribute vec4 a_Position;
+attribute vec4 a_Color;
 
-uniform mat4 mx2_ModelViewProjectionMatrix;
+uniform mat4 r_ModelViewProjectionMatrix;
 
 void main(){
 
-	color=mx2_Color;
+	v_Color=a_Color;
 	
-	gl_Position=mx2_ModelViewProjectionMatrix * mx2_Vertex;
+	gl_Position=r_ModelViewProjectionMatrix * a_Position;
 	
 	gl_PointSize=1.0;
 }
@@ -23,5 +23,5 @@ void main(){
 
 void main(){
 
-	gl_FragColor=color;
+	gl_FragColor=v_Color;
 }

+ 13 - 13
modules/mojo/graphics/shaders/sprite.glsl

@@ -1,41 +1,41 @@
 
 //@renderpasses 0,1,2
 
-varying vec2 texCoord0;
-varying vec4 color;
+varying vec2 v_TexCoord0;
+varying vec4 v_Color;
 
 //@vertex
 
-attribute vec4 mx2_Vertex;
-attribute vec2 mx2_TexCoord0;
-attribute vec4 mx2_Color;
+attribute vec4 a_Position;
+attribute vec2 a_TexCoord0;
+attribute vec4 a_Color;
 
-uniform mat4 mx2_ModelViewProjectionMatrix;
+uniform mat4 r_ModelViewProjectionMatrix;
 
-uniform vec4 mx2_ImageColor;
+uniform vec4 m_ImageColor;
 
 void main(){
 
-	texCoord0=mx2_TexCoord0;
+	v_TexCoord0=a_TexCoord0;
 
-	color=mx2_ImageColor * mx2_Color;
+	v_Color=m_ImageColor * a_Color;
 	
-	gl_Position=mx2_ModelViewProjectionMatrix * mx2_Vertex;
+	gl_Position=r_ModelViewProjectionMatrix * a_Position;
 }
 
 //@fragment
 
-uniform sampler2D mx2_ImageTexture0;
+uniform sampler2D m_ImageTexture0;
 
 void main(){
 
 #if MX2_RENDERPASS==0
 
-	gl_FragColor=texture2D( mx2_ImageTexture0,texCoord0 ) * color;
+	gl_FragColor=texture2D( m_ImageTexture0,v_TexCoord0 ) * v_Color;
 	
 #else
 
-	float alpha=texture2D( mx2_ImageTexture0,texCoord0 ).a * color.a;
+	float alpha=texture2D( m_ImageTexture0,v_TexCoord0 ).a * v_Color.a;
 
 	gl_FragColor=vec4( 0.0,0.0,0.0,alpha );
 

+ 276 - 208
modules/mojo/graphics/texture.monkey2

@@ -3,6 +3,61 @@ Namespace mojo.graphics
 
 Using std.resource
 
+Private
+
+Function IsPow2:Bool( w:Int,h:Int )
+	Local tw:=Log2( w ),th:=Log2( h )
+	Return tw=Round( tw ) And th=Round( th )
+End
+
+Function IsDepth:Bool( format:PixelFormat )
+	Return format=PixelFormat.Depth32F
+End
+
+Function glInternalFormat:GLenum( format:PixelFormat )
+	Select format
+	Case PixelFormat.A8 Return GL_ALPHA
+	Case PixelFormat.I8 Return GL_LUMINANCE
+	Case PixelFormat.IA16 Return GL_LUMINANCE_ALPHA
+	Case PixelFormat.RGB24 Return GL_RGB
+	Case PixelFormat.RGBA32 Return GL_RGBA
+	Case PixelFormat.RGBA16F Return GL_RGB
+	Case PixelFormat.Depth32F Return GL_DEPTH_COMPONENT
+	End
+	RuntimeError( "Invalid PixelFormat" )
+	Return GL_RGBA
+End
+
+Function glFormat:GLenum( format:PixelFormat )
+	Select format
+	Case PixelFormat.A8 Return GL_ALPHA
+	Case PixelFormat.I8 Return GL_LUMINANCE
+	Case PixelFormat.IA16 Return GL_LUMINANCE_ALPHA
+	Case PixelFormat.RGB24 Return GL_RGB
+	Case PixelFormat.RGBA32 Return GL_RGBA
+	Case PixelFormat.RGBA16F Return GL_RGB
+	Case PixelFormat.Depth32F Return GL_DEPTH_COMPONENT
+	End
+	RuntimeError( "Invalid PixelFormat" )
+	Return GL_RGBA
+End
+
+Function glType:GLenum( format:PixelFormat )
+	Select format
+	Case PixelFormat.A8 Return GL_UNSIGNED_BYTE
+	Case PixelFormat.I8 Return GL_UNSIGNED_BYTE
+	Case PixelFormat.IA16 Return GL_UNSIGNED_BYTE
+	Case PixelFormat.RGB24 Return GL_UNSIGNED_BYTE
+	Case PixelFormat.RGBA32 Return GL_UNSIGNED_BYTE
+	Case PixelFormat.RGBA16F Return GL_HALF_FLOAT
+	Case PixelFormat.Depth32F Return GL_UNSIGNED_INT
+	End
+	RuntimeError( "Invalid PixelFormat" )
+	Return GL_UNSIGNED_BYTE
+End
+
+Public
+
 #rem monkeydoc Texture flags.
 
 | TextureFlags	| Description
@@ -11,92 +66,110 @@ Using std.resource
 
 #end
 Enum TextureFlags
-
 	WrapS=			$0001			'wrap works, but hidden for now...
 	WrapT=			$0002
-	Unmanaged=		$0004
-	DisableMipmap=	$0008
-	RenderTarget=	$0010
+	Filter=			$0004
+	Mipmap=			$0008
+	Dynamic=		$0010
+	Cubemap=		$0020
 	
-	WrapST=			WrapS|WrapT
-	Dynamic=		Unmanaged|RenderTarget|DisableMipmap
+	Skybox=			Filter|Mipmap|Cubemap
 	
+	UseDefault=		$ffff
 End
 
-#rem monkeydoc Texture filters.
-
-| TextureFlags	| Description
-|:--------------|:-----------
-| Nearest		| Textures are not filtered.
-| Linear		| Textures are filtered when magnified.
-| Mipmap		| Textures are filtered when magnified and minified.
-
-#end
 Enum TextureFilter
-
-	None=0
-	Nearest=1
-	Linear
-	Mipmap
-	
+	Filter=			$0001
+	Mipmap=			$0002
 End
 
 #rem monkeydoc @hidden
 #end
 Class Texture Extends Resource
-
-	Method New( pixmap:Pixmap,flags:TextureFlags )
 	
-#If Not __DESKTOP_TARGET__
-		Local tw:=Log2( pixmap.Width ),th:=Log2( pixmap.Height )
-		If tw<>Round( tw ) Or th<>Round( th ) flags|=TextureFlags.DisableMipmap
-#Endif
-		_rect=New Recti( 0,0,pixmap.Width,pixmap.Height )
+	Method New( pixmap:Pixmap,flags:TextureFlags=TextureFlags.UseDefault )
+
+		If flags=TextureFlags.UseDefault flags=TextureFlags.Filter|TextureFlags.Mipmap
+			
+		_managed=pixmap
+		_size=New Vec2i( pixmap.Width,pixmap.Height )
 		_format=pixmap.Format
 		_flags=flags
-		_filter=Null
+		
+		If _flags & TextureFlags.Cubemap
+			If _size.x=_size.y
+			Else If _size.x/4*3=_size.y
+				_size.x/=4
+				_size.y/=3
+			Else
+				RuntimeError( "Invalid Cubemap size" )
+			Endif
+		Endif
+		
+#If Not __DESKTOP_TARGET__
+		If Not IsPow2( _size.x,_size.y ) _flags&=~TextureFlags.Mipmap
+#Endif
 
-		If _flags & TextureFlags.Unmanaged
-			PastePixmap( pixmap,0,0 )
+		_glTarget=_flags & TextureFlags.Cubemap ? GL_TEXTURE_CUBE_MAP Else GL_TEXTURE_2D
+		_glInternalFormat=glInternalFormat( _format )
+		_glFormat=glFormat( _format )
+		_glType=glType( _format )
+		
+		If _flags & TextureFlags.Dynamic
+			PastePixmap( _managed,0,0 )
 		Else
-			AddDependancy( pixmap )
-			_managed=pixmap
+			AddDependancy( _managed )
 		Endif
-		
 	End
 	
-	Method New( width:Int,height:Int,format:PixelFormat,flags:TextureFlags )
-	
-#If Not __DESKTOP_TARGET__
-		Local tw:=Log2( width ),th:=Log2( height )
-		If tw<>Round( tw ) Or th<>Round( th ) flags|=TextureFlags.DisableMipmap
-#Endif
-		_rect=New Recti( 0,0,width,height )
+	Method New( width:Int,height:Int,format:PixelFormat,flags:TextureFlags=TextureFlags.UseDefault )
+
+		If flags=TextureFlags.UseDefault flags=TextureFlags.Filter|TextureFlags.Dynamic
+		
+		_managed=Null
+		_size=New Vec2i( width,height )
 		_format=format
 		_flags=flags
-		_filter=Null
 		
-		If Not (_flags & TextureFlags.Unmanaged)
+		If _flags & TextureFlags.Cubemap
+			If _size.x=_size.y
+			Else If _size.x/4*3=_size.y
+				_size.x/=4
+				_size.y/=3
+			Else
+				RuntimeError( "Invalid Cubemap size" )
+			Endif
+		Endif
+		
+#If Not __DESKTOP_TARGET__
+		If Not IsPow2( _size.x,_size.y ) _flags&=~TextureFlags.Mipmap
+#Endif
+
+		_glTarget=_flags & TextureFlags.Cubemap ? GL_TEXTURE_CUBE_MAP Else GL_TEXTURE_2D
+		_glInternalFormat=glInternalFormat( _format )
+		_glFormat=glFormat( _format )
+		_glType=glType( _format )
+		
+		If Not (_flags & TextureFlags.Dynamic)
 			_managed=New Pixmap( width,height,format )
 			_managed.Clear( Color.Magenta )
 			AddDependancy( _managed )
 		Endif
-		
 	End
 	
-	Property Rect:Recti()
-	
-		Return _rect
+	Property Size:Vec2i()
+		
+		Return _size
 	End
 	
 	Property Width:Int()
 	
-		Return _rect.Width
+		Return _size.x
 	End
 	
 	Property Height:Int()
 	
-		Return _rect.Height
+		Return _size.y
 	End
 	
 	Property Format:PixelFormat()
@@ -104,6 +177,11 @@ Class Texture Extends Resource
 		Return _format
 	End
 	
+	Property Flags:TextureFlags()
+		
+		Return _flags
+	End
+	
 	Method PastePixmap( pixmap:Pixmap,x:Int,y:Int )
 	
 		If _managed
@@ -111,9 +189,9 @@ Class Texture Extends Resource
 			_managed.Paste( pixmap,x,y )
 			
 			_dirty|=Dirty.TexImage|Dirty.Mipmaps
+			
 		Else
-		
-			glPushTexture2d( GLTexture )
+			glPushTexture( _glTarget,ValidateGLTexture() )
 			
 			glPixelStorei( GL_UNPACK_ALIGNMENT,1 )
 			
@@ -125,7 +203,7 @@ Class Texture Extends Resource
 				Next
 			Endif
 			
-			glPopTexture2d()
+			glPopTexture()
 			
 			_dirty|=Dirty.Mipmaps
 			
@@ -187,183 +265,134 @@ Class Texture Extends Resource
 	End
 	
 	Function ColorTexture:Texture( color:Color )
-		Local texture:=_colorTextures[color]
+
+		Global _cache:=New Map<Color,Texture>
+		
+		Local texture:=_cache[color]
 		If Not texture
 			Local pixmap:=New Pixmap( 1,1 )
 			pixmap.Clear( color )
 			texture=New Texture( pixmap,Null )
-			_colorTextures[color]=texture
+			_cache[color]=texture
 		Endif
 		Return texture
 	End
 
+	'***** INTERNAL *****
+		
 	#rem monkeydoc @hidden
-	#end	
-	Property GLTexture:GLuint()
+	#end
+	Method Modified( r:Recti )
 	
-		If _texSeq=glGraphicsSeq And Not _dirty Return _glTexture
+		If _managed
+			glPixelStorei( GL_PACK_ALIGNMENT,1 )
+			glReadPixels( r.X,r.Y,r.Width,r.Height,GL_RGBA,GL_UNSIGNED_BYTE,_managed.PixelPtr( r.X,r.Y ) )
+		Endif
 		
-		If _discarded Return 0
+		_dirty|=Dirty.Mipmaps
+	End
+	
+	#rem monkeydoc @hidden
+	#end
+	Method Bind( unit:GLenum )
 		
-		If _texSeq=glGraphicsSeq
+		glActiveTexture( GL_TEXTURE0+unit )
+
+		glBindTexture( _glTarget,ValidateGLTexture() )
+	End
+	
+	#rem monkeydoc @hidden
+	#end
+	Method ValidateGLTexture:GLuint()
 		
-			glPushTexture2d( _glTexture )
+		If _glSeq=glGraphicsSeq And Not _dirty Or _discarded Return _glTexture
 		
-		Else
-
-			_texSeq=glGraphicsSeq
-			_dirty=Dirty.All
+		glCheck()
 		
+		If _glSeq<>glGraphicsSeq 
 			glGenTextures( 1,Varptr _glTexture )
+			_glSeq=glGraphicsSeq
+			_dirty=Dirty.All
+		Endif
+			
+		glPushTexture( _glTarget,_glTexture )
 
-			glPushTexture2d( _glTexture )
+		If _dirty & Dirty.TexParams
 			
 			If _flags & TextureFlags.WrapS
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT )
+				glTexParameteri( _glTarget,GL_TEXTURE_WRAP_S,GL_REPEAT )
 			Else
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE )
+				glTexParameteri( _glTarget,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE )
 			Endif
 			
 			If _flags & TextureFlags.WrapT
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT )
+				glTexParameteri( _glTarget,GL_TEXTURE_WRAP_T,GL_REPEAT )
 			Else
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE )
+				glTexParameteri( _glTarget,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE )
 			Endif
 			
-		Endif
-		
-		If _dirty & Dirty.Filter
-
-			'mag filter		
-			If _filter=TextureFilter.Mipmap Or _filter=TextureFilter.Linear
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR )
-			Else
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
-			Endif
-
-			'min filter			
-			If _filter=TextureFilter.Mipmap
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR )
-			Else If _filter=TextureFilter.Linear
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR )
+			If _flags & TextureFlags.Mipmap
+				If _flags & TextureFlags.Filter
+					glTexParameteri( _glTarget,GL_TEXTURE_MAG_FILTER,GL_LINEAR )
+					glTexParameteri( _glTarget,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR )
+				Else
+					glTexParameteri( _glTarget,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+					glTexParameteri( _glTarget,GL_TEXTURE_MIN_FILTER,GL_NEAREST_MIPMAP_NEAREST )
+				Endif
+			Else If _flags & TextureFlags.Filter
+				glTexParameteri( _glTarget,GL_TEXTURE_MAG_FILTER,GL_LINEAR )
+				glTexParameteri( _glTarget,GL_TEXTURE_MIN_FILTER,GL_LINEAR )
 			Else
-				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST )
+				glTexParameteri( _glTarget,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+				glTexParameteri( _glTarget,GL_TEXTURE_MIN_FILTER,GL_NEAREST )
 			Endif
-		
+			
+			glCheck()
 		Endif
 		
 		If _dirty & Dirty.TexImage
-		
-			glTexImage2D( GL_TEXTURE_2D,0,glFormat( _format ),Width,Height,0,glFormat( _format ),GL_UNSIGNED_BYTE,Null )
-			
-			If _managed
-				glPixelStorei( GL_UNPACK_ALIGNMENT,1 )
 			
-				If _managed.Pitch=_managed.Width*_managed.Depth
-					glTexSubImage2D( GL_TEXTURE_2D,0,0,0,_managed.Width,_managed.Height,glFormat( _format ),GL_UNSIGNED_BYTE,_managed.Data )
-				Else
-					For Local iy:=0 Until Height
-						glTexSubImage2D( GL_TEXTURE_2D,0,0,iy,Width,1,glFormat( _format ),GL_UNSIGNED_BYTE,_managed.PixelPtr( 0,iy ) )
-					Next
-				Endif
-				
-				glFlush()	'macos nvidia bug!
-				
-			Else
-				Local tmp:=New Pixmap( Width,1,Format )
-				tmp.Clear( Color.Red )
+			If _glTarget=GL_TEXTURE_CUBE_MAP
+
+				Const cubeFaces:=New GLenum[]( 
+					GL_TEXTURE_CUBE_MAP_NEGATIVE_X,GL_TEXTURE_CUBE_MAP_POSITIVE_Z,GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+					GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,GL_TEXTURE_CUBE_MAP_POSITIVE_Y,GL_TEXTURE_CUBE_MAP_NEGATIVE_Y )
+					
+				Const offsets:=New Int[]( 0,1, 1,1, 2,1, 3,1, 1,0, 1,2 )
 				
-				For Local iy:=0 Until Height
-					glTexSubImage2D( GL_TEXTURE_2D,0,0,iy,Width,1,glFormat( _format ),GL_UNSIGNED_BYTE,tmp.Data )
+				For Local i:=0 Until 6
+					If _managed
+						Local image:=_managed.Window( offsets[i*2]*Width,offsets[i*2+1]*Height,Width,Height )
+						UploadTexImage2D( cubeFaces[i],image )
+					Else
+						ClearTexImage2D( cubeFaces[i] )
+					Endif
 				Next
-				
-				glFlush()	'macos nvidia bug!
-				
-				tmp.Discard()
-			Endif
-
-		Endif
-		
-		If _dirty & Dirty.Mipmaps
-			If _filter=TextureFilter.Mipmap
-				glGenerateMipmap( GL_TEXTURE_2D )
-				_mipsDirty&=~Dirty.Mipmaps
 			Else
-				_mipsDirty|=Dirty.Mipmaps	'mipmap still dirty!
+				If _managed
+					UploadTexImage2D( _glTarget,_managed )
+				Else
+					ClearTexImage2D( _glTarget )
+				Endif
 			Endif
-		End
-		
-		_dirty=Null
-		
-		glPopTexture2d()
-		
-		Return _glTexture
-	End
-	
-	#rem monkeydoc @hidden
-	#end	
-	Property GLFramebuffer:GLuint()
-		If _discarded Return 0
-	
-		If _fbSeq=glGraphicsSeq Return _glFramebuffer
-		
-		glGenFramebuffers( 1,Varptr _glFramebuffer )
-			
-		glPushFramebuffer( _glFramebuffer )
 			
-		glBindFramebuffer( GL_FRAMEBUFFER,_glFramebuffer )
-		glFramebufferTexture2D( GL_FRAMEBUFFER,GL_COLOR_ATTACHMENT0,GL_TEXTURE_2D,GLTexture,0 )
-			
-		If glCheckFramebufferStatus( GL_FRAMEBUFFER )<>GL_FRAMEBUFFER_COMPLETE RuntimeError( "Incomplete framebuffer" )
-			
-		glPopFramebuffer()
+			glCheck()
 		
-		_fbSeq=glGraphicsSeq
-
-		Return _glFramebuffer
-	End
-
-	#rem monkeydoc @hidden
-	#end	
-	Method Bind( unit:Int,filter:TextureFilter )
-	
-		If _discarded Print "Binding discarded texture!"
-	
-		If _boundSeq<>glGraphicsSeq
-			_boundSeq=glGraphicsSeq
-			For Local i:=0 Until 8
-				_bound[i]=0
-			Next
 		Endif
 		
-		If filter<>_filter
-			If filter=TextureFilter.Mipmap And (_flags & TextureFlags.DisableMipmap) filter=TextureFilter.Linear
-			If filter<>_filter
-				If filter=TextureFilter.Mipmap _dirty|=_mipsDirty
-				_dirty|=Dirty.Filter
-				_filter=filter
-			Endif
-		Endif
-		
-		Local gltex:=GLTexture
-		If gltex=_bound[unit] Return
+		If _dirty & Dirty.Mipmaps
+			
+			If _flags & TextureFlags.Mipmap glGenerateMipmap( _glTarget )
+				
+			glCheck()
 		
-		_bound[unit]=gltex
+		End
 		
-		glActiveTexture( GL_TEXTURE0+unit )
-		glBindTexture( GL_TEXTURE_2D,gltex )
-	End
-	
-	#rem monkeydoc @hidden
-	#end
-	Method Modified( r:Recti )
-	
-		If _managed
-			glPixelStorei( GL_PACK_ALIGNMENT,1 )
-			glReadPixels( r.X,r.Y,r.Width,r.Height,GL_RGBA,GL_UNSIGNED_BYTE,_managed.PixelPtr( r.X,r.Y ) )
-		Endif
+		_dirty=Null
 		
-		_dirty|=Dirty.Mipmaps
+		glPopTexture()
+
+		Return _glTexture
 	End
 	
 	Protected
@@ -372,52 +401,91 @@ Class Texture Extends Resource
 	#end	
 	Method OnDiscard() Override
 	
-		If _texSeq=glGraphicsSeq
-			For Local i:=0 Until 8
-				If _bound[i]=_glTexture _bound[i]=0
-			Next
+		If _glSeq=glGraphicsSeq
+'			For Local i:=0 Until 8
+'				If _bound[i]=_glTexture _bound[i]=0
+'			Next
 			glDeleteTextures( 1,Varptr _glTexture )
 		Endif
 		
-		If _fbSeq=glGraphicsSeq
-			glDeleteFramebuffers( 1,Varptr _glFramebuffer )
-		Endif
-		
-		_texSeq=0
-		_fbSeq=0
+		_glSeq=0
 		_glTexture=0
-		_glFramebuffer=0
 		_discarded=True
 	End
 	
 	Private
 	
 	Enum Dirty
-		Filter=		1
+		TexParams=	1
 		TexImage=	2
 		Mipmaps=	4
 		All=		7
 	End
 	
-	Global _boundSeq:Int
-	Global _bound:=New GLuint[8]
-	
-	Field _rect:Recti
+	'Global _boundSeq:Int
+	'Global _bound:=New GLuint[8]
+
+	Field _size:Vec2i
 	Field _format:PixelFormat
 	Field _flags:TextureFlags
 	Field _managed:Pixmap
 	Field _discarded:Bool
 	
-	Field _texSeq:Int
 	Field _dirty:Dirty
-	Field _mipsDirty:Dirty
-	Field _filter:TextureFilter
+	
+	Field _glSeq:Int	
 	Field _glTexture:GLuint
 	
-	Field _fbSeq:Int
-	Field _glFramebuffer:GLuint
+	Field _glTarget:GLenum
+	Field _glInternalFormat:GLenum
+	Field _glFormat:GLenum
+	Field _glType:GLenum
+	
+	Method UploadTexImage2D( glTarget:GLenum,image:Pixmap )
+		glCheck()
+		
+		Local width:=image.Width,height:=image.Height
+
+		glPixelStorei( GL_UNPACK_ALIGNMENT,1 )
+	
+		If image.Pitch=width*image.Depth
+			glTexImage2D( glTarget,0,_glInternalFormat,width,height,0,_glFormat,_glType,image.Data )
+		Else
+			glTexImage2D( glTarget,0,_glInternalFormat,width,height,0,_glFormat,_glType,Null )
+			For Local y:=0 Until height
+				glTexSubImage2D( glTarget,0,0,y,width,1,_glFormat,_glType,image.PixelPtr( 0,y ) )
+			Next
+		Endif
+		
+		glFlush() 'macos nvidia bug!
+		
+		glCheck()
+	End
 	
-	Global _colorTextures:Map<Color,Texture>
+	Method ClearTexImage2D( glTarget:GLenum )
+		glCheck()
+		
+		Local width:=_size.x,height:=_size.y
+		
+		glTexImage2D( glTarget,0,_glInternalFormat,width,height,0,_glFormat,_glType,Null )
+		
+		If Not IsDepth( _format )
+			
+			Local image:=New Pixmap( width,1,Format )
+			image.Clear( Color.Magenta )
+			
+			For Local iy:=0 Until height
+				glTexSubImage2D( glTarget,0,0,iy,width,1,_glFormat,_glType,image.Data )
+			Next
+			
+			glFlush() 'macos nvidia bug!
+			
+			image.Discard()
+		
+		Endif
+		
+		glCheck()
+	End
 	
 End
 

+ 187 - 132
modules/mojo/graphics/uniformblock.monkey2

@@ -5,189 +5,244 @@ Namespace mojo.graphics
 #end
 Class UniformBlock Extends Resource
 
-	#rem monkeydoc Sets a scalar uniform.
-	#end
-	Method SetScalar( uniform:String,scalar:Float )
-		Local id:=GetUniformId( uniform )
-		_scalars[id]=scalar
-		_seq=_gseq
-		_gseq+=1
+	Method New( name:Int )
+		_name=name
 	End
 	
-	#rem monkeydoc Gets a scalar uniform.
-	#end
-	Method GetScalar:Float( uniform:String )
-		Local id:=GetUniformId( uniform )
-		Return _scalars[id]
+	Property Name:Int()
+		Return _name
+	End
+	
+	Function GetUniformId:Int( name:String,block:Int )
+		Local ids:=_ids[block]
+		If Not ids
+			ids=New StringMap<Int>
+			_ids[block]=ids
+		Endif
+		Local id:=ids[name]
+		If Not id
+			id=ids.Count()+1
+			ids[name]=id
+		Endif
+		Return id
+	End
+	
+	Method GetUniformId:Int( name:String )
+		Return GetUniformId( name,_name )
+	End
+	
+	Method GetUniformId:Int( name:String,type:Type )
+		Local id:=GetUniformId( name,_name )
+		DebugAssert( _uniforms[id].type=type,"Invalid uniform type" )
+		Return id
 	End
 
-	Method GetScalar:Float( id:Int )
-		Return _scalars[id]
+	'***** Float *****
+	'	
+	Method SetFloat( uniform:String,value:Float )
+		SetFloatData( uniform,value,Type.Scalar )
 	End
 	
-	#rem monkeydoc Sets a vector uniform.
-	#end
-	Method SetVector( uniform:String,color:Color )
-		Local id:=GetUniformId( uniform )
-		_vectors[id]=New Vec4f( color.r,color.g,color.b,color.a )
-		_seq=_gseq
-		_gseq+=1
+	Method GetFloat:Float( uniform:String )
+		Return GetFloatData<Float>( uniform,Type.Scalar )
+	End
+	
+	Method GetFloat:Float( id:Int )
+		Return GetFloatPtr( id,Type.Scalar )[0]
+	End
+	
+	'***** Vec2f *****
+	'
+	Method SetVec2f( uniform:String,value:Vec2f )
+		SetFloatData( uniform,value,Type.Vec2f )
+	End
+	
+	method GetVec2f:Vec2f( uniform:String )
+		Return GetFloatData<Vec2f>( uniform,Type.Vec2f )
+	End
+	
+	Method GetVec2fv:Float Ptr( id:Int )
+		Return GetFloatPtr( id,Type.Vec2f )
+	End
+	
+	'***** Vec3f *****
+	'
+	Method SetVec3f( uniform:String,value:Vec3f )
+		SetFloatData( uniform,value,Type.Vec3f )
 	End
 
-	Method SetVector( uniform:String,vector:Vec2f )
-		Local id:=GetUniformId( uniform )
-		_vectors[id]=New Vec4f( vector.x,vector.y,0,0 )
-		_seq=_gseq
-		_gseq+=1
+	Method GetVec3f:Vec3f( uniform:String )
+		Return GetFloatData<Vec3f>( uniform,Type.Vec3f )
+	End
+	
+	Method GetVec3fv:Float Ptr( id:Int )
+		Return GetFloatPtr( id,Type.Vec3f )
 	End
 
-	Method SetVector( uniform:String,vector:Vec3f )
-		Local id:=GetUniformId( uniform )
-		_vectors[id]=New Vec4f( vector.x,vector.y,vector.z,0 )
-		_seq=_gseq
-		_gseq+=1
+	'***** Vec4f *****
+	'	
+	Method SetVec4f( uniform:String,value:Vec4f )
+		SetFloatData( uniform,value,Type.Vec4f )
+	End
+
+	Method GetVec4f:Vec4f( uniform:String )
+		Return GetFloatData<Vec4f>( uniform,Type.Vec4f )
 	End
 	
-	Method SetVector( uniform:String,vector:Vec4f )
-		Local id:=GetUniformId( uniform )
-		_vectors[id]=vector
-		_seq=_gseq
-		_gseq+=1
+	Method GetVec4fv:Float Ptr( id:Int )
+		Return GetFloatPtr( id,Type.Vec4f )
 	End
 	
-	#rem monkeydoc Gets a vector uniform.
-	#end
-	Method GetVector:Vec4f( uniform:String )
-		Local id:=GetUniformId( uniform )
-		Return _vectors[id]
+	'***** Mat3f *****
+	'
+	Method SetMat3f( uniform:String,value:Mat3f )
+		SetFloatData( uniform,value,Type.Mat3f )
+	End
+
+	Method GetMat3f:Mat3f( uniform:String )
+		Return GetFloatData<Mat3f>( uniform,Type.Mat3f )
 	End
 	
-	Method GetVector:Vec4f( id:Int )
-		Return _vectors[id]
+	Method GetMat3fv:Float Ptr( id:Int )
+		Return GetFloatPtr( id,Type.Mat3f )
 	End
 	
-	#rem monkeydoc @hidden
-	#end	
-	Method GetVector4fv:Float Ptr( id:Int )
-		Return Varptr _vectors[id].x
+	'***** Mat4f *****
+	'
+	Method SetMat4f( uniform:String,value:Mat4f )
+		SetFloatData( uniform,value,Type.Mat4f )
+	End
+
+	Method SetMat4f( uniform:String,value:AffineMat4f )
+		SetFloatData( uniform,New Mat4f( value ),Type.Mat4f )
+	End
+
+	Method GetMat4f:Mat4f( uniform:String )
+		Return GetFloatData<Mat4f>( uniform,Type.Mat4f )
 	End
 	
-	#rem monkeydoc Sets a matrix uniform.
-	#end
-	Method SetMatrix( uniform:String,matrix:Mat4f )
+	Method GetMat4fv:Float Ptr( id:Int )
+		Return GetFloatPtr( id,Type.Mat4f )
+	End
+	
+	'***** Mat4f array *****
+	'
+	Method SetMat4fArray( uniform:String,value:Mat4f[] )
 		Local id:=GetUniformId( uniform )
-		_matrices[id]=matrix
+		_uniforms[id].mat4fArray=value
+		_uniforms[id].type=Type.Mat4fArray
 		_seq=_gseq
 		_gseq+=1
 	End
 	
-	#rem monkeydoc Gets a matrix uniform.
-	#end
-	Method GetMatrix:Mat4f( uniform:String )
+	Method GetMat4fArray:Mat4f[]( uniform:String )
 		Local id:=GetUniformId( uniform )
-		Return _matrices[id]
-	End
-	
-	Method GetMatrix:Mat4f( id:Int )
-		Return _matrices[id]
+		DebugAssert( _uniforms[id].type=Type.Mat4fArray,"Invalid uniform type" )
+		Return _uniforms[id].mat4fArray
 	End
 
-	#rem monkeydoc @hidden
-	#end	
-	Method GetMatrix4fv:Float Ptr( id:Int )
-		Return Varptr _matrices[id].i.x
+	Method GetMat4fArrayv:Float Ptr( id:Int )
+		DebugAssert( _uniforms[id].type=Type.Mat4fArray,"Invalid uniform type" )
+		Return Varptr _uniforms[id].mat4fArray[0].i.x
 	End
-
-	#rem monkeydoc Set a texture uniform.
-	#end	
-	Method SetTexture( uniform:String,texture:Texture )
+	
+	'***** Texture *****
+	'
+	Method SetTexture( uniform:String,value:Texture )
 		Local id:=GetUniformId( uniform )
-		If texture texture.Retain()
-		If _textures[id] _textures[id].Release()
-		_textures[id]=texture
+		_uniforms[id].texture=value
+		_uniforms[id].type=Type.Texture
 		_seq=_gseq
 		_gseq+=1
 	End
 
-	#rem monkeydoc Gets a texture uniform.
-	#end	
 	Method GetTexture:Texture( uniform:String )
 		Local id:=GetUniformId( uniform )
-		Return _textures[id]
+		DebugAssert( _uniforms[id].type=Type.Texture,"Invalid uniform type" )
+		Return _uniforms[id].texture
 	End
 	
 	Method GetTexture:Texture( id:Int )
-		Return _textures[id]
+		DebugAssert( _uniforms[id].type=Type.Texture,"Invalid uniform type" )
+		Return _uniforms[id].texture
 	End
-
-	#rem monkeydoc Gets the id of a uniform name.
-	#end	
-	Function GetUniformId:Int( uniform:String )
-		Init()
-		Local id:=_uniformIds[uniform]
-		If Not id
-			id=_uniformIds.Count()+1
-			_uniformIds[uniform]=id
-		Endif
-		Return id
-	End
-
+	
 	#rem monkeydoc @hidden
 	#end	
 	Property Seq:Int()
 		Return _seq
 	End
 	
-	#rem monkeydoc @hidden
-	#end	
-	Function BindUniformsToBlockId( uniforms:String[],index:Int )
-		For Local uniform:=Eachin uniforms
-			_blockIds[ GetUniformId( uniform ) ]=index
-		Next
-	End
-	
-	#rem monkeydoc @hidden
-	#end	
-	Function GetUniformBlockId:Int( uniform:String )
-		Return _blockIds[ GetUniformId( uniform ) ]
-	End
+	Private
 	
-	Protected
+	Field _name:Int
 	
-	Method OnDiscard() Override
+	Field _seq:Int
 	
-		For Local t:=Eachin _textures
-			If t t.Release()
-		Next
+	Global _gseq:Int
+	Global _ids:=New StringMap<Int>[8]
+	
+	Enum Type
+		None=0
+		Scalar=1
+		Vec2f=2
+		Vec3f=3
+		Vec4f=4
+		Mat3f=5
+		Mat4f=6
+		Texture=7
+		Mat4fArray=8
+	End
+	
+	Struct Uniform
+		Field type:Type
+
+		Field mat4fArray:Mat4f[]
+		Field texture:Texture
+		
+		'yuck...		
+		Field fdata0:Mat4f
+		Field fdata1:Mat4f
+		Field fdata2:Mat4f
+		Field fdata3:Mat4f
+		Field fdata4:Mat4f
+		Field fdata5:Mat4f
+		Field fdata6:Mat4f
+		Field fdata7:Mat4f
+		
+		Method SetFloatData<T>( t:T,type:Type )
+			Cast<T Ptr>(Varptr fdata0.i.x)[0]=t
+			Self.type=type
+		End
+		
+		Method GetFloatData<T>:T()
+			Return Cast<T Ptr>(Varptr fdata0.i.x)[0]
+		End
+		
+		Method GetFloatPtr:Float Ptr()
+			Return Cast<Float Ptr>(Varptr fdata0.i.x)
+		End
+		
+	End
+	
+	Field _uniforms:=New Uniform[32]
+	
+	Method SetFloatData<T>( uniform:String,data:T,type:Type )
+		Local id:=GetUniformId( uniform )
+		_uniforms[id].SetFloatData( data,type )
+		_seq=_gseq
+		_gseq+=1
 	End
 	
-	Private
-	
-	Field _seq:Int
-	Global _gseq:Int
-
-	Field _scalars:=New Float[MaxUniforms]
-	Field _vectors:=New Vec4f[MaxUniforms]
-	Field _matrices:=New Mat4f[MaxUniforms]
-	Field _textures:=New Texture[MaxUniforms]
+	Method GetFloatData<T>:T( uniform:String,type:Type )
+		Local id:=GetUniformId( uniform )
+		DebugAssert( _uniforms[id].type=type,"Invalid uniform type" )
+		Return _uniforms[id].GetFloatData<T>()
+	End
 	
-	Global _uniformIds:=New StringMap<Int>
-	Global _blockIds:=New Int[MaxUniforms]
-
-	Const MaxUniforms:=32
-
-	Function Init()
-		Global inited:=False
-		If inited Return	
-		inited=True
-	
-		UniformBlock.BindUniformsToBlockId( New String[]( "mx2_ViewportSize","mx2_ViewportOrigin","mx2_ViewportClip" ),0 )
-		UniformBlock.BindUniformsToBlockId( New String[]( "mx2_AmbientLight" ),0 )
-		UniformBlock.BindUniformsToBlockId( New String[]( "mx2_ModelViewProjectionMatrix" ),0 )
-		UniformBlock.BindUniformsToBlockId( New String[]( "mx2_GBuffer0","GBuffer1","GBufferScale" ),0 )
-
-		UniformBlock.BindUniformsToBlockId( New String[]( "mx2_ImageTexture0","mx2_ImageTexture1" ),1 )
-		UniformBlock.BindUniformsToBlockId( New String[]( "mx2_ImageColor","mx2_LightDepth" ),1 )
+	Method GetFloatPtr:Float Ptr( id:Int,type:Type )
+		DebugAssert( _uniforms[id].type=type,"Invalid uniform type" )
+		Return _uniforms[id].GetFloatPtr()
 	End
-
+	
 End

+ 54 - 0
modules/mojo/graphics/vertex2f.monkey2

@@ -0,0 +1,54 @@
+
+Namespace mojo.graphics
+
+Struct Vertex2f
+
+	Field position:Vec2f
+	Field texCoord0:Vec2f
+	Field texCoord1:Vec2f
+	Field color:UInt
+	
+	Method New()
+	End
+	
+	Method New( x:Float,y:Float,s0:Float=0,t0:Float=0,s1:Float=0,t1:Float=0,color:UInt=~0 )
+		position.x=x
+		position.y=y
+		texCoord0.x=s0
+		texCoord0.y=t0
+		texCoord1.x=s1
+		texCoord1.y=t1
+		Self.color=color
+	End
+	
+	Method New( position:Vec2f,texCoord0:Vec2f=Null,texCoord1:Vec2f=Null,color:UInt=~0 )
+		Self.position=position
+		Self.texCoord0=texCoord0
+		Self.texCoord1=texCoord1
+		Self.color=color
+	End
+	
+	Operator To:String()
+		Return "Vertex2f("+position+")"
+	End
+	
+End
+
+Class Vertex2fFormat Extends VertexFormat
+	
+	Const Instance:=New Vertex2fFormat
+	
+	Property Pitch:Int() Override
+		
+		Return 28
+	End
+
+	Method UpdateGLAttribs() Override
+		
+		glEnableVertexAttribArray( A_POSITION ) ; glVertexAttribPointer( A_POSITION,2,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 0 ) )
+		glEnableVertexAttribArray( A_TEXCOORD0 ) ; glVertexAttribPointer( A_TEXCOORD0,2,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 8 ) )
+		glEnableVertexAttribArray( A_TEXCOORD1 ) ; glVertexAttribPointer( A_TEXCOORD1,2,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 16 ) )
+		glEnableVertexAttribArray( A_COLOR ) ; glVertexAttribPointer( A_COLOR,4,GL_UNSIGNED_BYTE,True,Pitch,Cast<Void Ptr>( 24 ) )
+	End
+	
+End

+ 90 - 0
modules/mojo/graphics/vertex3f.monkey2

@@ -0,0 +1,90 @@
+
+Namespace mojo.graphics
+
+Struct Vertex3f
+
+	Field position:Vec3f	'0
+	Field texCoord0:Vec2f	'12
+	Field normal:Vec3f		'20
+	Field tangent:Vec4f		'32
+	Field weights:Vec4f		'48
+	Field bones:UInt		'64
+
+	Const Pitch:=68			'68
+	
+	Method New()
+	End
+	
+	Method New( x:Float,y:Float,z:Float,s0:Float=0,t0:Float=0,nx:Float=0,ny:Float=0,nz:Float=0 )
+		position.x=x
+		position.y=y
+		position.z=z
+		texCoord0.x=s0
+		texCoord0.y=t0
+		normal.x=nx
+		normal.y=ny
+		normal.z=nz
+	End
+	
+	Method New( position:Vec3f,texCoord0:Vec2f=New Vec2f,normal:Vec3f=New Vec3f )
+		Self.position=position
+		Self.texCoord0=texCoord0
+		Self.normal=normal
+	End
+	
+	Operator To:String()
+		Return "Vertex3f("+position+")"
+	End
+	
+	Property Tx:Float()
+		Return position.x
+	Setter( tx:Float )
+		position.x=tx
+	End
+	
+	Property Ty:Float()
+		Return position.y
+	Setter( ty:Float )
+		position.y=ty
+	End
+	
+	Property Tz:Float()
+		Return position.z
+	Setter( tz:Float )
+		position.z=tz
+	End
+
+	Property Sx:Float()
+		Return texCoord0.x
+	Setter( sx:Float )
+		texCoord0.x=sx
+	End
+	
+	Property Sy:Float()
+		Return texCoord0.y
+	Setter( sy:Float )
+		texCoord0.y=sy
+	End
+	
+End
+
+Class Vertex3fFormat Extends VertexFormat
+
+	Const Instance:=New Vertex3fFormat
+	
+	Property Pitch:Int() Override
+		
+		Return 68
+	End
+
+	Method UpdateGLAttribs() Override
+		
+		glEnableVertexAttribArray( A_POSITION ) ; glVertexAttribPointer( A_POSITION,3,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 0 ) )
+		glEnableVertexAttribArray( A_TEXCOORD0 ) ; glVertexAttribPointer( A_TEXCOORD0,2,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 12 ) )
+		glEnableVertexAttribArray( A_NORMAL ) ; glVertexAttribPointer( A_NORMAL,3,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 20 ) )
+		glEnableVertexAttribArray( A_TANGENT ) ; glVertexAttribPointer( A_TANGENT,4,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 32 ) )
+		glEnableVertexAttribArray( A_WEIGHTS ) ; glVertexAttribPointer( A_WEIGHTS,4,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 48 ) )
+		glEnableVertexAttribArray( A_BONES ) ; glVertexAttribPointer( A_BONES,4,GL_UNSIGNED_BYTE,False,Pitch,Cast<Void Ptr>( 64 ) )
+	End
+	
+End

+ 89 - 41
modules/mojo/graphics/vertexbuffer.monkey2

@@ -1,95 +1,143 @@
 
 Namespace mojo.graphics
 
+#rem monkeydoc @hidden
+#end	
+Class VertexFormat
+	
+	Property Pitch:Int() Abstract
+
+	Method UpdateGLAttribs() Abstract
+End
+
 #rem monkeydoc @hidden
 #end	
 Class VertexBuffer
 
-	Method New( capacity:Int )
-	
+	Method New( format:VertexFormat,capacity:Int )
+		_format=format
 		_capacity=capacity
+		_pitch=_format.Pitch
+		_length=0
+		_clean=0
+		_data=New UByte[_capacity*_pitch]
+	End
+	
+	Method New( vertices:VertexBuffer )
+		_format=vertices._format
+		_capacity=vertices._capacity
+		_pitch=vertices._pitch
+		_length=vertices._length
+		_clean=0
+		_data=vertices._data.Slice( 0 )
+	End
+	
+	Method New( vertices:Vertex3f[] )
+		Self.New( Vertex3fFormat.Instance,vertices.Length )
 		
-		_data=New Vertex2f[_capacity]
+		libc.memcpy( AddVertices( vertices.Length ),vertices.Data,_capacity*_pitch )
+	End
+	
+	Property Data:UByte Ptr()
+		
+		Return _data.Data
+	End
+	
+	Property Format:VertexFormat()
+		
+		Return _format
 	End
 	
 	Property Capacity:Int()
 	
 		Return _capacity
 	End
-
-	Property Length:Int()
 	
-		Return _length
+	Property Pitch:Int()
+		
+		Return _pitch
 	End
 	
-	Property Pitch:Int()
+	Property Length:Int()
 	
-		Return 28
+		Return _length
 	End
 	
 	Method Clear()
-	
 		_length=0
 		_clean=0
 	End
 	
-	Method AddVertices:Vertex2f Ptr( count:Int )
-		If _length+count>_capacity Return Null
+	Method Invalidate()
+		_clean=0
+	End
+	
+	Method AddVertices:UByte Ptr( count:Int )
+		Reserve( _length+count )
+
+		Local p:=_data.Data+_length*_pitch
 		
-		Local p:=_data.Data+_length
 		_length+=count
 		
 		Return p
 	End
-	
+
 	'***** INTERNAL *****
 	
 	Method Bind()
-	
-		If _seq<>glGraphicsSeq
-			_seq=glGraphicsSeq
+		
+		If _glSeq<>glGraphicsSeq
+			
+			glGenBuffers( 1,Varptr _glBuffer )
+			glBindBuffer( GL_ARRAY_BUFFER,_glBuffer )
+			
+			glBufferData( GL_ARRAY_BUFFER,_capacity*_pitch,Null,GL_DYNAMIC_DRAW )
+'			Print "bound vb "+_glBuffer
+			
+			_glSeq=glGraphicsSeq
 			_clean=0
-			glGenBuffers( 1,Varptr _glvbo )
-			glBindBuffer( GL_ARRAY_BUFFER,_glvbo )
-			glBufferData( GL_ARRAY_BUFFER,_capacity * Pitch,Null,GL_DYNAMIC_DRAW )
 		Else
-			glBindBuffer( GL_ARRAY_BUFFER,_glvbo )
+			glBindBuffer( GL_ARRAY_BUFFER,_glBuffer )
+'			Print "bound vb "+_glBuffer
 		Endif
 		
-		glEnableVertexAttribArray( 0 ) ; glVertexAttribPointer( 0,2,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 0 ) )
-		glEnableVertexAttribArray( 1 ) ; glVertexAttribPointer( 1,2,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 8 ) )
-		glEnableVertexAttribArray( 2 ) ; glVertexAttribPointer( 2,2,GL_FLOAT,False,Pitch,Cast<Void Ptr>( 16 ) )
-		glEnableVertexAttribArray( 3 ) ; glVertexAttribPointer( 3,4,GL_UNSIGNED_BYTE,True,Pitch,Cast<Void Ptr>( 24 ) )
-
+		_format.UpdateGLAttribs()
+			
 	End
 	
 	Method Validate()
 	
-		If _clean=_length Return
-		
-		_clean=_length
+		If _length=_clean Return
 		
-		'mythical 'orphaning'...
-'		glBufferData( GL_ARRAY_BUFFER,_capacity*Pitch,Null,GL_DYNAMIC_DRAW )	
+		glBufferData( GL_ARRAY_BUFFER,_length*_pitch,_data.Data,GL_DYNAMIC_DRAW )
+'		Print "updated vb "+_glBuffer
 
-'		glBufferSubData( GL_ARRAY_BUFFER,0,_length*Pitch,_data.Data )
-
-		'lazy - but fastest?
-		glBufferData( GL_ARRAY_BUFFER,_length*Pitch,_data.Data,GL_DYNAMIC_DRAW )
+		_clean=_length
 	End
 		
 	Private
 	
+	Field _format:VertexFormat
 	Field _capacity:Int
-	
+	Field _pitch:int
 	Field _length:Int
-	
 	Field _clean:Int
+	Field _data:UByte[]
 	
-	Field _data:Vertex2f[]
-	
-	Field _glvbo:GLuint
-	
-	Field _seq:Int
+	Field _glSeq:Int
+	Field _glBuffer:GLuint
+
+	Method Reserve( capacity:Int )
+		
+		If _capacity>=capacity Return
+		
+		_capacity=Max( _length*2+_length,capacity )
+		
+		Local data:=New UByte[_capacity*_pitch]
+		
+		libc.memcpy( data.Data,_data.Data,_length*_pitch )
+		
+		_data=data
+	End
 
 End