Browse Source

Tweaked shader system; added canvas.FilteringEnabled; more...

Mark Sibly 9 years ago
parent
commit
fcc05057b0

BIN
modules/mojo/bananas/spacechimps/assets/spaceship_32.png


+ 127 - 0
modules/mojo/graphics/assets/shader_env.glsl

@@ -0,0 +1,127 @@
+
+// One of these defined!
+
+//#define RENDERPASS_AMBIENT
+
+//#define RENDERPASS_NORMAL
+
+//#define RENDERPASS_LIGHT
+
+uniform mat4 mx2_ModelViewMatrix;
+uniform mat4 mx2_ProjectionMatrix;
+uniform vec4 mx2_AmbientLight;
+uniform vec4 mx2_RenderColor;
+
+varying vec4 mx2_ViewPosition;
+varying vec4 mx2_Color;
+
+#if defined( RENDERPASS_LIGHT )
+varying vec2 mx2_FragPos;
+#endif
+
+//@vertex
+
+attribute vec4 mx2_VertexPosition;
+attribute vec2 mx2_VertexTexCoord0;
+attribute vec2 mx2_VertexTangent;
+attribute vec4 mx2_VertexColor;
+
+void transform( out vec4 viewpos );
+
+void main(){
+
+	vec4 position;
+	
+	transform( position );
+	
+	mx2_ViewPosition=position;
+	mx2_Color=mx2_RenderColor * mx2_VertexColor;
+	
+	gl_Position=mx2_ProjectionMatrix * position;
+	
+#if defined( RENDERPASS_LIGHT )
+	mx2_FragPos=gl_Position;
+#endif
+}
+
+//@fragment
+
+#if defined( RENDERPASS_LIGHT )
+
+uniform vec4 mx2_LightVector;
+uniform vec4 mx2_LightColor;
+uniform sampler2D mx2_NormalTexture;
+
+#endif
+
+void lighting( out vec4 diffuse,out vec4 specular,out vec4 emissive,out vec3 normal,out float alpha );
+
+void main(){
+
+	vec4 diffuse,specular,emissive;
+	vec3 normal;
+	float alpha;
+	
+	lighting( diffuse,specular,emissive,normal,alpha );
+
+#if defined( RENDERPASS_AMBIENT )
+
+	vec4 color=diffuse * mx2_AmbientLight + emissive;
+	
+	gl_FragColor=vec4( color.rgb,alpha ) * mx2_Color;
+	
+#elif defined( RENDERPASS_NORMAL )
+
+	//write out normal + specular component
+	//
+	gl_FragColor=vec4( normal * alpha,specular.w );
+	
+#elif defined( RENDERPASS_LIGHT )
+
+	vec4 npass=texture2D( mx2_PassTexture,mx2_FragPos );
+	
+	//grab normal
+	vec3 normal=npass.xyz;
+
+	//specular power
+	float gloss=npass.w;
+	float spow=pow( 2.0,gloss*12.0 );
+	float fnorm=(spow+8.0)/25.1327412287;		//	(n+8)/8*pi apparently for blinn-phong...
+
+	//normalized vector to eye	
+	
+	vec3 v=mx2_LightVector.xyz-mx2_ViewPosition.xyz;
+	float falloff=max( 1.0-length( v )/mx2_LightVector.w,0.0 );
+	
+	vec3 lvec=normalize( v );
+	vec3 evec=normalize( -mx2_ViewPosition.xyz );
+	vec3 hvec=normalize( lvec + evec );
+	
+	float ndotv=max( dot( normal,evec ),0.0 );
+	float ndotl=max( dot( normal,lvec ),0.0 );
+	float ndoth=max( dot( normal,hvec ),0.0 );
+	
+	float i=ndtol * falloff;
+	
+	vec3 diff=mx2_LightColor.rgb * i;
+	float spec=mx2_LightColor.w * i * pow( ndoth,spow ) * fnorm;
+	
+	//frenel-ish?
+	spec+=(1.0-spec) * pow( 1.0-ndotv,5.0 ) * gloss;
+	
+	//write diffuse + specular
+	gl_FragColor=vec4( diff,spec );
+	
+#elif defined( RENDERPASS_LIGHT2 )
+
+	vec4 intex=texture2D( mx2_PassTexture,mx2_FragPos );
+	
+	diffuse=diffuse * mx2_AmbientLight + (diffuse * intex.rgb) + emissive;
+	
+	specular=specular * intex.w;
+	
+	gl_FragColor=vec4( (diffuse+specular).rgb,alpha );
+	
+#endif
+
+}

+ 5 - 12
modules/mojo/graphics/assets/shader_font.glsl

@@ -1,8 +1,6 @@
 
 // ***** alpha surface shader *****
 
-varying vec4 Color;
-
 varying vec2 TexCoord0;
 
 //@vertex
@@ -11,21 +9,16 @@ void transform( out vec4 viewpos ){
 
 	viewpos=mx2_ModelViewMatrix * mx2_VertexPosition;
 	
-	Color=mx2_VertexColor * mx2_RenderColor;
-	
 	TexCoord0=mx2_VertexTexCoord0;
 }
 
 //@fragment
 
-uniform sampler2D u_Texture0;
+uniform sampler2D DiffuseTexture;
 
-void ambientPass( out vec4 ambient ){
-
-	ambient=vec4( texture2D( u_Texture0,TexCoord0 ).a ) * Color;
-}
-
-void lightingPass( out vec4 diffuse,out vec4 specular,out vec3 normal ){
+void lighting( out vec4 diffuse,out vec4 specular,out vec4 emissive,out vec3 normal,out float alpha ){
 
+	emissive=vec4( texture2D( DiffuseTexture,TexCoord0 ).a );
+	
+	alpha=emissive.a;
 }
-

+ 6 - 11
modules/mojo/graphics/assets/shader_null.glsl

@@ -1,25 +1,20 @@
 
 // ***** alpha surface shader *****
 
-varying vec4 Color;
-
 //@vertex
 
 void transform( out vec4 viewpos ){
 
 	viewpos=mx2_ModelViewMatrix * mx2_VertexPosition;
-	
-	Color=mx2_VertexColor * mx2_RenderColor;
+
+	gl_PointSize=1.0;
 }
 
 //@fragment
 
-void ambientPass( out vec4 ambient ){
-
-	ambient=Color;
-}
-
-void lightingPass( out vec4 diffuse,out vec4 specular,out vec3 normal ){
+void lighting( out vec4 diffuse,out vec4 specular,out vec4 emissive,out vec3 normal,out float alpha ){
 
+	emissive=vec4( 1.0 );
+	
+	alpha=1.0;
 }
-

+ 13 - 16
modules/mojo/graphics/assets/shader_phong.glsl

@@ -1,33 +1,30 @@
 
 // ***** phong surface shader *****
 
-varying vec2 texCoord0;
+varying vec2 TexCoord0;
 
 //@vertex
 
 void transform( out vec4 viewpos ){
 
-	viewpos=mx2_ModelViewMatrix * mx2_Vertex;
-
-	texCoord0=mx2_TexCoord0;
+	viewpos=mx2_ModelViewMatrix * mx2_VertexPosition;
+	
+	TexCoord0=mx2_VertexTexCoord0;
 }
 
 //@fragment
 
-uniform sampler2D ColorTexture;			//default=white
-uniform sampler2D SpecularTexture;		//default=white
-uniform sampler2D NormalTexture;		//default=smooth
-
-void ambientPass( out vec4 ambient ){
+uniform sampler2D DiffuseTexture;
+uniform sampler2D SpecularTexture;
+uniform sampler2D NormalTexture;
 
-	diffuse=texture2D( ColorTexture,texCoord0 ) * mx2_Color * mx2_AmbientLight;
-}
-
-void lightingPass( out vec4 diffuse,out vec4 specular,out vec4 normal ){
+void lighting( out vec4 diffuse,out vec4 specular,out vec4 emissive,out vec3 normal,out float alpha ){
 
-	diffuse=texture2D( ColorTexture,texCoord0 ) * mx2_Color;
+	diffuse=texture2D( DiffuseTexture,TexCoord0 );
+	
+	specular=texture2D( SpecularTexture,TexCoord0 );
 	
-	specular=texture2D( SpecularTexture,texCoord0 );
+	normal=normalize( mat3( mx2_ModelViewMatrix ) * texture2D( NormalTexture,TexCoord0 ).xyz );
 	
-	normal=normalize( mat3( mx2_ModelViewMatrix ) * texture2D( NormalTexture,texCoord0 ).xyz );
+	alpha=diffuse.a;
 }

+ 6 - 13
modules/mojo/graphics/assets/shader_sprite.glsl

@@ -1,7 +1,5 @@
 
-// ***** matte surface shader *****
-
-varying vec4 Color;
+// ***** sprite surface shader *****
 
 varying vec2 TexCoord0;
 
@@ -11,21 +9,16 @@ void transform( out vec4 viewpos ){
 
 	viewpos=mx2_ModelViewMatrix * mx2_VertexPosition;
 	
-	Color=mx2_VertexColor * mx2_RenderColor;
-	
 	TexCoord0=mx2_VertexTexCoord0;
 }
 
 //@fragment
 
-uniform sampler2D u_Texture0;
+uniform sampler2D DiffuseTexture;
 
-void ambientPass( out vec4 ambient ){
-
-	ambient=texture2D( u_Texture0,TexCoord0 ) * Color;
-}
-
-void lightingPass( out vec4 diffuse,out vec4 specular,out vec3 normal ){
+void lighting( out vec4 diffuse,out vec4 specular,out vec4 emissive,out vec3 normal,out float alpha ){
 
+	emissive=texture2D( DiffuseTexture,TexCoord0 );
+	
+	alpha=emissive.a;
 }
-

+ 0 - 38
modules/mojo/graphics/assets/shaderenv_ambient.glsl

@@ -1,38 +0,0 @@
-
-// ***** ambient shaderenv *****
-
-uniform mat4 mx2_ModelViewMatrix;
-uniform mat4 mx2_ProjectionMatrix;
-uniform vec4 mx2_AmbientLight;
-uniform vec4 mx2_RenderColor;
-
-//@vertex
-
-attribute vec4 mx2_VertexPosition;
-attribute vec2 mx2_VertexTexCoord0;
-attribute vec2 mx2_VertexTangent;
-attribute vec4 mx2_VertexColor;
-
-void transform( out vec4 viewpos );
-
-void main(){
-
-	vec4 position;
-	
-	transform( position );
-	
-	gl_Position=mx2_ProjectionMatrix * position;
-}
-
-//@fragment
-
-void ambientPass( out vec4 ambient );
-
-void main(){
-
-	vec4 ambient;
-	
-	ambientPass( ambient );
-	
-	gl_FragColor=ambient;
-}

+ 0 - 37
modules/mojo/graphics/assets/shaderenv_lighting.glsl

@@ -1,37 +0,0 @@
-
-// ***** ambient shaderenv *****
-
-uniform mat4 mx2_ModelViewMatrix;
-uniform mat4 mx2_ProjectionMatrix;
-uniform vec4 mx2_AmbientLight;
-uniform vec4 mx2_RenderColor;
-
-varying vec4 mx2_Color;
-
-//@vertex
-
-attribute vec4 mx2_Vertex;
-attribute vec2 mx2_TexCoord0;
-attribute vec2 mx2_Tangent;
-attribute vec4 mx2_VertexColor;
-
-void transform( out vec4 viewpos );
-
-void main(){
-	vec4 position;
-	transform( position );
-	gl_Position=mx2_ProjectionMatrix * position;
-	mx2_color=mx2_VertexColor * mx2_RenderColor;
-}
-
-//@fragment
-
-void lightingPass( out vec4 diffuse,out vec4 specular,out vec3 normal );
-
-void main(){
-
-	vec4 diffuse,specular;
-	vec3 normal;
-	
-	lightingPass( ambient,diffuse,specular,normal );
-}

+ 333 - 125
modules/mojo/graphics/canvas.monkey2

@@ -1,7 +1,7 @@
 
 Namespace mojo.graphics
 
-#Import "assets/shaderenv_ambient.glsl@/mojo"
+#Import "assets/shader_env.glsl@/mojo"
 #Import "assets/RobotoMono-Regular.ttf@/mojo"
 
 #rem monkeydoc @hidden
@@ -14,19 +14,45 @@ Class DrawOp
 End
 
 #rem monkeydoc The Canvas class.
+
+Canvas objects are used to perform rendering to either a mojo [[app.View]] or an 'off screen' [[mojo.graphics.Image]].
+
+To draw to a canvas, use one of the 'Draw' methods. Drawing is affected by a number of draw states, including:
+
+* [[Color]] - the current drawing color. This is combined with the current alpha to produce the final rendering color and alpha values.
+
+* [[Alpha]] - the current drawing alpha level.
+
+* [[Matrix]] - the current 2d drawing matrix. All drawing coordinates are multiplied by this matrix before rendering.
+
+* [[BlendMode]] - the blending mode for drawing, eg: opaque, alpha, additive, multiply.
+
+* [[Viewport]] - the current viewport. All drawing coordinates are relative to the top-left of the viewport.
+
+* [[Scissor]] - the current scissor rect. All rendering is clipped to the union of the viewport and the scissor rect.
+
+* [[Font]] - The current font to use when drawing text with [[DrawText]].
+
+Drawing does not occur immediately. Drawing commands are 'buffered' to reduce the overhead of sending lots of draw calls to the lower level graphics API. You
+can force all drawing commands in the buffer to actually render using [[Flush]].
+
 #end
 Class Canvas
 
 	Method New( image:Image )
 	
 		Init( image.Texture,image.Texture.Rect.Size,image.Rect )
+		
+		BeginRender( New Recti( 0,0,image.Rect.Size ),New AffineMat3f )
 	End
 	
 	#rem monkeydoc @hidden
 	#end
 	Method New( texture:Texture )
 	
-		Init( texture,texture.Rect.Size,New Recti( 0,0,texture.Rect.Size ) )
+		Init( texture,texture.Rect.Size,texture.Rect )
+		
+		BeginRender( texture.Rect,New AffineMat3f )
 	End
 
 	#rem monkeydoc @hidden
@@ -36,6 +62,13 @@ Class Canvas
 		Init( Null,New Vec2i( width,height ),New Recti( 0,0,width,height ) )
 	End
 	
+	#rem monkeydoc The current viewport.
+	
+	The viewport describes the rect rendering actually occurs in.
+	
+	All rendering is relative to the top-left of the viewport, and clipped to the intersection of the current viewport and scissor rect.
+		
+	#end
 	Property Viewport:Recti()
 	
 		Return _viewport
@@ -46,9 +79,16 @@ Class Canvas
 		
 		_viewport=viewport
 		
-		_dirty|=Dirty.Scissor|Dirty.EnvParams
+		_dirty|=Dirty.EnvParams|Dirty.Scissor
 	End
+
+	#rem monkeydoc The current scissor rect.
+	
+	The scissor rect is rect within the viewport that can be used for additional clipping.
+	
+	Scissor rect coorindates are relative to the viewport.
 	
+	#end
 	Property Scissor:Recti()
 	
 		Return _scissor
@@ -122,34 +162,15 @@ Class Canvas
 		_dirty|=Dirty.EnvParams
 	End
 	
-	#rem monkeydoc @hidden
-	#end	
-	Property RenderMatrix:AffineMat3f()
-	
-		Return _renderMatrix
-		
-	Setter( renderMatrix:AffineMat3f )
-	
-		Flush()
-		
-		_renderMatrix=renderMatrix
-		
-		_dirty|=Dirty.Scissor|Dirty.EnvParams
-	End
+	Property FilteringEnabled:Bool()
 	
-	#rem monkeydoc @hidden
-	#end	
-	Property RenderBounds:Recti()
+		Return _filter
 	
-		Return _renderBounds
-		
-	Setter( renderBounds:Recti )
+	Setter( filteringEnabled:Bool )
 	
 		Flush()
 		
-		_renderBounds=renderBounds
-				
-		_dirty|=Dirty.Scissor
+		_filter=filteringEnabled
 	End
 	
 	#rem monkeydoc @hidden
@@ -159,30 +180,45 @@ Class Canvas
 		Flush()
 		
 		_targetSize=size
-		
 		_targetRect=New Recti( 0,0,size )
 		
 		_dirty|=Dirty.Target
 	End
 	
+	#rem monkeydoc Clears the viewport.
+	
+	Clears the viewport to `color`.
+	
+	#end
 	Method Clear( color:Color )
 
 		Flush()
 		
+		Validate()
+		
 		_device.Clear( color )
 	End
 	
 	#rem monkeydoc @hidden
 	#end	
-	Method BeginRender()
+	Method BeginRender( bounds:Recti,matrix:AffineMat3f )
 	
-		DebugAssert( Not _rendering )
+		Flush()
 		
-		_rendering=True
-	
 		_device.ShaderEnv=_ambientEnv
 		
-		_dirty=Dirty.All
+		_renderMatrixStack.Push( _renderMatrix )
+		_renderBoundsStack.Push( _renderBounds )
+		
+		_renderMatrix*=matrix
+		_renderBounds&=TransformRecti( bounds,_renderMatrix )
+
+		_dirty|=Dirty.EnvParams|Dirty.Scissor
+		
+		Viewport=bounds
+		Scissor=New Recti( 0,0,bounds.Size )
+		FilteringEnabled=True
+		ClearMatrix()
 	End
 	
 	#rem monkeydoc @hidden
@@ -191,13 +227,20 @@ Class Canvas
 	
 		Flush()
 		
-		_rendering=False
+		_renderBounds=_renderBoundsStack.Pop()
+		_renderMatrix=_renderMatrixStack.Pop()
 	End
 	
+		
+	#rem monkeydoc Flushes drawing commands.
+	
+	Flushes any outstanding drawint commands in the draw buffer.
+	
+	#end
 	Method Flush()
 	
-		If Not _rendering Return
-		
+'		_dirty|=Dirty.Target
+	
 		Validate()
 		
 		RenderDrawOps()
@@ -206,7 +249,12 @@ Class Canvas
 	End
 	
 	'***** DrawList *****
+
+	#rem monkeydoc The current font for use with DrawText
+	
+	You can set the font to null to use the default mojo font.
 	
+	#end	
 	Property Font:Font()
 	
 		Return _font
@@ -217,7 +265,13 @@ Class Canvas
 	
 		_font=font
 	End
+
+	#rem monkeydoc The current drawing alpha level.
 	
+	Note that both [[Alpha]] and the alpha component of [[Color]] contribute to the alpha level used for drawing. This allows you to
+	use [[Alpha]] as a 'master' alpha level.
+
+	#end	
 	Property Alpha:Float()
 	
 		Return _alpha
@@ -230,6 +284,12 @@ Class Canvas
 		_pmcolor=UInt(a) Shl 24 | UInt(_color.b*a) Shl 16 | UInt(_color.g*a) Shl 8 | UInt(_color.r*a)
 	End
 	
+	#rem monkeydoc The current drawing color.
+	
+	Note that both [[Alpha]] and the alpha component of [[Color]] contribute to the alpha level used for drawing. This allows you to
+	use [[Alpha]] as a 'master' alpha level.
+
+	#end
 	Property Color:Color()
 	
 		Return _color
@@ -242,6 +302,11 @@ Class Canvas
 		_pmcolor=UInt(a) Shl 24 | UInt(_color.b*a) Shl 16 | UInt(_color.g*a) Shl 8 | UInt(_color.r*a)
 	End
 	
+	#rem monkeydoc The current drawing 2d matrix.
+	
+	All coordinates in draw methods are multiplied by this matrix for rendering.
+	
+	#end
 	Property Matrix:AffineMat3f()
 	
 		Return _matrix
@@ -250,7 +315,10 @@ Class Canvas
 	
 		_matrix=matrix
 	End
+
+	#rem monkeydoc The current blendmode.
 	
+	#end	
 	Property BlendMode:BlendMode()
 	
 		Return _blendMode
@@ -259,61 +327,34 @@ Class Canvas
 	
 		_blendMode=blendMode
 	End
+
+	#rem monkeydoc @hidden The materials used to render primitives.
+	#end	
+	Property PrimitiveMaterials:Material[]()
 	
-	#rem monkeydoc @hidden
-	#end
-	Property PointMaterial:Material()
-	
-		Return _pointMaterial
-	
-	Setter( pointMaterial:Material )
-	
-		_pointMaterial=pointMaterial
-	End
-	
-	#rem monkeydoc @hidden
-	#end
-	Property LineMaterial:Material()
-	
-		Return _lineMaterial
-		
-	Setter( lineMaterial:Material )
-	
-		_lineMaterial=lineMaterial
+		Return _materials
 	End
 	
-	#rem monkeydoc @hidden
-	#end
-	Property TriangleMaterial:Material()
+	#rem monkeydoc Pushes the drawing matrix onto the internal matrix stack.
 	
-		Return _triangleMaterial
-	
-	Setter( triangleMaterial:Material )
-	
-		_triangleMaterial=triangleMaterial
-	End
-	
-	#rem monkeydoc @hidden
 	#end
-	Property QuadMaterial:Material()
-
-		Return _quadMaterial
-
-	Setter( quadMaterial:Material )
-
-		_quadMaterial=quadMaterial
-	End
-	
 	Method PushMatrix()
 	
 		_matrixStack.Push( Matrix )
 	End
 	
+	#rem monkeydoc Pops the drawing matrix off the internal matrix stack.
+	
+	#end
 	Method PopMatrix()
 	
 		Matrix=_matrixStack.Pop()
 	End
 	
+	
+	#rem monkeydoc Clears the internal matrix stack and sets matrix to the identitity matrix.
+	
+	#end
 	Method ClearMatrix()
 	
 		_matrixStack.Clear()
@@ -321,73 +362,134 @@ Class Canvas
 		Matrix=New AffineMat3f
 	End
 	
+	#rem monkeydoc Translates the drawing matrix.
+	
+	Translates the drawing matrix. This has the effect of offsetting all drawing coordinates by `tx` and `ty`.
+	
+	#end
 	Method Translate( tx:Float,ty:Float )
 	
 		Matrix=Matrix.Translate( tx,ty )
 	End
 	
+	#rem monkeydoc Rotates the drawing matrix.
+	
+	Rotates the drawing matrix. This has the effect of rotating all drawing coordinates by the angle `rz'.
+	
+	@param rz Rotation angle in radians.
+	
+	#end
 	Method Rotate( rz:Float )
 	
 		Matrix=Matrix.Rotate( rz )
 	End
 	
+	#rem monkeydoc Scales the drawing matrix.
+	
+	Scales the draw matrix. This has the effect of scaling all drawing coordinates by `sx` and `sy`.
+	
+	@param sx X scale factor.
+	
+	@param sy Y scale factor.
+	
+	#end
 	Method Scale( sx:Float,sy:Float )
 	
 		Matrix=Matrix.Scale( sx,sy )
 	End
 	
-	Method DrawPoint( v0:Vec2f )
-		AddDrawOp( _pointMaterial,1,1 )
-		AddVertex( v0.x+.5,v0.y+.5,0,0 )
+	#rem monkeydoc Draws a point.
+	
+	Draws a point in the current [[Color]] using the current [[BlendMode]].
+	
+	The point coordinates are also transform by the current [[Matrix]].
+	
+	The 
+	
+	@param v Point coordinates.
+	
+	@param x Point x coordinate.
+	
+	@param y Point y coordinate.
+	
+	#end
+	Method DrawPoint( v:Vec2f )
+		AddDrawOp( _materials[1],1,1 )
+		AddVertex( v.x+.5,v.y+.5,0,0 )
 	End
 	
-	Method DrawPoint( x0:Float,y0:Float )
-		AddDrawOp( _pointMaterial,1,1 )
-		AddVertex( x0+.5,y0+.5,0,0 )
+	Method DrawPoint( x:Float,y:Float )
+		AddDrawOp( _materials[1],1,1 )
+		AddVertex( x+.5,y+.5,0,0 )
 	End
+
+	#rem monkeydoc Draws a line.
+
+	Draws a line in the current [[Color]] using the current [[BlendMode]].
+	
+	The line coordinates are transform by the current [[Matrix]] and clipped to the current [[Viewport]] and [[Scissor]].
+	
+	@param v0 First endpoint of the line.
 	
+	@param v1 Second endpoint of the line.
+	
+	@param x0 X coordinate of first endpoint of the line.
+	
+	@param y0 Y coordinate of first endpoint of the line.
+	
+	@param x1 X coordinate of first endpoint of the line.
+	
+	@param y1 Y coordinate of first endpoint of the line.
+	
+	#end
 	Method DrawLine( v0:Vec2f,v1:Vec2f )
-		AddDrawOp( _lineMaterial,2,1 )
+		AddDrawOp( _materials[2],2,1 )
 		AddVertex( v0.x+.5,v0.y+.5,0,0 )
 		AddVertex( v1.x+.5,v1.y+.5,1,1 )
 	End
 	
 	Method DrawLine( x0:Float,y0:Float,x1:Float,y1:Float )
-		AddDrawOp( _lineMaterial,2,1 )
+		AddDrawOp( _materials[2],2,1 )
 		AddVertex( x0+.5,y0+.5,0,0 )
 		AddVertex( x1+.5,y1+.5,1,1 )
 	End
 	
+	#rem monkeydoc Draws a triangle.
+	#end
 	Method DrawTriangle( v0:Vec2f,v1:Vec2f,v2:Vec2f )
-		AddDrawOp( _triangleMaterial,3,1 )
+		AddDrawOp( _materials[3],3,1 )
 		AddVertex( v0.x,v0.y,.5,0 )
 		AddVertex( v1.x,v1.y,1,1 )
 		AddVertex( v2.x,v2.y,0,1 )
 	End
 	
 	Method DrawTriangle( x0:Float,y0:Float,x1:Float,y1:Float,x2:Float,y2:Float )
-		AddDrawOp( _triangleMaterial,3,1 )
+		AddDrawOp( _materials[3],3,1 )
 		AddVertex( x0,y0,0,0 )
 		AddVertex( x1,y1,1,0 )
 		AddVertex( x2,y2,1,1 )
 	End
 	
+	#rem monkeydoc Draws a quad.
+	#end
 	Method DrawQuad( x0:Float,y0:Float,x1:Float,y1:Float,x2:Float,y2:Float,x3:Float,y3:Float )
-		AddDrawOp( _quadMaterial,4,1 )
+		AddDrawOp( _materials[4],4,1 )
 		AddVertex( x0,y0,0,0 )
 		AddVertex( x1,y1,1,0 )
 		AddVertex( x2,y2,1,1 )
 		AddVertex( x3,y3,0,1 )
 	End
 	
+	#rem monkeydoc Draws a rectangle.
+	#end
 	Method DrawRect( rect:Rectf )
-		AddDrawOp( _quadMaterial,4,1 )
+		AddDrawOp( _materials[4],4,1 )
 		AddVertex( rect.min.x,rect.min.y,0,0 )
 		AddVertex( rect.max.x,rect.min.y,1,0 )
 		AddVertex( rect.max.x,rect.max.y,1,1 )
 		AddVertex( rect.min.x,rect.max.y,0,1 )
 	End
-	
+
 	Method DrawRect( x:Float,y:Float,width:Float,height:Float )
 		DrawRect( New Rectf( x,y,x+width,y+height ) )
 	End
@@ -418,9 +520,92 @@ Class Canvas
 	End
 	
 	Method DrawRect( x:Float,y:Float,width:Float,height:Float,srcImage:Image,srcX:Int,srcY:Int,srcWidth:Int,srcHeight:Int )
+
 		DrawRect( New Rectf( x,y,x+width,y+height ),srcImage,New Recti( srcX,srcY,srcX+srcWidth,srcY+srcHeight ) )
 	End
 	
+	Method DrawOval( x:Float,y:Float,width:Float,height:Float )
+		Local xr:=width/2.0,yr:=height/2.0
+		
+		Local dx_x:=xr*_matrix.i.x
+		Local dx_y:=xr*_matrix.i.y
+		Local dy_x:=yr*_matrix.j.x
+		Local dy_y:=yr*_matrix.j.y
+		Local dx:=Sqrt( dx_x*dx_x+dx_y*dx_y )
+		Local dy:=Sqrt( dy_x*dy_x+dy_y*dy_y )
+
+		Local n:=Max( Int( dx+dy ),12 ) & ~3
+		
+		Local x0:=x+xr,y0:=y+yr
+		
+		AddDrawOp( _materials[5],n,1 )
+		
+		For Local i:=0 Until n
+			Local th:=i*Pi*2/n
+			Local px:=x0+Cos( th ) * xr
+			Local py:=y0+Sin( th ) * yr
+			AddVertex( px,py,0,0 )
+		Next
+	End
+	
+	Method DrawPoly( vertices:Float[] )
+		DebugAssert( vertices.Length>=6 And vertices.Length&1=0 )
+		
+		Local n:=vertices.Length/2
+		
+		AddDrawOp( _materials[5],n,1 )
+		
+		For Local i:=0 Until n*2 Step 2
+			AddVertex( vertices[i],vertices[i+1],0,0 )
+		Next
+	End
+	
+	#rem monkeydoc @hidden
+	#end
+	Method DrawPrimitives( order:Int,count:Int,vertices:Float Ptr,verticesPitch:Int,texCoords:Float Ptr,texCoordsPitch:Int,indices:Int Ptr )
+		DebugAssert( order>0,"Illegal primtive type" )
+			
+		If Not texCoords
+			Global _texCoords:=New Stack<Float>
+			If _texCoords.Length<>order*2
+				_texCoords.Resize( order*2 )
+				For Local i:=0 Until order*2 Step 2
+					_texCoords[i]=0
+					_texCoords[i=1]=0
+				Next
+			Endif
+			texCoords=_texCoords.Data.Data
+			texCoordsPitch=8
+		Endif
+		
+		AddDrawOp( _materials[ Min( order,5 ) ],order,count )
+		
+		If indices
+		
+			For Local i:=0 Until count
+				For Local j:=0 Until order
+					Local k:=indices[j]
+					Local vp:=Cast<Float Ptr>( Cast<UByte Ptr>( vertices )+k*verticesPitch )
+					Local tp:=Cast<Float Ptr>( Cast<UByte Ptr>( texCoords )+k*texCoordsPitch )
+					AddVertex( vp[0],vp[1],tp[0],tp[1] )
+				Next
+				indices=indices+order
+			Next
+		
+		Else
+		
+			For Local i:=0 Until count
+				For Local j:=0 Until order
+					AddVertex( vertices[0],vertices[1],texCoords[0],texCoords[1] )
+					vertices=Cast<Float Ptr>( Cast<UByte Ptr>( vertices )+verticesPitch )
+					texCoords=Cast<Float Ptr>( Cast<UByte Ptr>( texCoords )+texCoordsPitch )
+				Next
+			Next
+		End
+	End
+
+	#rem monkeydoc Draws an image.
+	#end	
 	Method DrawImage( image:Image,tx:Float,ty:Float )
 		Local vs:=image.Vertices
 		Local tc:=image.TexCoords
@@ -447,7 +632,6 @@ Class Canvas
 		DrawImage( image,trans.x,trans.y,rz )
 	End
 
-	
 	Method DrawImage( image:Image,tx:Float,ty:Float,rz:Float,sx:Float,sy:Float )
 		Local matrix:=_matrix
 		Translate( tx,ty )
@@ -461,11 +645,13 @@ Class Canvas
 		DrawImage( image,trans.x,trans.y,rz,scale.x,scale.y )
 	End
 	
+	#rem monkeydoc Draw text.
+	#end
 	Method DrawText( text:String,tx:Float,ty:Float,handleX:Float=0,handleY:Float=0 )
 	
 		tx-=_font.TextWidth( text ) * handleX
 		ty-=_font.Height * handleY
-	
+		
 		Local image:=_font.Image
 		Local sx:=image.Rect.min.x,sy:=image.Rect.min.y
 		Local tw:=image.Texture.Width,th:=image.Texture.Height
@@ -484,8 +670,9 @@ Class Canvas
 			Local x0:=tx+g.offset.x,x1:=x0+g.rect.Width
 			Local y0:=ty+g.offset.y,y1:=y0+g.rect.Height
 			
-			'Integerize font coods!
-			x0=Round( x0 );y0=Round( y0 );x1=Round( x1 );y1=Round( y1 )
+			'Integerize font coods - could do this in shader?
+			x0=Round( x0 );y0=Round( y0 )
+			x1=Round( x1 );y1=Round( y1 )
 			
 			AddVertex( x0,y0,s0,t0 )
 			AddVertex( x1,y0,s1,t0 )
@@ -496,8 +683,26 @@ Class Canvas
 		Next
 	End
 	
+	#rem
+	Method AddLight( tx:Float,ty:Float,radius:Radius )
+		Local x:=_matrix.i.x * tx + _matrix.j.x * ty + _matrix.t.x
+		Local y:=_matrix.i.y * tx + _matrix.j.y * ty + _matrix.t.y
+		Local inst:=New LightInst
+		inst.position=New Vec2f( x,y )
+		inst.radius=radius
+		inst.color=_color
+		'_lights.Push( inst )
+	End
+	#end
+	
 	Private
 	
+	Struct LightInst
+		Field position:Vec2f
+		Field radius:Float
+		Field color:Color
+	End
+	
 	Enum Dirty
 		Target=1
 		Scissor=2
@@ -510,7 +715,6 @@ Class Canvas
 	Global _defaultFont:Font
 
 	Field _dirty:Dirty
-	Field _rendering:Bool
 	Field _target:Texture
 	Field _targetSize:Vec2i
 	Field _targetRect:Recti
@@ -522,10 +726,14 @@ Class Canvas
 	Field _viewMatrix:Mat4f
 	Field _modelMatrix:Mat4f
 	Field _ambientLight:Color
+	Field _filter:Bool=True
+
 	Field _renderColor:Color
-	
 	Field _renderMatrix:AffineMat3f
+	Field _renderMatrixStack:=New Stack<AffineMat3f>
+
 	Field _renderBounds:Recti
+	Field _renderBoundsStack:=New Stack<Recti>
 	
 	Field _font:Font
 	Field _alpha:Float
@@ -542,15 +750,14 @@ Class Canvas
 	Field _vertexData:Vertex2f[]
 	Field _vertex:Int
 	
-	Field _pointMaterial:Material
-	Field _lineMaterial:Material
-	Field _triangleMaterial:Material
-	Field _quadMaterial:Material
+	Field _materials:=New Material[6]
 	
 	Method Init( target:Texture,size:Vec2i,viewport:Recti )
 	
 		If Not _device
-			_ambientEnv=New ShaderEnv( stringio.LoadString( "asset::mojo/shaderenv_ambient.glsl" ) )
+			Local env:=stringio.LoadString( "asset::mojo/shader_env.glsl" )
+			_ambientEnv=New ShaderEnv( "#define RENDERPASS_AMBIENT~n"+env )
+'			_ambientEnv=New ShaderEnv( "#define RENDERPASS_NORMAL~n"+env )
 			_defaultFont=Font.Load( "asset::mojo/RobotoMono-Regular.ttf",16 )
 			_nullShader=Shader.GetShader( "null" )
 		Endif
@@ -561,28 +768,28 @@ Class Canvas
 		
 		_envParams=New ParamBuffer
 		_device=New GraphicsDevice
-		_rendering=False
 		
 		_viewport=New Recti( 0,0,_targetRect.Width,_targetRect.Height )
-		_scissor=New Recti( 0,0,16384,16384 )
+		_scissor=_viewport
 		_viewMatrix=New Mat4f
 		_modelMatrix=New Mat4f
 		_ambientLight=Color.Black
+		_filter=True
+		
 		_renderColor=Color.White
 		_renderMatrix=New AffineMat3f
-		_renderBounds=New Recti( 0,0,_targetRect.Width,_targetRect.Height )
+		_renderBounds=New Recti( 0,0,$40000000,$40000000 )
+		
+		_dirty=Dirty.All
 		
 		Font=Null
 		Alpha=1
 		Color=Color.White
 		Matrix=New AffineMat3f
 		BlendMode=BlendMode.Alpha
-		PointMaterial=New Material( _nullShader )
-		LineMaterial=New Material( _nullShader )
-		TriangleMaterial=New Material( _nullShader )
-		QuadMaterial=New Material( _nullShader )
-		
-		BeginRender()
+		For Local i:=0 Until _materials.Length
+			_materials[i]=New Material( _nullShader )
+		Next
 	End
 	
 	Method Validate()
@@ -610,23 +817,6 @@ Class Canvas
 			
 		Endif
 		
-		If _dirty & Dirty.Scissor
-		
-'			Local viewport:=TransformRecti( _viewport & _scissor,_renderMatrix )
-			Local viewport:=TransformRecti( _viewport & (_scissor+_viewport.Origin),_renderMatrix )
-			
-			Local scissor:=(viewport & _renderBounds)+_targetRect.Origin
-			
-			If Not _target
-				Local h:=scissor.Height
-				scissor.min.y=_targetSize.y-scissor.max.y
-				scissor.max.y=scissor.min.y+h
-			Endif
-			
-			_device.Scissor=scissor
-		
-		Endif
-		
 		If _dirty & Dirty.EnvParams
 		
 			Local renderMatrix:=_renderMatrix.Translate( New Vec2f( _viewport.X,_viewport.Y ) )
@@ -638,6 +828,22 @@ Class Canvas
 			_envParams.SetColor( "mx2_RenderColor",_renderColor )
 
 			_device.EnvParams=_envParams
+
+		Endif
+		
+		If _dirty & Dirty.Scissor
+		
+			Local scissor:=TransformRecti( _viewport & (_scissor+_viewport.Origin),_renderMatrix )
+			
+			scissor=(scissor & _renderBounds)+_targetRect.Origin
+			
+			If Not _target
+				Local h:=scissor.Height
+				scissor.min.y=_targetSize.y-scissor.max.y
+				scissor.max.y=scissor.min.y+h
+			Endif
+
+			_device.Scissor=scissor
 		Endif
 		
 		_dirty=Null
@@ -646,6 +852,8 @@ Class Canvas
 	Method RenderDrawOps()
 	
 		Local p:=_vertexData.Data
+		
+		_device.FilteringEnabled=_filter
 	
 		For Local op:=Eachin _ops
 			_device.BlendMode=op.blendMode

+ 20 - 2
modules/mojo/graphics/device.monkey2

@@ -119,6 +119,19 @@ Class GraphicsDevice
 		_dirty|=Dirty.Params
 	End
 	
+	Property FilteringEnabled:Bool()
+	
+		Return _filter
+	
+	Setter( filteringEnabled:Bool )
+	
+		If filteringEnabled=_filter Return
+		
+		_filter=filteringEnabled
+
+		_dirty|=Dirty.Params
+	End
+	
 	Method Clear( color:Color )
 	
 		Validate()
@@ -130,7 +143,7 @@ Class GraphicsDevice
 			glDisable( GL_SCISSOR_TEST )
 		Endif
 		
-		glClearColor( color.r,color.g,color.b,color.a )
+		glClearColor( color.r,color.g,color.b,color.a )
 
 		glClear( GL_COLOR_BUFFER_BIT )
 		
@@ -180,6 +193,10 @@ Class GraphicsDevice
 				Next
 			Endif
 			glDrawElements( GL_TRIANGLES,n,GL_UNSIGNED_SHORT,_qindices.Data )
+		Default
+			For Local i:=0 Until count
+				glDrawArrays( GL_TRIANGLE_FAN,i*order,order )
+			Next
 		End
 		
 	End
@@ -207,6 +224,7 @@ Class GraphicsDevice
 	Field _envParams:ParamBuffer
 	Field _shader:Shader
 	Field _params:ParamBuffer
+	Field _filter:Bool=True
 	
 	Field _rscissor:Recti
 
@@ -287,7 +305,7 @@ Class GraphicsDevice
 			Endif
 			
 			If _dirty & Dirty.Params
-				_shader.BindParams( _params )
+				_shader.BindParams( _params,_filter )
 			End
 			
 		Endif

+ 2 - 2
modules/mojo/graphics/font.monkey2

@@ -84,9 +84,9 @@ Class Font
 	End
 
 	'Make this ALWAYS work!	
-	Function Load:Font( path:String,height:Float )
+	Function Load:Font( path:String,height:Float,textureFlags:TextureFlags=TextureFlags.DefaultFlags )
 	
-		Local font:=fontloader.LoadFont( path,height )
+		Local font:=fontloader.LoadFont( path,height,textureFlags )
 		
 		Return font
 	End

+ 3 - 3
modules/mojo/graphics/fontloader_freetype.monkey2

@@ -13,7 +13,7 @@ Public
 
 #rem monkeydoc @hidden
 #end
-Function LoadFont:Font( path:String,fheight:Float )
+Function LoadFont:Font( path:String,fheight:Float,textureFlags:TextureFlags )
 
 	If Not FreeType And FT_Init_FreeType( Varptr FreeType ) Return Null
 	
@@ -80,7 +80,7 @@ Function LoadFont:Font( path:String,fheight:Float )
 			x=0
 		Endif
 		
-		Local tmp:=New Pixmap( gw,gh,PixelFormat.A8,slot->bitmap.buffer,slot->bitmap.pitch,Null )
+		Local tmp:=New Pixmap( gw,gh,PixelFormat.A8,slot->bitmap.buffer,slot->bitmap.pitch )
 		
 		pixmap.Paste( tmp,x,y )
 		
@@ -94,7 +94,7 @@ Function LoadFont:Font( path:String,fheight:Float )
 	
 	data.Discard()
 	
-	Local image:=New Image( pixmap,Shader.GetShader( "font" ) )
+	Local image:=New Image( pixmap,textureFlags,Shader.GetShader( "font" ) )
 	
 	Local font:=New Font( image,height,firstChar,glyphs )
 	

+ 4 - 5
modules/mojo/graphics/glutil.monkey2

@@ -74,11 +74,10 @@ Function glCompile:Int( type:Int,source:String )
 	glGetShaderiv( shader,GL_COMPILE_STATUS,Varptr tmpi )
 	If Not tmpi
 		Print "Failed to compile fragment shader:"+glGetShaderInfoLogEx( shader )
-		Print source
-'		Local lines:=source.Split( "~n" )
-'		For Local i:=0 Until lines.Length
-'			Print (i+1)+":~t"+lines[i]
-'		Next
+		Local lines:=source.Split( "~n" )
+		For Local i:=0 Until lines.Length
+			Print (i+1)+":~t"+lines[i]
+		Next
 		Assert( False,"Compile fragment shader failed" )
 	Endif
 	Return shader

+ 55 - 16
modules/mojo/graphics/image.monkey2

@@ -5,18 +5,30 @@ Namespace mojo.graphics
 #end
 Class Image
 
-	Method New( pixmap:Pixmap,shader:Shader=Null )
+	#rem monkeydoc @hidden
+	#end
+	Field OnDiscarded:Void()
+
+	Method New( pixmap:Pixmap,textureFlags:TextureFlags=TextureFlags.DefaultFlags,shader:Shader=Null )
 	
-		Local texture:=New Texture( pixmap )
+		Local texture:=New Texture( pixmap,textureFlags )
 		
 		Init( Null,texture,texture.Rect,shader )
+		
+		OnDiscarded+=Lambda()
+			texture.Discard()
+		End
 	End
 	
-	Method New( width:Int,height:Int,shader:Shader=Null )
+	Method New( width:Int,height:Int,textureFormat:PixelFormat=PixelFormat.RGBA32,textureFlags:TextureFlags=TextureFlags.DefaultFlags,shader:Shader=Null )
 	
-		Local texture:=New Texture( width,height )
+		Local texture:=New Texture( width,height,textureFormat,textureFlags )
 		
 		Init( Null,texture,texture.Rect,shader )
+
+		OnDiscarded+=Lambda()
+			texture.Discard()
+		End
 	End
 	
 	Method New( image:Image,rect:Recti )
@@ -113,26 +125,53 @@ Class Image
 		Return _texCoords
 	End
 	
-	Function Load:Image( path:String,shader:Shader=Null )
+	#rem monkeydoc Release the image and any resource it uses.
+	#end
+	Method Discard()
+		If _discarded Return
+		_discarded=True
+		OnDiscarded()
+	End
+	
+	Function Load:Image( path:String,textureFlags:TextureFlags=TextureFlags.DefaultFlags,shader:Shader=Null )
 	
-		Local texture:=mojo.graphics.Texture.Load( path )
-		If Not texture Return Null
+		Local diffuse:=mojo.graphics.Texture.Load( path,textureFlags )
+		If Not diffuse Return Null
 		
 		Local file:=StripExt( path )
 		Local ext:=ExtractExt( path )
 		
-		Local specular:=mojo.graphics.Texture.Load( file+"_SPECULAR"+ext )
-		Local normal:=mojo.graphics.Texture.Load( file+"_NORMALS"+ext )
+		Local specular:=mojo.graphics.Texture.Load( file+"_SPECULAR"+ext,textureFlags )
+		Local normal:=mojo.graphics.Texture.Load( file+"_NORMALS"+ext,textureFlags )
+		
+		If specular Or normal
+			If Not specular specular=mojo.graphics.Texture.ColorTexture( Color.Black )
+			If Not normal normal=mojo.graphics.Texture.ColorTexture( New Color( .5,.5,.5 ) )
+		Endif
 		
-		If Not shader shader=Shader.GetShader( "sprite" )
+		If Not shader
+			If specular Or normal
+				shader=Shader.GetShader( "phong" )
+			Else
+				shader=Shader.GetShader( "sprite" )
+			Endif
+		Endif
 		
 		Local material:=New Material( shader )
 		
-		material.SetTexture( "u_Texture0",texture )
-		If specular material.SetTexture( "u_Texture1",specular )
-		If normal material.SetTexture( "u_Texture2",normal )
+		If diffuse material.SetTexture( "DiffuseTexture",diffuse )
+		If specular material.SetTexture( "SpecularTexture",specular )
+		If normal material.SetTexture( "NormalTexture",normal )
 		
-		Return New Image( material,texture,texture.Rect )
+		Local image:=New Image( material,diffuse,diffuse.Rect )
+		
+		image.OnDiscarded+=Lambda()
+			If diffuse diffuse.Discard()
+			If specular specular.Discard()
+			If normal normal.Discard()
+		End
+		
+		Return image
 	End
 	
 	Private
@@ -140,7 +179,7 @@ Class Image
 	Field _material:Material
 	Field _texture:Texture
 	Field _rect:Recti
-	
+	Field _discarded:Bool
 	Field _handle:=New Vec2f( 0,0 )
 	Field _scale:=New Vec2f( 1,1 )
 	Field _vertices:Rectf
@@ -152,7 +191,7 @@ Class Image
 		If Not material
 			If Not shader shader=Shader.GetShader( "sprite" )
 			material=New Material( shader )
-			material.SetTexture( "u_Texture0",texture )
+			material.SetTexture( "DiffuseTexture",texture )
 		Endif
 		
 		_material=material

+ 11 - 4
modules/mojo/graphics/shader.monkey2

@@ -2,12 +2,13 @@
 Namespace mojo.graphics
 
 #Import "assets/shader_sprite.glsl@/mojo"
+#Import "assets/shader_phong.glsl@/mojo"
 #Import "assets/shader_font.glsl@/mojo"
 #Import "assets/shader_null.glsl@/mojo"
 
 Private
 
-Function BindUniforms( uniforms:Uniform[],params:ParamBuffer )
+Function BindUniforms( uniforms:Uniform[],params:ParamBuffer,filter:Bool )
 
 	For Local u:=Eachin uniforms
 	
@@ -25,6 +26,11 @@ Function BindUniforms( uniforms:Uniform[],params:ParamBuffer )
 			DebugAssert( tex,"Can't bind shader texture uniform '"+u.name+"' - no texture!" )
 			glActiveTexture( GL_TEXTURE0+u.texunit )
 			glBindTexture( GL_TEXTURE_2D,tex.GLTexture )
+			If (tex.Flags & TextureFlags.Filter) And filter
+				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR )
+			Else
+				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST )
+			Endif
 			glUniform1i( u.location,u.texunit )
 		Default
 			Assert( False,"Unsupported uniform type for param:"+u.name )
@@ -296,14 +302,14 @@ Class Shader
 	#end
 	Method BindEnvParams( params:ParamBuffer )
 	
-		BindUniforms( _bound._envUniforms,params )
+		BindUniforms( _bound._envUniforms,params,True )
 	End
 	
 	#rem monkeydoc @hidden
 	#end
-	Method BindParams( params:ParamBuffer )
+	Method BindParams( params:ParamBuffer,filter:Bool )
 	
-		BindUniforms( _bound._uniforms,params )
+		BindUniforms( _bound._uniforms,params,filter )
 	End
 	
 	#rem monkeydoc @hidden
@@ -313,6 +319,7 @@ Class Shader
 		If Not _shaders
 			_shaders=New StringMap<Shader>
 			_shaders["sprite"]=New Shader( stringio.LoadString( "asset::mojo/shader_sprite.glsl" ) )
+			_shaders["phong"]=New Shader( stringio.LoadString( "asset::mojo/shader_phong.glsl" ) )
 			_shaders["font"]=New Shader( stringio.LoadString( "asset::mojo/shader_font.glsl" ) )
 			_shaders["null"]=New Shader( stringio.LoadString( "asset::mojo/shader_null.glsl" ) )
 		Endif

+ 51 - 18
modules/mojo/graphics/texture.monkey2

@@ -7,9 +7,9 @@ Namespace mojo.graphics
 |:--------------|:-----------
 | Filter		| Filter texture.
 | Mipmap		| Mipmap texture.
-| ClampS		| Clamp texture S coordinate.
-| ClampT		| Clamp texture T coordinate.
-| Clamp			| Clamp texture coordinates.
+| WrapS			| Wrap texture S coordinate.
+| WrapT			| Wrap texture T coordinate.
+| WrapST		| Wrap texture coordinates.
 | Managed		| Managed by mojo.
 | RenderTarget	| Texture can be used as a render target.
 | DefaultFlags	| Use default flags.
@@ -19,24 +19,31 @@ Enum TextureFlags
 
 	Filter=			$0001
 	Mipmap=			$0002
-	ClampS=			$0004
-	ClampT=			$0008
+	WrapS=			$0004
+	WrapT=			$0008
 	Managed=		$0010
 	RenderTarget=	$0020
-	ClampST=		ClampS|ClampT
+	
+	WrapST=			WrapS|WrapT
 
 	DefaultFlags=	$ffff
 End
 
 Class Texture
 
+	#rem monkeydoc @hidden
+	#end
+	Field OnDiscarded:Void()
+
 	Method New( pixmap:Pixmap,flags:TextureFlags=TextureFlags.DefaultFlags )
 
 		If flags=TextureFlags.DefaultFlags 
-			flags=TextureFlags.Filter|TextureFlags.Mipmap|TextureFlags.ClampST|TextureFlags.Managed
+			flags=TextureFlags.Filter|TextureFlags.Mipmap
 		Endif
 		
-#If __TARGET__="emscripten"
+		flags|=TextureFlags.Managed
+		
+#If __TARGET__<>"desktop"
 		If flags & TextureFlags.Mipmap
 			Local tw:=Log2( pixmap.Width ),th:=Log2( pixmap.Height )
 			If tw<>Round( tw ) Or th<>Round( th ) flags&=~TextureFlags.Mipmap
@@ -46,16 +53,13 @@ Class Texture
 		_rect=New Recti( 0,0,pixmap.Width,pixmap.Height )
 		_format=pixmap.Format
 		_flags=flags
-		
-		If _flags & TextureFlags.Managed
-			_managed=pixmap
-		Endif
+		_managed=pixmap
 	End
 	
 	Method New( width:Int,height:Int,format:PixelFormat=PixelFormat.RGBA32,flags:TextureFlags=TextureFlags.DefaultFlags )
 	
 		If flags=TextureFlags.DefaultFlags 
-			flags=TextureFlags.Filter|TextureFlags.ClampST|TextureFlags.RenderTarget
+			flags=TextureFlags.Filter|TextureFlags.RenderTarget
 		Endif
 
 		_rect=New Recti( 0,0,width,height )
@@ -63,8 +67,11 @@ Class Texture
 		_flags=flags
 		
 		If _flags & TextureFlags.Managed
-			_managed=New Pixmap( Width,Height,_format )
+			_managed=New Pixmap( width,height,format )
 			_managed.Clear( Color.Magenta )
+			OnDiscarded+=Lambda()
+				_managed.Discard()
+			End
 		Endif
 	End
 	
@@ -88,6 +95,14 @@ Class Texture
 		Return _flags
 	End
 	
+	Method Discard()
+		If _discarded Return
+		If _texSeq=glGraphicsSeq glDeleteTextures( 1,Varptr _glTexture )
+		If _fbSeq=glGraphicsSeq glDeleteFramebuffers( 1,Varptr _glFramebuffer )
+		_discarded=True
+		OnDiscarded()
+	End
+	
 	Method PastePixmap( pixmap:Pixmap,x:Int,y:Int )
 	
 		If _managed
@@ -123,7 +138,13 @@ Class Texture
 		
 		pixmap.PremultiplyAlpha()
 		
-		Return New Texture( pixmap,flags )
+		Local texture:=New Texture( pixmap,flags )
+		
+		texture.OnDiscarded+=Lambda()
+			pixmap.Discard()
+		End
+		
+		Return texture
 	End
 
 	Function ColorTexture:Texture( color:Color )
@@ -140,6 +161,7 @@ Class Texture
 	#rem monkeydoc @hidden
 	#end	
 	Property GLTexture:GLuint()
+		DebugAssert( Not _discarded,"texture has been discarded" )
 	
 		If _texSeq=glGraphicsSeq And Not _texDirty Return _glTexture
 		
@@ -169,9 +191,18 @@ Class Texture
 			Else
 				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST )
 			Endif
-	
-			If _flags & TextureFlags.ClampS glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE )
-			If _flags & TextureFlags.ClampT glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE )
+			
+			If _flags & TextureFlags.WrapS
+				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT )
+			Else
+				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE )
+			Endif
+			
+			If _flags & TextureFlags.WrapT
+				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT )
+			Else
+				glTexParameteri( GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE )
+			Endif
 		
 			glTexImage2D( GL_TEXTURE_2D,0,glFormat( _format ),Width,Height,0,glFormat( _format ),GL_UNSIGNED_BYTE,Null )
 			
@@ -205,6 +236,7 @@ Class Texture
 	#rem monkeydoc @hidden
 	#end	
 	Property GLFramebuffer:GLuint()
+		DebugAssert( Not _discarded,"texture has been discarded" )
 	
 		If _fbSeq=glGraphicsSeq Return _glFramebuffer
 		
@@ -230,6 +262,7 @@ Class Texture
 	Field _format:PixelFormat
 	Field _flags:TextureFlags
 	Field _managed:Pixmap
+	Field _discarded:Bool
 	
 	Field _texSeq:Int
 	Field _texDirty:Bool