/// <summary> /// Loads a COLLADA section /// </summary> /// <param name="reader">XML reader</param> public override object LoadSection( XmlReader reader ) { Hashtable sources = new Hashtable( ); MeshVertices vertices = null; MeshPolygons polygons = null; while ( reader.Read( ) && reader.NodeType != XmlNodeType.EndElement ) { if ( reader.NodeType != XmlNodeType.Element ) { continue; } switch ( reader.Name ) { case "source": { sources[ reader.GetAttribute( "id" ) ] = new MeshSource( reader ); break; } case "vertices": { vertices = new MeshVertices( reader, sources ); break; } case "polygons": { polygons = new MeshPolygons( reader, false, false ); break; } case "triangles": { polygons = new MeshPolygons( reader, true, false ); break; } default: { ReadPastElement( reader ); break; } } } return BuildMesh( vertices, polygons ); }
/// <summary> /// Builds an OpenGL mesh /// </summary> private object BuildMesh( MeshVertices vertices, MeshPolygons polygons ) { OpenGlMesh mesh = new OpenGlMesh( ); // Set up the index buffer in the mesh if ( polygons.StoredAsTriangles ) { int[] indexBuffer = new int[ polygons.Polygons.Count * 3 ]; int curIndex = 0; foreach ( MeshPolygon curPoly in polygons.Polygons ) { indexBuffer[ curIndex++ ] = curPoly.Indices[ 0 ]; indexBuffer[ curIndex++ ] = curPoly.Indices[ 1 ]; indexBuffer[ curIndex++ ] = curPoly.Indices[ 2 ]; } mesh.CreateGroups( 1 ); mesh.SetGroup( 0, new OpenGlIndexedGroup( Gl.GL_TRIANGLES, indexBuffer ) ); } else { throw new ApplicationException( "sorry, non-triange index buffers not implemented yet" ); } mesh.CreateVertexBuffers( vertices.Sources.Count ); int vboIndex = 0; foreach ( MeshTaggedSource curSource in vertices.Sources ) { // Convert the source semantic to an opengl client state // Swap y and z elements // TODO: Should be a resource flag, at the very least bool swapYz = false; int clientState = 0; switch ( curSource.Semantic ) { case "POSITION": clientState = Gl.GL_VERTEX_ARRAY; swapYz = true; break; case "NORMAL": clientState = Gl.GL_NORMAL_ARRAY; swapYz = true; break; case "COLOR": clientState = Gl.GL_COLOR_ARRAY; break; default: throw new ApplicationException( string.Format( "Unknown mesh semantic \"{0}\"", curSource.Semantic ) ); } // Store the stride (note, for GL this has a slightly different meaning, I think. TODO: Check COLLADA spec. to make sure) int numObjects = curSource.Source.Data.Count / curSource.Source.Stride; short stride = 0; short numElements = ( short )curSource.Source.Stride; Type dataType = curSource.Source.DataType; switch ( Type.GetTypeCode( dataType ) ) { case TypeCode.Single: { // HACK: Swap y and z coordinates - in blender (the 3d editor I'm currently using), z is up, in the engine, y is up. float[] bufferData = ( float[] )curSource.Source.Data.ToArray( dataType ); if ( swapYz ) { for ( int index = 0; index < bufferData.Length; index += 3 ) { float tmp = bufferData[ index + 1 ]; bufferData[ index + 1 ] = bufferData[ index + 2 ]; bufferData[ index + 2 ] = tmp; } } mesh.SetVertexBuffer( vboIndex, new OpenGlVertexBuffer( numObjects, 0, clientState, stride, numElements, Gl.GL_STATIC_DRAW_ARB, bufferData ) ); break; } case TypeCode.Int32: { int[] bufferData = ( int[] )curSource.Source.Data.ToArray( dataType ); mesh.SetVertexBuffer( vboIndex, new OpenGlVertexBuffer( numObjects, 0, clientState, stride, numElements, Gl.GL_STATIC_DRAW_ARB, bufferData ) ); break; } case TypeCode.Byte: { byte[] bufferData = ( byte[] )curSource.Source.Data.ToArray( dataType ); mesh.SetVertexBuffer( vboIndex, new OpenGlVertexBuffer( numObjects, 0, clientState, stride, numElements, Gl.GL_STATIC_DRAW_ARB, bufferData ) ); break; } default: { throw new ApplicationException( string.Format( "Unhandled vertex source type \"{0}\"", curSource.Source.DataType.Name ) ); } } ++vboIndex; } return mesh; }