// // The graphics engine GLXEngine. The unit of GLScene for Delphi // unit Formats.MD3; (* File loading methods for the MD3 file format *) interface uses System.Classes, Stage.VectorTypes; type // Quake3 MD3 structure types TMD3Tag = record strName: array [0 .. 63] of AnsiChar; vPosition: TVector3f; rotation: TMatrix3f; end; (* This part of the MD3 structure called 2 things: A frame and a bone. It doesn't matter because we don't use it *) (* TMD3Frame = record min_bound,max_bounds, local_origin : TVector3f; radius : single; name : array[0..15] of char; end; *) TMD3Bone = record mins, maxs, position: TVector3f; scale: single; creator: array [0 .. 15] of AnsiChar; end; TMD3Triangle = record vertex: TVector3s; // value/64 to get real number position normal: TVector2b; // Latitude,Longitude end; TMD3Face = record vertexIndices: TVector3i; end; TMD3TexCoord = record textureCoord: TVector2f; end; TMD3Skin = record strName: array [0 .. 63] of AnsiChar; shaderIndex: Integer; end; TMD3Header = record fileID: array [0 .. 3] of AnsiChar; version: Integer; strFile: array [0 .. 63] of AnsiChar; flags, numFrames, numTags, numMeshes, numMaxSkins, headerSize, tagStart, tagEnd, fileSize: Integer; end; TMD3MeshHeader = record meshID: array [0 .. 3] of AnsiChar; strName: array [0 .. 63] of AnsiChar; flags, numMeshFrames, numSkins, numVertices, numTriangles, triStart, headerSize, uvStart, vertexStart, meshSize: Integer; end; TMD3MeshData = record MeshHeader: TMD3MeshHeader; Skins: array of TMD3Skin; Triangles: array of TMD3Face; TexCoords: array of TMD3TexCoord; Vertices: array of TMD3Triangle; end; // MD3 Main file class TFileMD3 = class public ModelHeader: TMD3Header; Bones: array of TMD3Bone; Tags: array of TMD3Tag; MeshData: array of TMD3MeshData; procedure LoadFromStream(aStream: TStream); end; implementation // ------------------------------------------------------------ // ------------------ // ------------------ TFileMD3 ------------------ // ------------------ procedure TFileMD3.LoadFromStream(aStream: TStream); var i: Integer; meshOffset: LongInt; begin aStream.Read(ModelHeader, sizeof(ModelHeader)); // Test for correct file ID and version Assert(ModelHeader.fileID = 'IDP3', 'Incorrect MD3 file ID'); Assert(ModelHeader.version = 15, 'Incorrect MD3 version number'); // Read in the bones SetLength(Bones, ModelHeader.numFrames); aStream.Read(Bones[0], sizeof(TMD3Bone) * ModelHeader.numFrames); // Read in the Tags SetLength(Tags, ModelHeader.numFrames * ModelHeader.numTags); if ModelHeader.numTags > 0 then aStream.Read(Tags[0], sizeof(TMD3Tag) * ModelHeader.numFrames * ModelHeader.numTags); // Read in the Mesh data meshOffset := aStream.position; SetLength(MeshData, ModelHeader.numMeshes); for i := 0 to ModelHeader.numMeshes - 1 do begin with MeshData[i] do begin aStream.position := meshOffset; aStream.Read(MeshHeader, sizeof(MeshHeader)); // Set up the dynamic arrays SetLength(Skins, MeshHeader.numSkins); SetLength(Triangles, MeshHeader.numTriangles); SetLength(TexCoords, MeshHeader.numVertices); SetLength(Vertices, MeshHeader.numVertices * MeshHeader.numMeshFrames); // Skins aStream.Read(Skins[0], sizeof(TMD3Skin) * MeshHeader.numSkins); // Face data aStream.position := meshOffset + MeshHeader.triStart; aStream.Read(Triangles[0], sizeof(TMD3Face) * MeshHeader.numTriangles); // Texture coordinates aStream.position := meshOffset + MeshHeader.uvStart; aStream.Read(TexCoords[0], sizeof(TMD3TexCoord) * MeshHeader.numVertices); // Vertices aStream.position := meshOffset + MeshHeader.vertexStart; aStream.Read(Vertices[0], sizeof(TMD3Triangle) * MeshHeader.numMeshFrames * MeshHeader.numVertices); // Increase the offset meshOffset := meshOffset + MeshHeader.meshSize; end; end; end; // ------------------------------------------------------------------ end.