/// <summary> /// Sets the mesh for a specified body part /// </summary> public void SetPartMesh( ModelPart part, ModelMesh mesh ) { m_PartMeshes[ ( int )part ] = mesh; }
/// <summary> /// Sets the root mesh, rendered /// </summary> public void SetRootMesh( ModelMesh rootMesh ) { m_RootMesh = rootMesh; }
/// <summary> /// Reads surface vertices (positions and normals) /// </summary> private static void ReadVertices( BinaryReader reader, long offset, int numVertices, int numFrames, ModelMesh.Surface surface, Matrix44 transform ) { reader.BaseStream.Seek( offset, SeekOrigin.Begin ); // Allocate surface frames surface.SurfaceFrames = new ModelMesh.SurfaceFrame[ numFrames ]; // Allocate temporary arrays for storing position and normal data float[] positions = new float[ numVertices * 3 ]; float[] normals = new float[ numVertices * 3 ]; // Run through all frames for ( int frameIndex = 0; frameIndex < numFrames; ++frameIndex ) { int positionIndex = 0; int normalIndex = 0; // Allocate a surface frame ModelMesh.SurfaceFrame frame = new ModelMesh.SurfaceFrame( ); // Run through all vertices for ( int vertexCount = 0; vertexCount < numVertices; ++vertexCount ) { // NOTE: Re-order coordinates. I use +ve Y as up, +ve X as right, +ve Z as into, MD3 default is +ve X as into, +ve Y as right, +ve Z as up Point3 pt = new Point3( ); pt.Z = reader.ReadInt16( ) * XyzScale; pt.X = reader.ReadInt16( ) * XyzScale; pt.Y = reader.ReadInt16( ) * XyzScale; pt = transform * pt; positions[ positionIndex + 0 ] = pt.X; positions[ positionIndex + 1 ] = pt.Y; positions[ positionIndex + 2 ] = pt.Z; positionIndex += 3; float s = reader.ReadByte( ) * ByteToAngle; float t = reader.ReadByte( ) * ByteToAngle; normals[ normalIndex + 2 ] = ( Functions.Cos( s ) * Functions.Sin( t ) ); normals[ normalIndex + 0 ] = ( Functions.Sin( s ) * Functions.Sin( t ) ); normals[ normalIndex + 1 ] = ( Functions.Cos( t ) ); normalIndex += 3; } // Convert position and normal data into vertex buffer objects frame.VertexBuffers = new OpenGlVertexArray[ 2 ]; frame.VertexBuffers[ 0 ] = new OpenGlVertexArray( numVertices, 0, Gl.GL_VERTEX_ARRAY, 0, 3, Gl.GL_STATIC_DRAW_ARB, positions ); frame.VertexBuffers[ 1 ] = new OpenGlVertexArray( numVertices, 0, Gl.GL_NORMAL_ARRAY, 0, 3, Gl.GL_STATIC_DRAW_ARB, normals ); // Assign the frame to the surface surface.SurfaceFrames[ frameIndex ] = frame; } }
/// <summary> /// Reads tag information /// </summary> private static void ReadTags( BinaryReader reader, long offset, int numTags, int numFrames, ModelMesh mesh, Matrix44 transform ) { reader.BaseStream.Seek( offset, SeekOrigin.Begin ); mesh.TagNames = new string[ numTags ]; for ( int frameIndex = 0; frameIndex < numFrames; ++frameIndex ) { ModelMesh.Tag[] tags = new ModelMesh.Tag[ numTags ]; for ( int tagCount = 0; tagCount < numTags; ++tagCount ) { string tagName = ReadString( reader, MaxPathLength ); if ( frameIndex == 0 ) { mesh.TagNames[ tagCount ] = tagName; } Point3 origin = transform * ReadPoint( reader ); Vector3 xAxis = ReadVector( reader ); Vector3 yAxis = ReadVector( reader ); Vector3 zAxis = ReadVector( reader ); ModelMesh.Tag curTag = new ModelMesh.Tag( ); curTag.Transform = new Matrix44( origin, xAxis, yAxis, zAxis ); curTag.Name = tagName; tags[ tagCount ] = curTag; } mesh.FrameInfoList[ frameIndex ].Tags = tags; } }
/// <summary> /// Reads surface information /// </summary> private static void ReadSurfaces( ISource source, BinaryReader reader, long offset, int numSurfaces, int numFrames, ModelMesh mesh, IDictionary<string, ITexture2d> surfaceTextureTable, Matrix44 transform) { // Move to the start of the first surface reader.BaseStream.Seek( offset, SeekOrigin.Begin ); // Allocate mesh surface array mesh.Surfaces = new ModelMesh.Surface[ numSurfaces ]; for ( int surfaceCount = 0; surfaceCount < numSurfaces; ++surfaceCount ) { // Create a new surface ModelMesh.Surface curSurface = new ModelMesh.Surface( ); //int ident = reader.ReadInt32( ); string name = ReadString ( reader, MaxPathLength ); //int flags = reader.ReadInt32( ); //int surfaceNumFrames = reader.ReadInt32( ); //int numShaders = reader.ReadInt32( ); int numVertices = reader.ReadInt32( ); int numTriangles = reader.ReadInt32( ); int trianglesOffset = reader.ReadInt32( ); //int shadersOffset = reader.ReadInt32( ); int texturesOffset = reader.ReadInt32( ); int verticesOffset = reader.ReadInt32( ); int endOffset = reader.ReadInt32( ); // Assign surface texture curSurface.Texture = GetTexture( source, surfaceTextureTable, name ); // Assign surface shaders // ReadShaders( reader, offset + shadersOffset, numShaders ); // Read in surface index group and texture UVs curSurface.Group = ReadTriangles( reader, offset + trianglesOffset, numTriangles ); curSurface.TextureUVs = ReadTextureUVs( reader, offset + texturesOffset, numVertices ); // Read in surface vertices // curSurface.NumVertices = numVertices; ReadVertices( reader, offset + verticesOffset, numVertices, numFrames, curSurface, transform ); // Assign the new surface to the mesh mesh.Surfaces[ surfaceCount ] = curSurface; // Move the stream to the next surface reader.BaseStream.Seek( offset + endOffset, SeekOrigin.Begin ); offset += endOffset; } }
/// <summary> /// Reads frame information /// </summary> private static void ReadFrames( BinaryReader reader, long offset, int numFrames, ModelMesh mesh, Matrix44 transform ) { reader.BaseStream.Seek( offset, SeekOrigin.Begin ); ModelMesh.FrameInfo[] frames = new ModelMesh.FrameInfo[ numFrames ]; float scaleLength = ( transform * new Vector3( 1, 1, 1 ) ).Length; for ( int frameCount = 0; frameCount < numFrames; ++frameCount ) { frames[ frameCount] = new ModelMesh.FrameInfo( ); ModelMesh.FrameInfo curFrame = frames[ frameCount ]; curFrame.MinBounds = transform * ReadPoint( reader ); curFrame.MaxBounds = transform * ReadPoint( reader ); curFrame.Origin = transform * ReadPoint( reader ); curFrame.Radius = reader.ReadSingle( ) * scaleLength; curFrame.Name = ReadString( reader, FrameNameLength ); } mesh.FrameInfoList = frames; }
/// <summary> /// Loads an MD3 mesh resource from a stream /// </summary> private static ModelMesh LoadMd3( ISource source, Model model, ModelPart part, Matrix44 transform, ISource md3Source, IDictionary<string, ITexture2d> surfaceTextureTable ) { using ( Stream inputStream = OpenStream( md3Source ) ) { BinaryReader reader = new BinaryReader( inputStream ); // http://icculus.org/homepages/phaethon/q3a/formats/md3format.html // Make sure of the MD3 identity byte[] ident = reader.ReadBytes( 4 ); if ( ( ident[ 0 ] != 'I' ) || ( ident[ 1 ] != 'D' ) || ( ident[ 2 ] != 'P' ) || ( ident[ 3 ] != '3' ) ) { throw new ApplicationException( "Failed to load MD3 resource - stream did not start with 'IDP3' MD3 identifier" ); } // Read in header //int version = reader.ReadInt32( ); //string name = ReadString( reader, MaxPathLength ); //int flags = reader.ReadInt32( ); int numFrames = reader.ReadInt32( ); int numTags = reader.ReadInt32( ); int numSurfaces = reader.ReadInt32( ); //int numSkins = reader.ReadInt32( ); int framesOffset = reader.ReadInt32( ); int tagsOffset = reader.ReadInt32( ); int surfacesOffset = reader.ReadInt32( ); //int eofOffset = reader.ReadInt32( ); // TODO: Can load directly into mesh frame, tag and surface structures - don't do this intermediate step ModelMesh mesh = new ModelMesh( model, part ); ReadFrames( reader, framesOffset, numFrames, mesh, transform ); ReadTags( reader, tagsOffset, numTags, numFrames, mesh, transform ); ReadSurfaces( source, reader, surfacesOffset, numSurfaces, numFrames, mesh, surfaceTextureTable, transform ); // TODO: REMOVE. test frames string md3Name = md3Source.ToString( ); if ( md3Name.IndexOf( "Upper" ) != -1 ) { mesh.DefaultFrame = 151; } else if ( md3Name.IndexOf( "Head" ) != -1 ) { mesh.DefaultFrame = 0; } else { mesh.DefaultFrame = 0; } return mesh; } }