Browse Source

WIP Mesh changes; Added abstract Renderable class.

Mark Sibly 8 years ago
parent
commit
7cf9f75d8a

+ 0 - 1
modules/mojo3d/graphics/gltf2loader.monkey2

@@ -172,7 +172,6 @@ Class Gltf2Loader
 					Print "Gltf mesh has no indices"
 					Print "Gltf mesh has no indices"
 					Continue
 					Continue
 				Endif
 				Endif
-				
 
 
 				If prim.POSITION.componentType<>5126 Or prim.POSITION.type<>"VEC3"
 				If prim.POSITION.componentType<>5126 Or prim.POSITION.type<>"VEC3"
 					Print "Gltf invalid nesh POSITION data"
 					Print "Gltf invalid nesh POSITION data"

+ 282 - 147
modules/mojo3d/graphics/mesh.monkey2

@@ -15,27 +15,48 @@ Class Mesh Extends Resource
 	
 	
 	#end
 	#end
 	Method New()
 	Method New()
-		
+	
 		_dirty=Null
 		_dirty=Null
 		_bounds=Boxf.EmptyBounds
 		_bounds=Boxf.EmptyBounds
-		_vbuffer=New VertexBuffer( Vertex3fFormat.Instance,0 )
-		_ibuffers=New Stack<IndexBuffer>
+		_vertices=New Stack<Vertex3f>
+		_materials=New Stack<MaterialID>
+'		AddMaterials( 1 )
 	End
 	End
 	
 	
-	Method New( mesh:Mesh )
-		_dirty=mesh._dirty
-		_bounds=mesh._bounds
-		_vbuffer=New VertexBuffer( mesh._vbuffer )
-		For Local ibuffer:=Eachin mesh._ibuffers
-			_ibuffers.Push( New IndexBuffer( ibuffer ) )
+	Method New( vertices:Vertex3f[],indices:UInt[] )
+		Self.New()
+		AddVertices( vertices )
+		AddTriangles( indices )
+	End
+		
+	#rem monkeydoc Number of vertices.
+	#end
+	Property NumVertices:Int()
+		
+		Return _vertices.Length
+	End
+	
+	#rem monkeydoc Total number of indices.
+	#end
+	Property NumIndices:int()
+		
+		Local n:=0
+	
+		For Local material:=Eachin _materials
+			n+=material.indices.Length
 		Next
 		Next
+		
+		Return n
 	End
 	End
+		
+	#rem monkeydoc Number of materials.
 	
 	
-	Method New( vertices:Vertex3f[],triangles:UInt[] )
-		Self.New()
+	This will always be at least one.
+	
+	#end
+	Property NumMaterials:Int()
 		
 		
-		AddVertices( vertices )
-		AddTriangles( triangles )
+		Return _materials.Length
 	End
 	End
 
 
 	#rem monkeydoc Mesh bounding box.
 	#rem monkeydoc Mesh bounding box.
@@ -44,12 +65,10 @@ Class Mesh Extends Resource
 		
 		
 		If _dirty & Dirty.Bounds
 		If _dirty & Dirty.Bounds
 			
 			
-			Local vertices:=Cast<Vertex3f Ptr>( _vbuffer.Data )
-			
 			_bounds=Boxf.EmptyBounds
 			_bounds=Boxf.EmptyBounds
 			
 			
-			For Local i:=0 Until _vbuffer.Length
-				_bounds|=vertices[i].position
+			For Local i:=0 Until _vertices.Length
+				_bounds|=_vertices[i].position
 			Next
 			Next
 			
 			
 			_dirty&=~Dirty.Bounds
 			_dirty&=~Dirty.Bounds
@@ -58,23 +77,6 @@ Class Mesh Extends Resource
 		Return _bounds
 		Return _bounds
 	End
 	End
 	
 	
-	#rem monkeydoc Number of vertices.
-	#end
-	Property NumVertices:Int()
-		
-		Return _vbuffer.Length
-	End
-	
-	#rem monkeydoc Number of materials.
-	
-	This will always be at least one.
-	
-	#end
-	Property NumMaterials:Int()
-		
-		Return _ibuffers.Length
-	End
-	
 	#rem monkeydoc Clears the mesh.
 	#rem monkeydoc Clears the mesh.
 	
 	
 	Removes all vertices and primitives from the mesh, and resets the number of logical materials to '1'.
 	Removes all vertices and primitives from the mesh, and resets the number of logical materials to '1'.
@@ -82,15 +84,26 @@ Class Mesh Extends Resource
 	#end
 	#end
 	Method Clear()
 	Method Clear()
 		
 		
-		_vbuffer.Clear()
+		_dirty=Null
+		_bounds=Boxf.EmptyBounds
+		_vertices.Clear()
+		_materials.Clear()
 		
 		
-		For Local ibuffer:=Eachin _ibuffers
-			ibuffer.Clear()
-		Next
+		InvalidateVertices()
+	End
+	
+	Method ClearVertices()
 		
 		
-		_ibuffers.Resize( 1 )
+		ResizeVertices( 0 )
 	End
 	End
+	
+	Method ResizeVertices( length:Int )
+		
+		_vertices.Resize( length )
 
 
+		InvalidateVertices()
+	End
+#rem
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end	
 	#end	
 	Method AddMesh( mesh:Mesh )
 	Method AddMesh( mesh:Mesh )
@@ -108,82 +121,199 @@ Class Mesh Extends Resource
 			AddTriangles( Cast<UInt Ptr>( ibuffer.Data ),ibuffer.Length )
 			AddTriangles( Cast<UInt Ptr>( ibuffer.Data ),ibuffer.Length )
 		Next
 		Next
 	End
 	End
-	
-	#rem monkeydoc Adds vertices to the mesh.
+#end
+
+	#rem monkeydoc Sets a range of vertices.
 	#end
 	#end
-	Method AddVertices( vertices:Vertex3f Ptr,count:Int )
+	Method SetVertices( vertices:Vertex3f Ptr,first:Int,count:Int )
+		
+		DebugAssert( first>=0 And count>=0 And first<=_vertices.Length And first+count<=_vertices.Length,"Invalid vertex range" )
+		
+		libc.memcpy( _vertices.Data.Data+first*Vertex3f.Pitch,vertices,count*Vertex3f.Pitch )
 
 
-		Local p:=_vbuffer.AddVertices( count )
+		InvalidateVertices( first,count )
+	End
+	
+	Method SetVertices( vertices:Vertex3f[] )
+		
+		_vertices.Resize( vertices.Length )
+		
+		SetVertices( vertices.Data,0,vertices.Length )
+	End
+	
+	#rem monkeydoc Sets a single vertex.
+	#end
+	Method SetVertex( index:Int,vertex:Vertex3f )
+		
+		DebugAssert( index>=0 And index<_vertices.Length,"Vertex index out of range" )
 		
 		
-		libc.memcpy( p,vertices,count * _vbuffer.Pitch )
+		_vertices[index]=vertex
 		
 		
-		_dirty|=Dirty.Bounds
+		InvalidateVertices( index,1 )
 	End
 	End
 	
 	
+	#rem monkeydoc Adds vertices.
+	#end
+	Method AddVertices( vertices:Vertex3f Ptr,count:Int )
+		
+		Local first:=_vertices.Length
+		
+		_vertices.Resize( first+count )
+		
+		libc.memcpy( _vertices.Data.Data+first*Vertex3f.Pitch,vertices,count * Vertex3f.Pitch )
+		
+		InvalidateVertices( first,count )
+	End
+
 	Method AddVertices( vertices:Vertex3f[] )
 	Method AddVertices( vertices:Vertex3f[] )
 	
 	
 		AddVertices( vertices.Data,vertices.Length )
 		AddVertices( vertices.Data,vertices.Length )
 	End
 	End
 	
 	
-	#rem monkeydoc Adds a single vertex to the mesh
+	#rem monkeydoc Adds a single vertex.
 	#end
 	#end
 	Method AddVertex( vertex:Vertex3f )
 	Method AddVertex( vertex:Vertex3f )
 		
 		
 		AddVertices( Varptr vertex,1 )
 		AddVertices( Varptr vertex,1 )
 	End
 	End
 	
 	
+	#rem monkeydoc Gets all vertices as an array.
+	#end	
+	Method GetVertices:Vertex3f[]()
+		
+		Return _vertices.ToArray()
+	End
+	
+	#rem monkeydoc Gets a single vertex.
+	#end
+	Method GetVertex:Vertex3f( index:Int )
+		
+		DebugAssert( index>=0 And index<_vertices.Length,"Vertex index out of range" )
+		
+		Return _vertices[index]
+	End		
+	
+	#rem monkeydoc Sets tthe triangles for a material in the mesh.
+	
+	`materialid` must be a valid material id in the range 0 to [[NumMaterials]] inclusive.
+	
+	#end
+	Method SetTriangles( indices:UInt Ptr,first:Int,count:Int,materialid:Int=0 )
+		
+		DebugAssert( first Mod 3=0,"First must be a multiple of 3" )
+
+		DebugAssert( count Mod 3=0,"Count must be a multiple of 3" )
+		
+		Local mindices:=GetMaterial( materialid ).indices
+
+		DebugAssert( first>=0 And count>=0 And first<=mindices.Length And first+count<=mindices.Length,"Invalid range" )
+		
+		libc.memcpy( mindices.Data.Data+first*4,indices,count*4 )
+	End
+	
+	Method SetTriangles( indices:UInt[],materialid:Int=0 )
+		
+		SetTriangles( indices.Data,indices.Length,materialid )
+	End
+	
+	Method SetTriangle( index:Int,i0:Int,i1:Int,i2:Int,materialid:Int=0 )
+		
+		DebugAssert( index Mod 3=0,"Index must be a multiple of 3" )
+		
+		Local mindices:=GetMaterial( materialid ).indices
+		
+		DebugAssert( index>=0 And index+3<=mindices.Length,"Triangle index out of range" )
+		
+		mindices[index]=i0;mindices[index+1]=i1;mindices[index+2]=i2
+	End
+	
 	#rem monkeydoc Adds triangles to the mesh.
 	#rem monkeydoc Adds triangles to the mesh.
+
+	`count` is the number of indices to add and must be a multiple of 3.
 	
 	
-	The `materialid` parameter must be greater than or equal to 0 and less or equal to [[NumMaterials]].
+	`materialid` must be a valid material id in the range 0 to [[NumMaterials]] inclusive.
 	
 	
 	If `materialid` is equal to NumMaterials, a new material is automatically added first.
 	If `materialid` is equal to NumMaterials, a new material is automatically added first.
 	
 	
 	#end
 	#end
 	Method AddTriangles( indices:UInt Ptr,count:Int,materialid:Int=0 )
 	Method AddTriangles( indices:UInt Ptr,count:Int,materialid:Int=0 )
 		
 		
-		If materialid=_ibuffers.Length AddMaterials( 1 )
+		DebugAssert( count Mod 3=0,"Count must be a multiple of 3" )
 		
 		
-		Local p:=_ibuffers[materialid].AddIndices( count )
+		Local mindices:=GetMaterial( materialid ).indices
 		
 		
-		libc.memcpy( p,indices,count*4 )
+		Local first:=mindices.Length
+		
+		mindices.Resize( mindices.Length+count )
+		
+		libc.memcpy( mindices.Data.Data+first*4,indices,count*4 )
 	End
 	End
 	
 	
 	Method AddTriangles( indices:UInt[],materialid:Int=0 )
 	Method AddTriangles( indices:UInt[],materialid:Int=0 )
-	
+		
 		AddTriangles( indices.Data,indices.Length,materialid )
 		AddTriangles( indices.Data,indices.Length,materialid )
 	End
 	End
 
 
-	#rem  monkeydoc Adds a single triangle the mesh.
+	#rem monkeydoc Adds a single triangle the mesh.
 	#end	
 	#end	
 	Method AddTriangle( i0:UInt,i1:UInt,i2:UInt,materialid:Int=0 )
 	Method AddTriangle( i0:UInt,i1:UInt,i2:UInt,materialid:Int=0 )
 		
 		
-		AddTriangles( New UInt[]( i0,i1,i2 ),materialid )
+		Local indices:=GetMaterial( materialid ).indices
+		
+		indices.Add( i0 )
+		indices.Add( i1 )
+		indices.Add( i2 )
+	End
+	
+	#rem monkeydoc Get indices for a material id.
+	#end
+	Method GetIndices:UInt[]( materialid:Int=0 )
+		
+		DebugAssert( materialid>=0 And materialid<_materials.Length,"Material id out of range" )
+		
+		Return _materials[materialid].indices.ToArray()
 	End
 	End
 	
 	
+	Method GetAllIndices:Uint[]()
+		
+		Local indices:=New Uint[NumIndices],ip:=indices.Data
+		
+		For Local material:=Eachin _materials
+			Local mindices:=material.indices
+			libc.memcpy( ip,mindices.Data.Data,mindices.Length*4 )
+			ip+=mindices.Length
+		Next
+		
+		Return indices
+	End
+
 	#rem monkeydoc Adds materials to the mesh.
 	#rem monkeydoc Adds materials to the mesh.
 	
 	
 	Adds `count` logical materials to the mesh.
 	Adds `count` logical materials to the mesh.
 	
 	
-	WIP! Eventually want to be able to add lines, points etc to meshes, probably via this method...
+	Returns the first material id of the newly added materials.
 	
 	
 	#end
 	#end
-	Method AddMaterials( count:Int )
+	Method AddMaterials:Int( count:Int )
+		
+		Local first:=_materials.Length
 		
 		
 		For Local i:=0 Until count
 		For Local i:=0 Until count
-			
-			_ibuffers.Push( New IndexBuffer( IndexFormat.UINT32,0 ) )
-		End
+			_materials.Push( New MaterialID )
+		Next
+		
+		Return first
 	End
 	End
 	
 	
 	#rem monkeydoc Transforms all vertices in the mesh.
 	#rem monkeydoc Transforms all vertices in the mesh.
 	#end
 	#end
 	Method TransformVertices( matrix:AffineMat4f )
 	Method TransformVertices( matrix:AffineMat4f )
 		
 		
-		Local vertices:=Cast<Vertex3f Ptr>( _vbuffer.Data )
+		Local vertices:=_vertices.Data
 		
 		
 		Local cofactor:=matrix.m.Cofactor()
 		Local cofactor:=matrix.m.Cofactor()
 		
 		
-		For Local i:=0 Until _vbuffer.Length
+		For Local i:=0 Until _vertices.Length
 		
 		
 			vertices[i].position=matrix * vertices[i].position
 			vertices[i].position=matrix * vertices[i].position
 			
 			
@@ -192,9 +322,7 @@ Class Mesh Extends Resource
 			vertices[i].tangent.XYZ=(cofactor * vertices[i].tangent.XYZ).Normalize()
 			vertices[i].tangent.XYZ=(cofactor * vertices[i].tangent.XYZ).Normalize()
 		Next
 		Next
 		
 		
-		_vbuffer.Invalidate()
-		
-		_dirty|=Dirty.Bounds
+		InvalidateVertices()
 	End
 	End
 	
 	
 	#rem monkeydoc Fits all vertices in the mesh to a box.
 	#rem monkeydoc Fits all vertices in the mesh to a box.
@@ -221,21 +349,18 @@ Class Mesh Extends Resource
 	#end
 	#end
 	Method UpdateNormals()
 	Method UpdateNormals()
 
 
-		Local vcount:=_vbuffer.Length
+		Local vertices:=_vertices.Data
 		
 		
-		Local vertices:=Cast<Vertex3f Ptr>( _vbuffer.Data )
-		
-		For Local i:=0 Until vcount
+		For Local i:=0 Until _vertices.Length
 			
 			
 			vertices[i].normal=New Vec3f(0)
 			vertices[i].normal=New Vec3f(0)
 		Next
 		Next
 		
 		
-		For Local ibuffer:=Eachin _ibuffers
+		For Local material:=Eachin _materials
 			
 			
-			Local icount:=ibuffer.Length
-			Local indices:=Cast<UInt Ptr>( ibuffer.Data )
+			Local indices:=material.indices.Data
 		
 		
-			For Local i:=0 Until icount Step 3
+			For Local i:=0 Until material.indices.Length
 				
 				
 				Local i1:=indices[i+0]
 				Local i1:=indices[i+0]
 				Local i2:=indices[i+1]
 				Local i2:=indices[i+1]
@@ -255,11 +380,12 @@ Class Mesh Extends Resource
 		
 		
 		Next
 		Next
 		
 		
-		For Local i:=0 Until vcount
+		For Local i:=0 Until _vertices.Length
 			
 			
 			vertices[i].normal=vertices[i].normal.Normalize()
 			vertices[i].normal=vertices[i].normal.Normalize()
 		Next
 		Next
-	
+
+		InvalidateVertices()
 	End
 	End
 
 
 	#rem monkeydoc Updates mesh tangents.
 	#rem monkeydoc Updates mesh tangents.
@@ -269,19 +395,16 @@ Class Mesh Extends Resource
 	#end
 	#end
 	Method UpdateTangents()
 	Method UpdateTangents()
 		
 		
-		Local vcount:=_vbuffer.Length
+		Local vertices:=_vertices.Data.Data
 		
 		
-		Local vertices:=Cast<Vertex3f Ptr>( _vbuffer.Data )
+		Local tan1:=New Vec3f[_vertices.Length]
+		Local tan2:=New Vec3f[_vertices.Length]
 		
 		
-		Local tan1:=New Vec3f[vcount]
-		Local tan2:=New Vec3f[vcount]
-		
-		For Local ibuffer:=Eachin _ibuffers
+		For Local material:=Eachin _materials
 			
 			
-			Local icount:=ibuffer.Length
-			Local indices:=Cast<UInt Ptr>( ibuffer.Data )
+			Local indices:=material.indices.Data
 		
 		
-			For Local i:=0 Until icount Step 3
+			For Local i:=0 Until material.indices.Length Step 3
 				
 				
 				Local i1:=indices[i+0]
 				Local i1:=indices[i+0]
 				Local i2:=indices[i+1]
 				Local i2:=indices[i+1]
@@ -316,9 +439,10 @@ Class Mesh Extends Resource
 				tan2[i2]+=tdir
 				tan2[i2]+=tdir
 				tan2[i3]+=tdir
 				tan2[i3]+=tdir
 			Next
 			Next
+			
 		Next
 		Next
 	
 	
-		For Local i:=0 Until vcount
+		For Local i:=0 Until _vertices.Length
 			
 			
 			Local v:=vertices+i
 			Local v:=vertices+i
 	
 	
@@ -329,24 +453,24 @@ Class Mesh Extends Resource
 			v->tangent.w=n.Cross( t ).Dot( tan2[i] ) < 0 ? -1 Else 1
 			v->tangent.w=n.Cross( t ).Dot( tan2[i] ) < 0 ? -1 Else 1
 		Next
 		Next
 		
 		
-		_vbuffer.Invalidate()
+		InvalidateVertices()
 	End
 	End
 	
 	
 	#rem monkeydoc Flips all triangles.
 	#rem monkeydoc Flips all triangles.
 	#end
 	#end
 	Method FlipTriangles()
 	Method FlipTriangles()
 		
 		
-		For Local ibuffer:=Eachin _ibuffers
-			
-			Local indices:=Cast<UInt Ptr>( ibuffer.Data )
+		For Local material:=Eachin _materials
 			
 			
-			For Local i:=0 Until ibuffer.Length Step 3
+			Local indices:=material.indices.Data
+		
+			For Local i:=0 Until material.indices.Length Step 3
 				Local t:=indices[i]
 				Local t:=indices[i]
 				indices[i]=indices[i+1]
 				indices[i]=indices[i+1]
 				indices[i+1]=t
 				indices[i+1]=t
 			Next
 			Next
 			
 			
-			ibuffer.Invalidate()
+			material.dirty|=Dirty.IndexBuffer
 		Next
 		Next
 		
 		
 	End
 	End
@@ -355,61 +479,16 @@ Class Mesh Extends Resource
 	#end
 	#end
 	Method ScaleTexCoords( scale:Vec2f )
 	Method ScaleTexCoords( scale:Vec2f )
 		
 		
-		Local vertices:=Cast<Vertex3f Ptr>( _vbuffer.Data )
+		Local vertices:=_vertices.Data
 		
 		
-		For Local i:=0 Until _vbuffer.Length
+		For Local i:=0 Until _vertices.Length
 		
 		
 			vertices[i].texCoord0*=scale
 			vertices[i].texCoord0*=scale
 		Next
 		Next
 		
 		
-		_vbuffer.Invalidate()
-	End
-
-	#rem monkeydoc Gets all vertices in the mesh.
-	#end	
-	Method GetVertices:Vertex3f[]()
-		
-		Local vertices:=New Vertex3f[ _vbuffer.Length ]
-		
-		libc.memcpy( vertices.Data,_vbuffer.Data,_vbuffer.Length*_vbuffer.Pitch )
-		
-		Return vertices
-	End
-	
-	#rem monkeydoc Get indices for a material id.
-	#end
-	Method GetIndices:UInt[]( materialid:Int )
-	
-		Local ibuffer:=_ibuffers[materialid]
-		
-		Local indices:=New UInt[ ibuffer.Length ]
-		
-		libc.memcpy( indices.Data,ibuffer.Data,ibuffer.Length*4 )
-		
-		Return indices
+		InvalidateVertices()
 	End
 	End
 
 
-	#rem monkeydoc Gets all indices in the mesh.
-	#end	
-	Method GetAllIndices:UInt[]()
-	
-		Local n:=0
-		For Local ibuffer:=Eachin _ibuffers
-			n+=ibuffer.Length
-		Next
-		
-		Local indices:=New UInt[ n ],p:=indices.Data
-		
-		For Local ibuffer:=Eachin _ibuffers
-			
-			libc.memcpy( p,ibuffer.Data,ibuffer.Length*4 )
-		
-			p+=ibuffer.Length
-		Next
-		
-		Return indices
-	End
-	
 	#rem monkeydoc Loads a mesh from a file.
 	#rem monkeydoc Loads a mesh from a file.
 	
 	
 	On its own, mojo3d can only load gltf2 format mesh and model files.
 	On its own, mojo3d can only load gltf2 format mesh and model files.
@@ -438,31 +517,87 @@ Class Mesh Extends Resource
 		Return Null
 		Return Null
 	End
 	End
 	
 	
-	'***** INTERNAL *****
+	Internal
 	
 	
-	#rem monkeydoc @hidden
-	#end
 	Method GetVertexBuffer:VertexBuffer()
 	Method GetVertexBuffer:VertexBuffer()
 		
 		
+		If _dirty & Dirty.VertexBuffer
+			
+			_vbuffer=New VertexBuffer( Vertex3f.Format,_vertices.Length )
+			
+			_vbuffer.SetVertices( _vertices.Data.Data,0,_vertices.Length )
+			
+			_dirty&=~Dirty.VertexBuffer
+		End
+		
 		Return _vbuffer
 		Return _vbuffer
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#end
-	Method GetIndexBuffers:Stack<IndexBuffer>()
+	Method GetIndexBuffer:IndexBuffer( materialid:Int )
 		
 		
-		Return _ibuffers
+		Local material:=_materials[materialid]
+		
+		If material.dirty & Dirty.IndexBuffer
+			
+			Local indices:=material.indices
+			
+			material.ibuffer=New IndexBuffer( IndexFormat.UINT32,indices.Length )
+			
+			material.ibuffer.SetIndices( indices.Data.Data,0,indices.Length )
+			
+			material.dirty&=~Dirty.IndexBuffer
+		End
+		
+		Return material.ibuffer
 	End
 	End
 	
 	
 	Private
 	Private
 	
 	
 	Enum Dirty
 	Enum Dirty
 		Bounds=1
 		Bounds=1
+		VertexBuffer=2
+		IndexBuffer=4
+	End
+	
+	class MaterialID
+		Field indices:=New Stack<UInt>
+		Field dirty:Dirty=Dirty.IndexBuffer
+		Field ibuffer:IndexBuffer
 	End
 	End
 	
 	
-	Field _dirty:Dirty
-	Field _bounds:Boxf
+	Field _vertices:=New Stack<Vertex3f>
+	Field _materials:=New Stack<MaterialID>
+	
+	Field _dirty:Dirty=Null
+	Field _bounds:Boxf=Boxf.EmptyBounds
 	Field _vbuffer:VertexBuffer
 	Field _vbuffer:VertexBuffer
-	Field _ibuffers:Stack<IndexBuffer>
+	Field _minDirty:Int
+	Field _maxDirty:Int
+	
+	Method InvalidateVertices( first:Int,count:Int )
+		
+		_minDirty=Min( _minDirty,first )
+		_maxDirty=Max( _maxDirty,first+count )
+		
+		_dirty|=Dirty.Bounds|Dirty.VertexBuffer
+	End
+	
+	Method InvalidateVertices()
+		
+		InvalidateVertices( 0,_vertices.Length )
+	End
+	
+	Method GetMaterial:MaterialID( materialid:Int,dirty:Dirty=Dirty.IndexBuffer )
+		
+		DebugAssert( materialid>=0 And materialid<=_materials.Length,"Materialid out of range" )
+		
+		If materialid=_materials.Length AddMaterials( 1 )
+			
+		Local material:=_materials[materialid]
+		
+		material.dirty|=dirty
+
+		Return material
+	End
 	
 	
 End
 End

+ 25 - 58
modules/mojo3d/graphics/model.monkey2

@@ -3,7 +3,7 @@ Namespace mojo3d.graphics
 
 
 #rem monkeydoc The Model class.
 #rem monkeydoc The Model class.
 #end
 #end
-Class Model Extends Entity
+Class Model Extends Renderable
 	
 	
 	#rem monkeydoc @hidden
 	#rem monkeydoc @hidden
 	#end
 	#end
@@ -83,15 +83,6 @@ Class Model Extends Entity
 		_bones=bones
 		_bones=bones
 	End
 	End
 	
 	
-	Property CastsShadow:Bool()
-		
-		Return _castsShadow
-		
-	Setter( castsShadow:Bool )
-	
-		_castsShadow=castsShadow
-	End
-	
 	#rem monkeydoc Loads a model from a file path.
 	#rem monkeydoc Loads a model from a file path.
 	
 	
 	On its own, mojo3d can only load gltf2 format mesh and model files.
 	On its own, mojo3d can only load gltf2 format mesh and model files.
@@ -148,19 +139,27 @@ Class Model Extends Entity
 		
 		
 		Return Null
 		Return Null
 	End
 	End
+	
+	Protected
 
 
-	#rem monkeydoc @hidden
-	#end	
-	Method OnRender( rq:RenderQueue )
+	Method New( model:Model,parent:Entity )
+		Super.New( model,parent )
 		
 		
-		If Not _mesh Return
+		_mesh=model._mesh
+		
+		_material=model._material
 		
 		
-		Local instance:=Self
+		_materials=model._materials.Slice( 0 )
+	End
+	
+	Internal
+
+	Method OnRender( rq:RenderQueue ) Override
+		
+		If Not _mesh Return
 		
 		
 		If _bones
 		If _bones
 
 
-			instance=Null
-		
 			If _boneMatrices.Length<>_bones.Length _boneMatrices=New Mat4f[ _bones.Length ]
 			If _boneMatrices.Length<>_bones.Length _boneMatrices=New Mat4f[ _bones.Length ]
 			
 			
 			For Local i:=0 Until _bones.Length
 			For Local i:=0 Until _bones.Length
@@ -171,51 +170,21 @@ Class Model Extends Entity
 		
 		
 		Local vbuffer:=_mesh.GetVertexBuffer()
 		Local vbuffer:=_mesh.GetVertexBuffer()
 		
 		
-		Local ibuffers:=_mesh.GetIndexBuffers()
-		
-		For Local i:=0 Until ibuffers.Length
-			
+		For Local i:=0 Until _mesh.NumMaterials
+
+			Local ibuffer:=_mesh.GetIndexBuffer( i )
+
 			Local material:=i<_materials.Length And _materials[i] ? _materials[i] Else _material
 			Local material:=i<_materials.Length And _materials[i] ? _materials[i] Else _material
 			
 			
-			Local ibuffer:=ibuffers[i]
-			
-			rq.AddRenderOp( material,vbuffer,ibuffer,instance,_boneMatrices,3,ibuffer.Length/3,0 )
+			If _bones
+				rq.AddRenderOp( material,_boneMatrices,vbuffer,ibuffer,3,ibuffer.Length/3,0 )
+			Else
+				rq.AddRenderOp( material,Self,vbuffer,ibuffer,3,ibuffer.Length/3,0 )
+			Endif
 			
 			
 		Next
 		Next
 	End
 	End
 	
 	
-	Protected
-
-	#rem monkeydoc @hidden
-	#end
-	Method New( model:Model,parent:Entity )
-		Super.New( model,parent )
-		
-		_mesh=model._mesh
-		
-		_material=model._material
-		
-		_materials=model._materials.Slice( 0 )
-		
-		_castsShadow=model._castsShadow
-		
-		Show()
-	End
-
-	#rem monkeydoc @hidden
-	#end	
-	Method OnShow() Override
-		
-		Scene.Models.Add( Self )
-	End
-	
-	#rem monkeydoc @hidden
-	#end	
-	Method OnHide() Override
-		
-		Scene.Models.Remove( Self )
-	End
-	
 	Private
 	Private
 	
 	
 	Field _mesh:Mesh
 	Field _mesh:Mesh
@@ -225,6 +194,4 @@ Class Model Extends Entity
 	Field _bones:Bone[]
 	Field _bones:Bone[]
 	Field _boneMatrices:Mat4f[]
 	Field _boneMatrices:Mat4f[]
 	
 	
-	Field _castsShadow:Bool=true
-	
 End
 End

+ 15 - 8
modules/mojo3d/graphics/particlebuffer.monkey2

@@ -7,13 +7,14 @@ Class ParticleBuffer
 	
 	
 		_length=length
 		_length=length
 
 
-		_vbuffer=New VertexBuffer( Vertex3fFormat.Instance,_length )
+		_vbuffer=New VertexBuffer( Vertex3f.Format,_length )
 		
 		
 		_uniforms=New UniformBlock( 4,true )
 		_uniforms=New UniformBlock( 4,true )
 		
 		
-		Local vertices:=_vbuffer.AddVertices( _length )
-		
-		libc.memset( vertices,0,_vbuffer.Pitch*_length )
+		Local vertices:=_vbuffer.Lock()
+		libc.memset( vertices,0,_vbuffer.Length*_vbuffer.Pitch)
+		_vbuffer.Invalidate()
+		_vbuffer.Unlock()
 
 
 		Gravity=New Vec3f( 0,-9.81,0 )
 		Gravity=New Vec3f( 0,-9.81,0 )
 		Duration=5.0
 		Duration=5.0
@@ -137,17 +138,23 @@ Class ParticleBuffer
 			
 			
 			local timeStep:=frames * (1.0/60.0) / n
 			local timeStep:=frames * (1.0/60.0) / n
 			
 			
+			Local vertices:=Cast<Vertex3f Ptr>( _vbuffer.Lock() )
+			
 			For Local i:=0 Until n
 			For Local i:=0 Until n
 			
 			
-				AddParticle( _time )
+				AddParticle( vertices,_time )
 				
 				
 				_time+=timeStep
 				_time+=timeStep
 				
 				
 			Next
 			Next
+			
+			_vbuffer.Unlock()
+			
+			_vbuffer.Invalidate()
 
 
 		Endif
 		Endif
 		
 		
-		rq.AddRenderOp( material,_uniforms,instance,_vbuffer,Null,1,_length,0 )
+		rq.AddSpriteOp( material,_uniforms,instance,_vbuffer,Null,1,_length,0 )
 	End		
 	End		
 	
 	
 	Private
 	Private
@@ -167,7 +174,7 @@ Class ParticleBuffer
 	Field _time:Float
 	Field _time:Float
 	Field _index:Int
 	Field _index:Int
 
 
-	Method AddParticle( time:Float )
+	Method AddParticle( vertices:Vertex3f Ptr,time:Float )
 	
 	
 		Local r:=Rnd( -Pi,Pi )
 		Local r:=Rnd( -Pi,Pi )
 		Local d:=Rnd( 0,Tan( _coneAngle*.5*TwoPi/360.0 ) )
 		Local d:=Rnd( 0,Tan( _coneAngle*.5*TwoPi/360.0 ) )
@@ -188,7 +195,7 @@ Class ParticleBuffer
 		Local velocity:=New Vec3f( vx,vy,1.0 ) * sp '.Normalize() * sp
 		Local velocity:=New Vec3f( vx,vy,1.0 ) * sp '.Normalize() * sp
 		#end
 		#end
 			
 			
-		Local vertex:=Cast<Vertex3f Ptr>( _vbuffer.Data )+_index
+		Local vertex:=vertices+_index
 		
 		
 		_index+=1 
 		_index+=1 
 		
 		

+ 2 - 22
modules/mojo3d/graphics/particlesystem.monkey2

@@ -1,7 +1,7 @@
 
 
 Namespace mojo3d.graphics
 Namespace mojo3d.graphics
 
 
-Class ParticleSystem Extends Entity
+Class ParticleSystem Extends Renderable
 
 
 	#rem monkeydoc Creates a new particle system.
 	#rem monkeydoc Creates a new particle system.
 	#end
 	#end
@@ -11,8 +11,6 @@ Class ParticleSystem Extends Entity
 		_pbuffer=New ParticleBuffer( particleCount )
 		_pbuffer=New ParticleBuffer( particleCount )
 		
 		
 		_material=New ParticleMaterial
 		_material=New ParticleMaterial
-
-		Show()
 	End
 	End
 
 
 	Method New( particleBuffer:ParticleBuffer,material:ParticleMaterial,parent:Entity=Null )
 	Method New( particleBuffer:ParticleBuffer,material:ParticleMaterial,parent:Entity=Null )
@@ -21,8 +19,6 @@ Class ParticleSystem Extends Entity
 		_pbuffer=particleBuffer
 		_pbuffer=particleBuffer
 		
 		
 		_material=material
 		_material=material
-		
-		Show()
 	End
 	End
 
 
 	#rem monkeydoc Copies the particle system.
 	#rem monkeydoc Copies the particle system.
@@ -69,27 +65,11 @@ Class ParticleSystem Extends Entity
 		_pbuffer=psystem._pbuffer
 		_pbuffer=psystem._pbuffer
 		
 		
 		_material=psystem._material
 		_material=psystem._material
-		
-		Show()
-	End
-	
-	#rem monkeydoc @hidden
-	#End		
-	Method OnShow() Override
-		
-		Scene.ParticleSystems.Add( Self )
-	End
-	
-	#rem monkeydoc @hidden
-	#End		
-	Method OnHide() Override
-		
-		Scene.ParticleSystems.Remove( Self )
 	End
 	End
 	
 	
 	Internal
 	Internal
 	
 	
-	Method OnRender( rq:RenderQueue )
+	Method OnRender( rq:RenderQueue ) override
 	
 	
 		_pbuffer.OnRender( rq,_material,Self )
 		_pbuffer.OnRender( rq,_material,Self )
 	End
 	End

+ 35 - 2
modules/mojo3d/graphics/renderable.monkey2

@@ -4,15 +4,48 @@ Namespace mojo3d.graphics
 Class Renderable Extends Entity Abstract
 Class Renderable Extends Entity Abstract
 
 
 	Method New( parent:Entity=Null )
 	Method New( parent:Entity=Null )
+	
 		Super.New( parent )
 		Super.New( parent )
+		
+		Show()
 	End
 	End
 	
 	
+	Property CastsShadow:bool()
+	
+		Return _castsShadow
+	
+	Setter( castsShadow:Bool )
+	
+		_castsShadow=castsShadow
+	End
+	
+	Protected
+	
 	Method New( renderable:Renderable,parent:Entity )
 	Method New( renderable:Renderable,parent:Entity )
+	
 		Super.New( renderable,parent )
 		Super.New( renderable,parent )
+		
+		_castsShadow=renderable.CastsShadow
+		
+		Show()
+	End
+	
+	Method OnShow() Override
+		
+		Scene.Renderables.Add( Self )
 	End
 	End
 	
 	
-	'***** INTERNAL *****
+	Method OnHide() Override
+		
+		Scene.Renderables.Remove( Self )
+	End
+	
+	Internal
+	
+	Method OnRender( rq:RenderQueue ) Abstract
+	
+	Private
 	
 	
-	Method OnRender( device:GraphicsDevice ) Abstract
+	Field _castsShadow:bool
 	
 	
 End
 End

+ 8 - 18
modules/mojo3d/graphics/renderer.monkey2

@@ -140,22 +140,13 @@ Class Renderer
 		_renderQueue.Time=time
 		_renderQueue.Time=time
 		
 		
 		_renderQueue.AddShadowOps=False
 		_renderQueue.AddShadowOps=False
-			
-		For Local model:=Eachin _renderScene.Models
-			
-			_renderQueue.AddShadowOps=model.CastsShadow
-			
-			model.OnRender( _renderQueue )
-		Next
-		
-		_spriteQueue.Clear()
-		
-		_spriteQueue.Time=time
 		
 		
-		For Local psystem:=Eachin _renderScene.ParticleSystems
+		For Local r:=Eachin _renderScene.Renderables
 		
 		
-			psystem.OnRender( _spriteQueue )
-		End
+			_renderQueue.AddShadowOps=r.CastsShadow
+			
+			r.OnRender( _renderQueue )
+		Next
 		
 		
 		'***** Set render camera *****
 		'***** Set render camera *****
 
 
@@ -165,7 +156,6 @@ Class Renderer
 		Local viewMat:=_renderCamera.InverseMatrix
 		Local viewMat:=_renderCamera.InverseMatrix
 		Local projMat:=_renderCamera.ProjectionMatrix
 		Local projMat:=_renderCamera.ProjectionMatrix
 		Local invProjMat:=-projMat
 		Local invProjMat:=-projMat
-		
 			
 			
 		_runiforms.SetMat3f( "EnvMatrix",envMat )
 		_runiforms.SetMat3f( "EnvMatrix",envMat )
 		_runiforms.SetMat4f( "ProjectionMatrix",projMat )
 		_runiforms.SetMat4f( "ProjectionMatrix",projMat )
@@ -175,7 +165,7 @@ Class Renderer
 		_runiforms.SetFloat( "DepthNear",_renderCamera.Near )
 		_runiforms.SetFloat( "DepthNear",_renderCamera.Near )
 		_runiforms.SetFloat( "DepthFar",_renderCamera.Far )
 		_runiforms.SetFloat( "DepthFar",_renderCamera.Far )
 		
 		
-		_spriteBuffer.AddSprites( _spriteQueue,_renderScene.Sprites,_renderCamera )
+		_spriteBuffer.AddSprites( _renderQueue,_renderCamera )
 		
 		
 		OnRender( scene,camera,device )
 		OnRender( scene,camera,device )
 		
 		
@@ -252,7 +242,7 @@ Class Renderer
 	Method RenderQuad()
 	Method RenderQuad()
 
 
 		Global _vertices:VertexBuffer
 		Global _vertices:VertexBuffer
-	
+		
 		If Not _vertices
 		If Not _vertices
 			_vertices=New VertexBuffer( New Vertex3f[](
 			_vertices=New VertexBuffer( New Vertex3f[](
 			New Vertex3f( 0,1,0 ),
 			New Vertex3f( 0,1,0 ),
@@ -313,7 +303,7 @@ Class Renderer
 
 
 	Method RenderSpriteOps()
 	Method RenderSpriteOps()
 
 
-		RenderRenderOps( _spriteQueue.TransparentOps,_renderCamera.InverseMatrix,_renderCamera.ProjectionMatrix )
+		RenderRenderOps( _renderQueue.SpriteOps,_renderCamera.InverseMatrix,_renderCamera.ProjectionMatrix )
 	End
 	End
 	
 	
 	#rem
 	#rem

+ 41 - 9
modules/mojo3d/graphics/renderqueue.monkey2

@@ -6,10 +6,10 @@ Namespace mojo3d.graphics
 Class RenderOp
 Class RenderOp
 	Field material:Material
 	Field material:Material
 	Field uniforms:UniformBlock
 	Field uniforms:UniformBlock
-	Field vbuffer:VertexBuffer
-	Field ibuffer:IndexBuffer
 	Field instance:Entity
 	Field instance:Entity
 	Field bones:Mat4f[]
 	Field bones:Mat4f[]
+	Field vbuffer:VertexBuffer
+	Field ibuffer:IndexBuffer
 	Field order:Int
 	Field order:Int
 	Field count:Int
 	Field count:Int
 	Field first:Int
 	Field first:Int
@@ -38,10 +38,21 @@ Class RenderQueue
 		Return _transparentOps
 		Return _transparentOps
 	End
 	End
 	
 	
+	Property SpriteOps:Stack<RenderOp>()
+	
+		Return _spriteOps
+	End
+	
 	Property ShadowOps:Stack<RenderOp>()
 	Property ShadowOps:Stack<RenderOp>()
 		
 		
 		Return _shadowOps
 		Return _shadowOps
 	End
 	End
+
+	'bit of a hack for now, but renderqueue should be able to handle sprites...	
+	Property Sprites:Stack<Sprite>()
+	
+		Return _sprites
+	End
 	
 	
 	Property AddShadowOps:Bool()
 	Property AddShadowOps:Bool()
 		
 		
@@ -53,7 +64,8 @@ Class RenderQueue
 	End
 	End
 	
 	
 	Method Clear()
 	Method Clear()
-		
+	
+		_sprites.Clear()	
 		_opaqueOps.Clear()
 		_opaqueOps.Clear()
 		_shadowOps.Clear()
 		_shadowOps.Clear()
 		_transparentOps.Clear()
 		_transparentOps.Clear()
@@ -88,9 +100,10 @@ Class RenderQueue
 		AddRenderOp( op )
 		AddRenderOp( op )
 	End
 	End
 	
 	
-	Method AddRenderOp( material:Material,vbuffer:VertexBuffer,ibuffer:IndexBuffer,order:Int,count:Int,first:Int )
+	Method AddRenderOp( material:Material,instance:Entity,vbuffer:VertexBuffer,ibuffer:IndexBuffer,order:Int,count:Int,first:Int )
 		Local op:=New RenderOp
 		Local op:=New RenderOp
 		op.material=material
 		op.material=material
+		op.instance=instance
 		op.vbuffer=vbuffer
 		op.vbuffer=vbuffer
 		op.ibuffer=ibuffer
 		op.ibuffer=ibuffer
 		op.order=order
 		op.order=order
@@ -99,37 +112,56 @@ Class RenderQueue
 		AddRenderOp( op )
 		AddRenderOp( op )
 	End
 	End
 	
 	
-	Method AddRenderOp( material:Material,vbuffer:VertexBuffer,ibuffer:IndexBuffer,instance:Entity,order:Int,count:Int,first:Int )
+	Method AddRenderOp( material:Material,bones:Mat4f[],vbuffer:VertexBuffer,ibuffer:IndexBuffer,order:Int,count:Int,first:Int )
 		Local op:=New RenderOp
 		Local op:=New RenderOp
 		op.material=material
 		op.material=material
+		op.bones=bones
 		op.vbuffer=vbuffer
 		op.vbuffer=vbuffer
 		op.ibuffer=ibuffer
 		op.ibuffer=ibuffer
-		op.instance=instance
 		op.order=order
 		op.order=order
 		op.count=count
 		op.count=count
 		op.first=first
 		op.first=first
 		AddRenderOp( op )
 		AddRenderOp( op )
 	End
 	End
 	
 	
-	Method AddRenderOp( material:Material,vbuffer:VertexBuffer,ibuffer:IndexBuffer,instance:Entity,bones:Mat4f[],order:Int,count:Int,first:Int )
+	Method AddRenderOp( material:Material,vbuffer:VertexBuffer,ibuffer:IndexBuffer,order:Int,count:Int,first:Int )
 		Local op:=New RenderOp
 		Local op:=New RenderOp
 		op.material=material
 		op.material=material
 		op.vbuffer=vbuffer
 		op.vbuffer=vbuffer
 		op.ibuffer=ibuffer
 		op.ibuffer=ibuffer
-		op.instance=instance
-		op.bones=bones
 		op.order=order
 		op.order=order
 		op.count=count
 		op.count=count
 		op.first=first
 		op.first=first
 		AddRenderOp( op )
 		AddRenderOp( op )
 	End
 	End
 	
 	
+	Method AddSpriteOp( material:Material,uniforms:UniformBlock,instance:Entity,vbuffer:VertexBuffer,ibuffer:IndexBuffer,order:Int,count:Int,first:Int )
+		Local op:=New RenderOp
+		op.material=material
+		op.uniforms=uniforms
+		op.instance=instance
+		op.vbuffer=vbuffer
+		op.ibuffer=ibuffer
+		op.order=order
+		op.count=count
+		op.first=first
+		_spriteOps.Add( op )
+	End
+	
+	Method AddSprite( sprite:Sprite )
+	
+		_sprites.Add( sprite )
+	End
+	
 	Private
 	Private
 
 
 	Field _time:float	
 	Field _time:float	
 	Field _opaqueOps:=New Stack<RenderOp>
 	Field _opaqueOps:=New Stack<RenderOp>
 	Field _transparentOps:=New Stack<RenderOp>
 	Field _transparentOps:=New Stack<RenderOp>
+	Field _spriteOps:=New Stack<RenderOp>
 	Field _shadowOps:=New Stack<RenderOp>
 	Field _shadowOps:=New Stack<RenderOp>
 	
 	
+	Field _sprites:=New Stack<Sprite>
+	
 	Field _addShadowOps:Bool
 	Field _addShadowOps:Bool
 End
 End

+ 3 - 15
modules/mojo3d/graphics/scene.monkey2

@@ -180,19 +180,9 @@ Class Scene Extends DynamicObject
 		Return _lights
 		Return _lights
 	End
 	End
 	
 	
-	Property Models:Stack<Model>()
-		
-		Return _models
-	End
-	
-	Property Sprites:Stack<Sprite>()
-		
-		Return _sprites
-	End
-	
-	Property ParticleSystems:Stack<ParticleSystem>()
+	Property Renderables:Stack<Renderable>()
 	
 	
-		Return _psystems
+		Return _renderables
 	End
 	End
 	
 	
 	Private
 	Private
@@ -214,8 +204,6 @@ Class Scene Extends DynamicObject
 	
 	
 	Field _cameras:=New Stack<Camera>
 	Field _cameras:=New Stack<Camera>
 	Field _lights:=New Stack<Light>
 	Field _lights:=New Stack<Light>
-	Field _models:=New Stack<Model>
-	Field _sprites:=New Stack<Sprite>
-	Field _psystems:=New Stack<ParticleSystem>
+	Field _renderables:=New Stack<Renderable>()
 			
 			
 End
 End

+ 3 - 18
modules/mojo3d/graphics/sprite.monkey2

@@ -16,14 +16,12 @@ End
 
 
 #rem monkeydoc The Sprite class.
 #rem monkeydoc The Sprite class.
 #end
 #end
-Class Sprite Extends Entity
+Class Sprite Extends Renderable
 	
 	
 	#rem monkeydoc Creates a new sprite.
 	#rem monkeydoc Creates a new sprite.
 	#end
 	#end
 	Method New( parent:Entity=Null )
 	Method New( parent:Entity=Null )
 		Super.New( parent )
 		Super.New( parent )
-
-		Show()
 	End
 	End
 
 
 	Method New( material:Material,parent:Entity=Null )
 	Method New( material:Material,parent:Entity=Null )
@@ -99,30 +97,17 @@ Class Sprite Extends Entity
 	
 	
 	Protected
 	Protected
 
 
-	#rem monkeydoc @hidden
-	#End		
 	Method New( sprite:Sprite,parent:Entity )
 	Method New( sprite:Sprite,parent:Entity )
 		Super.New( sprite,parent )
 		Super.New( sprite,parent )
 		
 		
 		_material=sprite._material
 		_material=sprite._material
 		_handle=sprite._handle
 		_handle=sprite._handle
 		_mode=sprite._mode
 		_mode=sprite._mode
-		
-		Show()
 	End
 	End
 	
 	
-	#rem monkeydoc @hidden
-	#End		
-	Method OnShow() Override
-		
-		Scene.Sprites.Add( Self )
-	End
+	Method OnRender( rq:RenderQueue ) Override
 	
 	
-	#rem monkeydoc @hidden
-	#End		
-	Method OnHide() Override
-		
-		Scene.Sprites.Remove( Self )
+		rq.AddSprite( Self )
 	End
 	End
 	
 	
 	Private
 	Private

+ 30 - 22
modules/mojo3d/graphics/spritebuffer.monkey2

@@ -6,37 +6,42 @@ Namespace mojo3d.graphics
 Class SpriteBuffer
 Class SpriteBuffer
 	
 	
 	Method New()
 	Method New()
+		_vbuffer=New VertexBuffer( Vertex3f.Format,0 )
 		
 		
-		If _spriteVertices Return
-		
-		_spriteVertices=New VertexBuffer( Vertex3fFormat.Instance,0 )
-		
-		_spriteIndices=New IndexBuffer( IndexFormat.UINT32,0 )
+		_ibuffer=New IndexBuffer( IndexFormat.UINT32,0 )
 	End
 	End
 	
 	
-	Method AddSprites( rq:RenderQueue,sprites:Stack<Sprite>,camera:Camera )
+	Method AddSprites( rq:RenderQueue,camera:Camera )
+	
+		Local sprites:=rq.Sprites
 		
 		
 		If sprites.Empty Return
 		If sprites.Empty Return
 		
 		
 		Local n:=sprites.Length
 		Local n:=sprites.Length
 		
 		
-		_spriteVertices.Clear()
-		Local vp:=Cast<Vertex3f Ptr>( _spriteVertices.AddVertices( n*4 ) )
+		If n*4>_vbuffer.Length
+			_vbuffer.Resize( Max( _vbuffer.Length*3/2,n*4 ) )
+		Endif
 		
 		
-		If n>_spriteIndices.Length/6
-			Local i:=_spriteIndices.Length/6
-			Local ip:=Cast<UInt Ptr>( _spriteIndices.AddIndices( (n-i)*6 ) )
-			For Local j:=i Until n
-				ip[0]=j*4
-				ip[1]=j*4+1
-				ip[2]=j*4+2
-				ip[3]=j*4
-				ip[4]=j*4+2
-				ip[5]=j*4+3
+		If n*6>_ibuffer.Length
+			Local i0:=_ibuffer.Length/6
+			_ibuffer.Resize( Max( _ibuffer.Length*3/2,n*6 ) )
+			Local ip:=Cast<UInt Ptr>( _ibuffer.Lock() )+i0*6
+			For Local i:=i0 Until n
+				ip[0]=i*4
+				ip[1]=i*4+1
+				ip[2]=i*4+2
+				ip[3]=i*4
+				ip[4]=i*4+2
+				ip[5]=i*4+3
 				ip+=6
 				ip+=6
 			Next
 			Next
+			_ibuffer.Invalidate( i0*6,(n-i0)*6 )
+			_ibuffer.Unlock()
 		Endif
 		Endif
 		
 		
+		Local vp:=Cast<Vertex3f Ptr>( _vbuffer.Lock() )
+		
 		'Sort sprites by distance from camera. Only really need to do this for transparent sprites, but meh...
 		'Sort sprites by distance from camera. Only really need to do this for transparent sprites, but meh...
 		'
 		'
 		sprites.Sort( Lambda:Int( x:Sprite,y:Sprite )
 		sprites.Sort( Lambda:Int( x:Sprite,y:Sprite )
@@ -50,7 +55,7 @@ Class SpriteBuffer
 			
 			
 			Local material:=sprite.Material
 			Local material:=sprite.Material
 			If material<>cmaterial
 			If material<>cmaterial
-				rq.AddRenderOp( cmaterial,_spriteVertices,_spriteIndices,3,(i-i0)*2,i0*6 )
+				rq.AddSpriteOp( cmaterial,Null,Null,_vbuffer,_ibuffer,3,(i-i0)*2,i0*6 )
 				cmaterial=material
 				cmaterial=material
 				i0=i
 				i0=i
 			Endif
 			Endif
@@ -83,14 +88,17 @@ Class SpriteBuffer
 			i+=1
 			i+=1
 		Next
 		Next
 		
 		
-		rq.AddRenderOp( cmaterial,_spriteVertices,_spriteIndices,3,(i-i0)*2,i0*6 )
+		rq.AddSpriteOp( cmaterial,Null,Null,_vbuffer,_ibuffer,3,(i-i0)*2,i0*6 )
+		
+		_vbuffer.Invalidate()
 		
 		
+		_vbuffer.Unlock()
 	End
 	End
 
 
 	Private
 	Private
 	
 	
-	Field _spriteVertices:VertexBuffer
+	Field _vbuffer:VertexBuffer
 	
 	
-	Field _spriteIndices:IndexBuffer
+	Field _ibuffer:IndexBuffer
 	
 	
 End
 End

+ 1 - 0
modules/mojo3d/mojo3d.monkey2

@@ -42,6 +42,7 @@ Using gles20..
 #Import "graphics/entityexts"
 #Import "graphics/entityexts"
 
 
 #Import "graphics/renderqueue"
 #Import "graphics/renderqueue"
+#Import "graphics/renderable"
 #Import "graphics/renderer"
 #Import "graphics/renderer"
 #Import "graphics/deferredrenderer"
 #Import "graphics/deferredrenderer"
 #Import "graphics/forwardrenderer"
 #Import "graphics/forwardrenderer"

+ 5 - 4
modules/mojo3d/tests/ducks.monkey2

@@ -38,8 +38,9 @@ Class MyWindow Extends Window
 		'create scene
 		'create scene
 		'		
 		'		
 		_scene=Scene.GetCurrent()
 		_scene=Scene.GetCurrent()
+		
 		_scene.ClearColor=Color.Sky
 		_scene.ClearColor=Color.Sky
-
+		
 		'add fog effect to scene
 		'add fog effect to scene
 		'		
 		'		
 '		_fog=New FogEffect
 '		_fog=New FogEffect
@@ -66,7 +67,7 @@ Class MyWindow Extends Window
 
 
 		'create ground
 		'create ground
 		'
 		'
-		_ground=Model.CreateBox( New Boxf( -50,-1,-50,50,0,50 ),10,10,10,New PbrMaterial( Color.Green,0,1 ) )
+		_ground=Model.CreateBox( New Boxf( -50,-1,-50,50,0,50 ),1,1,1,New PbrMaterial( Color.Green,0,1 ) )
 		_ground.CastsShadow=False
 		_ground.CastsShadow=False
 		
 		
 		'create ducks
 		'create ducks
@@ -126,7 +127,7 @@ Class MyWindow Extends Window
 
 
 		canvas.Scale( Width/640.0,Height/480.0 )
 		canvas.Scale( Width/640.0,Height/480.0 )
 		
 		
-		canvas.DrawText( "Width="+Width+", Height="+Height+", FPS="+App.FPS,0,0 )
+		'canvas.DrawText( "Width="+Width+", Height="+Height+", FPS="+App.FPS,0,0 )
 	End
 	End
 	
 	
 End
 End
@@ -140,7 +141,7 @@ Function Main()
 '	config["mojo3d_renderer"]="forward-direct"	'default on mobile targets. depth buffer must be enabled too.
 '	config["mojo3d_renderer"]="forward-direct"	'default on mobile targets. depth buffer must be enabled too.
 '	config["GL_depth_buffer_enabled"]=1
 '	config["GL_depth_buffer_enabled"]=1
 
 
-	config["mojo3d_renderer"]="forward"
+'	config["mojo3d_renderer"]="forward"
 		
 		
 	New AppInstance( config )
 	New AppInstance( config )
 	
 	

+ 165 - 0
modules/mojo3d/tests/morpher.monkey2

@@ -0,0 +1,165 @@
+
+Namespace myapp
+
+#Import "<std>"
+#Import "<mojo>"
+#Import "<mojo3d>"
+
+#Import "assets/"
+
+#Import "util"
+
+Using std..
+Using mojo..
+Using mojo3d..
+
+Class Morpher Extends Renderable
+
+	Method New( mesh0:Mesh,mesh1:Mesh,material:Material,parent:Entity=null )
+		Super.New( parent )
+
+		'get mesh vertices - don't need entire meshes	
+		_vertices0=mesh0.GetVertices()
+		_vertices1=mesh1.GetVertices()
+		_material=material
+		
+		'create vertexbuffer
+		'
+		_vbuffer=New VertexBuffer( Vertex3f.Format,_vertices0.Length )
+		
+		'create and initilize indexbuffer
+		'	
+		Local indices:=mesh0.GetIndices( 0 )
+		_ibuffer=New IndexBuffer( IndexFormat.UINT32,indices.Length )
+		_ibuffer.SetIndices( indices.Data,0,indices.Length )
+	End
+	
+	Protected
+	
+	Method OnRender( rq:RenderQueue ) override
+	
+		Local alpha:=Sin( Now() )*.5+.5
+		
+		'lock vertex buffer
+		Local vp:=Cast<Vertex3f Ptr>( _vbuffer.Lock() )
+		
+		For Local i:=0 Until _vbuffer.Length
+		
+			Local v:=_vertices0[i]
+
+			'interpolate position			
+			v.position=_vertices0[i].position.Blend( _vertices1[i].position,alpha )
+			
+			'interpolate normal
+			v.normal=_vertices0[i].normal.Blend( _vertices1[i].normal,alpha ).Normalize()
+			
+			vp[i]=v
+		Next
+		
+		'invalidate all vertices
+		_vbuffer.Invalidate()
+		
+		'unlock vertices
+		_vbuffer.Unlock()
+		
+		'add renderop
+		rq.AddRenderOp( _material,Self,_vbuffer,_ibuffer,3,_ibuffer.Length/3,0 )
+	End
+	
+	Private
+	
+	Field _vertices0:Vertex3f[]
+	Field _vertices1:Vertex3f[]
+	Field _material:Material
+	
+	Field _vbuffer:VertexBuffer
+	Field _ibuffer:IndexBuffer
+	
+	Field _nvertices:Int
+End
+
+Class MyWindow Extends Window
+	
+	Field _scene:Scene
+	
+	Field _camera:Camera
+	
+	Field _light:Light
+	
+	Field _morpher:Morpher
+	
+	Method New( title:String="Simple mojo app",width:Int=640,height:Int=480,flags:WindowFlags=WindowFlags.Resizable )
+
+		Super.New( title,width,height,flags )
+		
+		Print gles20.glGetString( gles20.GL_EXTENSIONS ).Replace( " ","~n" )
+		
+		'create scene
+		'		
+		_scene=Scene.GetCurrent()
+		
+		_scene.ClearColor=Color.Sky
+		
+		'create camera
+		'
+		_camera=New Camera
+		_camera.Move( 0,0,-5 )
+		
+		'create light
+		'
+		_light=New Light
+		_light.RotateX( 90 )
+		_light.CastsShadow=True
+		
+		Local mesh1:=Mesh.CreateBox( New Boxf( -1,1 ),8,8,8 )
+		
+		Local mesh2:=Mesh.CreateBox( New Boxf( -1,1 ),8,8,8 )
+		
+		'sphericalize mesh2
+		For Local i:=0 Until mesh2.NumVertices
+			Local v:=mesh2.GetVertex( i )
+			v.position=v.position.Normalize()
+			v.normal=v.position.Normalize()
+			mesh2.SetVertex( i,v )
+		Next
+		
+		Local material:=New PbrMaterial( Color.Green )
+		
+		_morpher=New Morpher( mesh1,mesh2,material )
+	End
+	
+	Method OnRender( canvas:Canvas ) Override
+
+		RequestRender()
+
+		util.Fly( _camera,Self )
+		
+		_scene.Render( canvas,_camera )
+
+		canvas.Scale( Width/640.0,Height/480.0 )
+		
+		canvas.DrawText( "Width="+Width+", Height="+Height+", FPS="+App.FPS,0,0 )
+	End
+	
+End
+
+Function Main()
+	
+	Local config:=New StringMap<String>
+
+'	config["mojo3d_renderer"]="deferred"		'defeault on non-mobile targets.
+
+'	config["mojo3d_renderer"]="forward-direct"	'default on mobile targets. depth buffer must be enabled too.
+'	config["GL_depth_buffer_enabled"]=1
+
+'	config["mojo3d_renderer"]="forward"
+		
+	New AppInstance( config )
+	
+	New MyWindow
+	
+	App.Run()
+End
+		
+		
+