/***************************************************************************/
/* */
/* File: main.cpp */
/* Author: bkenwright@xbdev.net */
/* URL: www.xbdev.net */
/* Date: 19-03-2006 (easter) */
/* */
/***************************************************************************/
/*
Understanding the Quake3 MD3 File Format
*/
//---------------------------------------------------------------------------
#define SZ_MD3_FILE "media\\model\\sarge\\upper.md3"
#define MAX_FILENAME_LENGTH 256
//---------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h> //sprintf(...)
//---------------------------------------------------------------------------
//Saving debug information to a log file
void abc(char *str)
{
FILE *fp = fopen("output.txt", "a+");
fprintf(fp, "%s\n", str);
fclose(fp);
}
//---------------------------------------------------------------------------
typedef unsigned int uint32;
typedef int int32;
typedef unsigned short int uint16;
typedef short int int16;
typedef float float32;
struct stMD3Header
{
char ID[4]; // ID of the file is always "IDP3"
int32 Version; // Version number, usually 15
char Filename[68]; // Filename, sometimes left blank
int32 numBoneFrames; // Number of BoneFrames
int32 numTags; // Number of 'tags' per BoneFrame
int32 numMeshes; // Number of Meshes/Skins in MaxSkin
int32 numMaxSkins; // Maximum number of unique skins
int32 ofsFrames; // Always equal to the length this header
int32 ofsTagStart; // Starting position of tag structures
int32 ofMeshSurfaces; // Ending position of tag structure
int32 ofEndOfFile; // Size of file
};
struct stBoneFrame
{
float32 mins[3];
float32 maxs[3];
float32 Position[3];
float32 Scale;
char Creator[16];
};
struct stAnim
{
int32 FirstFrame;
int32 numFrames;
int32 LoopingFrames;
int32 FPS;
};
struct stSkin
{
char Name[64];
int32 index;
};
struct stTag
{
char Name[64];
float32 Position[3];
float32 Rotation[3][3];
};
struct stTriangle
{
int32 Vertex[3];
};
struct stTexCoord
{
float32 Coord[2];
};
struct stVertex // = Record
{
int16 Vertex[3];
unsigned char Normal[2];
};
struct stMeshHeader
{
char ID[4];
char Name[64];
int32 flags;
int32 numMeshFrames;
int32 numSkins;
int32 numVertexes;
int32 numTriangles;
int32 ofsTriangles;
int32 ofsSkins;
int32 ofsTexVector;
int32 ofsVertex;
int32 ofsEndMeshSize;
};
struct stMesh
{
stMeshHeader MeshHeader;
stSkin* pSkins;
stTriangle* pTriangle;
stTexCoord* pTexCoord;
stVertex* pVertex;
};
//---------------------------------------------------------------------------
long filesize(FILE *stream)
{
long curpos, length;
curpos = ftell(stream);
fseek(stream, 0L, SEEK_END);
length = ftell(stream);
fseek(stream, curpos, SEEK_SET);
return length;
}
//---------------------------------------------------------------------------
class CMD3
{
public:
char m_md3FileName[MAX_FILENAME_LENGTH];
stMD3Header m_md3Header;
stBoneFrame* m_pBoneFrame;
stTag* m_pTags;
stMesh* m_pMeshes;
//-----------------------------------------------------------------------
//
// Loads model from a .md3 file
//
//-----------------------------------------------------------------------
bool LoadModel(const char* filename)
{
char buf[256];
FILE* fp = fopen(filename, "rb");
if (fp==NULL)
{
abc("unable to open file");
return false;
}
// Lets get the size of this md3 file
int md3filesize = filesize(fp);
fseek(fp, 0L, SEEK_SET);
if (strlen(filename)>255)
{
sprintf(buf, "filename is longer than %d", MAX_FILENAME_LENGTH);
abc(buf);
return false;
}
// copy name
strcpy(m_md3FileName, filename);
sprintf(buf, "MD3 FileName: %s", m_md3FileName);
abc(buf);
sprintf(buf, "FileSize: %d", md3filesize);
abc(buf);
abc("\n~~MD3 Header~~\n");
// read header
fread(&m_md3Header, 1, sizeof(stMD3Header), fp);
// log debug information to file
sprintf(buf, "ID %c%c%c%c", m_md3Header.ID[0], m_md3Header.ID[1], m_md3Header.ID[2], m_md3Header.ID[3]);
abc(buf);
sprintf(buf, "Version: %d", m_md3Header.Version);
abc(buf);
sprintf(buf, "FileName: %s", m_md3Header.Filename);
abc(buf);
sprintf(buf, "numBoneFrames: %d", m_md3Header.numBoneFrames);
abc(buf);
sprintf(buf, "numTags: %d", m_md3Header.numTags);
abc(buf);
sprintf(buf, "numMeshes: %d", m_md3Header.numMeshes);
abc(buf);
sprintf(buf, "numMaxSkins: %d", m_md3Header.numMaxSkins);
abc(buf);
sprintf(buf, "ofsFrames: %d", m_md3Header.ofsFrames);
abc(buf);
sprintf(buf, "ofsTagStart: %d", m_md3Header.ofsTagStart);
abc(buf);
sprintf(buf, "ofMeshSurfaces: %d", m_md3Header.ofMeshSurfaces);
abc(buf);
sprintf(buf, "ofEndOfFile (Filesize): %d", m_md3Header.ofEndOfFile);
abc(buf);
if (strcmp("IDP3", m_md3Header.ID)==NULL)
{
sprintf(buf, "Incorrect File Format 'Incorrect ID' ie. ('IDP3')");
abc(buf);
}
// Allocate memory for all or bones/tags/etc
m_pBoneFrame = new stBoneFrame[m_md3Header.numBoneFrames];
m_pTags = new stTag[m_md3Header.numBoneFrames * m_md3Header.numTags];
m_pMeshes = new stMesh[m_md3Header.numMeshes];
// Lets seek to the start of the bone frames & read boneframe
fseek(fp, m_md3Header.ofsFrames, SEEK_SET);
fread(m_pBoneFrame, 1, m_md3Header.numBoneFrames*sizeof(stBoneFrame), fp);
sprintf(buf, "\n~~~~BoneFrames: %d~~~~~~", m_md3Header.numBoneFrames);
abc(buf);
for (int i=0; i<m_md3Header.numBoneFrames; i++)
{
abc("#");
sprintf(buf, "mins[%.1f,%.1f,%.1f]", m_pBoneFrame[i].mins[0], m_pBoneFrame[i].mins[1], m_pBoneFrame[i].mins[2]);
abc(buf);
sprintf(buf, "maxs[%.1f,%.1f,%.1f]", m_pBoneFrame[i].maxs[0], m_pBoneFrame[i].maxs[1], m_pBoneFrame[i].maxs[2]);
abc(buf);
sprintf(buf, "Position[%.1f,%.1f,%.1f]", m_pBoneFrame[i].Position[0], m_pBoneFrame[i].Position[1], m_pBoneFrame[i].Position[2]);
abc(buf);
sprintf(buf, "Scale[%.1f]", m_pBoneFrame[i].Scale);
abc(buf);
sprintf(buf, "Creator[%s]", m_pBoneFrame[i].Creator);
abc(buf);
}
// Seek to start of tags and read them all in
fseek(fp, m_md3Header.ofsTagStart, SEEK_SET);
fread(m_pTags, 1, m_md3Header.numBoneFrames*m_md3Header.numTags*sizeof(stTag), fp);
sprintf(buf, "\n~~~~Tags: %d~~~~~~", m_md3Header.numTags);
abc(buf);
for (int i=0; i<m_md3Header.numTags; i++)
{
abc("#");
sprintf(buf, "Name[%s]", m_pTags[i].Name);
abc(buf);
sprintf(buf, "Position[%.1f,%.1f,%.1f]", m_pTags[i].Position[0], m_pTags[i].Position[1], m_pTags[i].Position[2]);
abc(buf);
sprintf(buf, "Rotation[%.1f,%.1f,%.1f][...][...]", m_pTags[i].Rotation[0][0], m_pTags[i].Rotation[0][1], m_pTags[i].Rotation[0][2]);
abc(buf);
}
//fseek(fp, m_md3Header.ofMeshSurfaces, SEEK_SET);
int meshOFS = m_md3Header.ofMeshSurfaces;
sprintf(buf, "\n~~~~Mesh Surfaces: %d~~~~~~", m_md3Header.numMeshes);
abc(buf);
for (int j=0; j<m_md3Header.numMeshes; j++)
{
abc("#");
stMesh * pMesh = &m_pMeshes[j];
stMeshHeader * pMeshHeader = &(pMesh->MeshHeader);
fseek(fp, meshOFS, SEEK_SET);
// Seek to the start of the mesh data and read it all in
fread(pMeshHeader, 1, sizeof(stMeshHeader), fp);
sprintf(buf, "ID [%c%c%c%c]", pMeshHeader->ID[0], pMeshHeader->ID[1], pMeshHeader->ID[2], pMeshHeader->ID[3]);
abc(buf);
sprintf(buf, "Name [%s]", pMeshHeader->Name);
abc(buf);
sprintf(buf, "flags [0x%.2X]", pMeshHeader->flags);
abc(buf);
sprintf(buf, "numMeshFrames [%d]", pMeshHeader->numMeshFrames);
abc(buf);
sprintf(buf, "numSkins [%d]", pMeshHeader->numSkins);
abc(buf);
sprintf(buf, "numVertexes [%d]", pMeshHeader->numVertexes);
abc(buf);
sprintf(buf, "numVertexes [%d]", pMeshHeader->numVertexes);
abc(buf);
sprintf(buf, "ofsTriangles [%d]", pMeshHeader->ofsTriangles);
abc(buf);
sprintf(buf, "ofsSkins [%d]", pMeshHeader->ofsSkins);
abc(buf);
sprintf(buf, "ofsTexVector [%d]", pMeshHeader->ofsTexVector);
abc(buf);
sprintf(buf, "ofsVertex [%d]", pMeshHeader->ofsVertex);
abc(buf);
sprintf(buf, "ofsEndMeshSize [%d]", pMeshHeader->ofsEndMeshSize);
abc(buf);
meshOFS += pMeshHeader->ofsEndMeshSize;
}//End for meshes
fclose(fp);
delete[] m_pBoneFrame;
delete[] m_pTags;
delete[] m_pMeshes;
m_pBoneFrame = NULL;
m_pTags = NULL;
m_pMeshes = NULL;
return true;
}// End LoadModel(..)
};
//---------------------------------------------------------------------------
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
static CMD3 md3;
md3.LoadModel(SZ_MD3_FILE);
// If something was not done, let it go
return 0;
}
//---------------------------------------------------------------------------
|