• Advertisement
Sign in to follow this  

Regarding a MD3 loader

This topic is 4146 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey, i am trying to write a md3 loader, i found the file spec in one of the threads in this forum, and have been following it ( http://www.icculus.org/homepages/phaethon/q3/formats/md3format.html ) (under the shader part ) S32 NUM_FRAMES Number of animation frames. This should match NUM_FRAMES in the MD3 header. But when i loade a file, it dosnt match at all.. (one file has 30 frames in md3 header, and 200 frames under md3->surface). does anyone here have experience with this fileformat.. is theresomething wrong with my loader, or could it be that there are diffrent frames between, even though the specs tells it should match? I find it logic that the diffrent surfaces/objects have separate frames from the main scene.. but i dont know too much about the md3 format, and are just following the spec (which i find rather good) :) So some enlightment would have been good :) thanks :) rgs Egil

Share this post

Link to post
Share on other sites
For the MD3 loader I wrote, I didn't bother checking the number of frames in the entire model, I just used the number of frames in each mesh, but the number of frames in the model always matched the number of frames in the meshes in the models I tested.

The problem could be with you either reading too much or too little data, since a few random bytes here and there can give you some fairly odd results. Check your code, since I've often come across things I've missed/over-looked which have screwed me over.

In the worst case scenario, you can always use my code below (I wouldn't post it, but I don't play in the forums much these days). Beyond loading and rendering the model (with animation), I haven't done anything, so if you need more information on getting it all working properly, you'll have to ask somebody else. By the way, I'm well aware of the not-so-portable types, but nobody else was really meant to be playing with this code, and I only wrote it for something to do in my spare time.


#ifndef _MD3LOADER_H
#define _MD3LOADER_H

#ifdef __cplusplus
extern "C" {

const unsigned int MD3_HEADER_ID = 0x33504449;
const unsigned int MD3_MODEL_VERSION = 15;
const unsigned int MD3_MESH_ID = 0x33504449;

typedef struct {
unsigned int id; //id of file, always "IDP3"
unsigned int version; //version, always 15
char filename[68]; //sometimes left blank

unsigned int numFrames; //number of frames
unsigned int numTags; //number of tags per frame
unsigned int numMeshes; //number of meshes

unsigned int numSkins; //number of skins

unsigned int frameStart; //the length of this header
unsigned int tagStart; //starting position of tag structures
unsigned int meshStart; //starting position of mesh structures

unsigned int dataLength; //the total length of the data used for this model

typedef struct {
char name[64]; //name of tag
float postition[3]; //relative position of tag
float rotation[3][3]; //the direction the tag is facing relative to the rest of the model

typedef struct {
float bounds[2][3];//min + max
float position[3];//local origin
float radius;
char name[16];

typedef struct {
unsigned int id; //id, always "IDP3"
char name[68]; //name of mesh

unsigned int numFrames; //number of frames in mesh
unsigned int numSkins; //number of skins in mesh
unsigned int numVertices; //number of vertices
unsigned int numTriangles; //number of Triangles

unsigned int triangleStart; //pos. of tri. data, relative to start of the mesh header
unsigned int skinStart; //pos. of skin data, relative to the start of the mesh header
unsigned int tcoordStart; //pos. of tex coord data, relative to start of the mesh header
unsigned int vertexStart; //pos. of vertex data, relative to start of the mesh header

unsigned int meshSize; //size of this mesh

typedef struct {
char name[68]; //name of skin used by mesh

typedef struct {
unsigned int indices[3];

typedef struct {
float uv[2];

typedef struct {
short position[3];
unsigned char envMapCoords[2];

//added structure to help keep the format clean
typedef struct {
MD3MeshHeader* header;
MD3Skin* skins;
MD3Triangle* triangles;
MD3TCoord* tcoords;
MD3Vertex* vertices;

typedef struct {
MD3Header* header;
MD3Frame* frames;
MD3Tag* tags;
MD3MeshData* meshes;
//the entire file's data is held in the 'data' pointer
void* data;

//returns 1 on success, 0 otherwise
//NOTE: any model data currently in the model is not released
extern int readMD3ModelDataInto(const char* filename,MD3Model* model);

//allocates memory for the model using malloc(), returning 0 if failed
extern MD3Model* readMD3Model(const char* filename);

//releases memory allocated in the model, but wont free the model itself
extern void releaseMD3ModelData(MD3Model* model);

#ifdef __cplusplus



#include "MD3Loader.h"

#ifdef __cplusplus
extern "C" {

#include <stdio.h>
#include <string.h>

int readMD3ModelDataInto(const char* filename,MD3Model* model){
if (!(filename && model)) return 0;
FILE* file = fopen(filename,"rb");
if (!file) return 0;


#define quit(){ releaseMD3ModelData(model); fclose(file); return 0; }

MD3Header tempHeader;
//read the header, check the id and model version
if (!fread(&tempHeader,sizeof(MD3Header),1,file)) quit();
if (
(tempHeader.id != MD3_HEADER_ID) ||
(tempHeader.version != MD3_MODEL_VERSION)
) quit();

if (tempHeader.dataLength <= sizeof(MD3Header)){
tempHeader.dataLength = ftell(file);

//seek back to the start

//allocate the model's memory
if (!(
(model->data = malloc(tempHeader.dataLength)) &&
(model->meshes = (MD3MeshData*)malloc(
tempHeader.numMeshes * sizeof(MD3MeshData)
)) quit();

//read the model's data
if (!fread(model->data,tempHeader.dataLength,1,file)) quit();

//set the pointers
model->header = (MD3Header*)model->data;
model->frames = (MD3Frame*)(((unsigned int)model->data) + model->header->frameStart);
model->tags = (MD3Tag*)(((unsigned int)model->data) + model->header->tagStart);

int i;
for (i = 0;i < model->header->numMeshes;i++){
if (i == 0){
model->meshes.header = (MD3MeshHeader*)(
((unsigned int)model->data) + model->header->meshStart
model->meshes.header = (MD3MeshHeader*)(
((unsigned int)model->meshes[i-1].header) + model->meshes[i-1].header->meshSize

//check mesh ID
if (model->meshes.header->id != MD3_MESH_ID) quit();

model->meshes.skins = (MD3Skin*)(
((unsigned int)model->meshes.header) + model->meshes.header->skinStart
model->meshes.triangles = (MD3Triangle*)(
((unsigned int)model->meshes.header) + model->meshes.header->triangleStart
model->meshes.tcoords = (MD3TCoord*)(
((unsigned int)model->meshes.header) + model->meshes.header->tcoordStart
model->meshes.vertices = (MD3Vertex*)(
((unsigned int)model->meshes.header) + model->meshes.header->vertexStart

#undef quit
return 1;

MD3Model* readMD3Model(const char* filename){
MD3Model* model = (MD3Model*)malloc(sizeof(MD3Model));
if (!readMD3ModelDataInto(filename,model)){
model = 0;
return model;

void releaseMD3ModelData(MD3Model* model){
if (model->data) free(model->data);
if (model->meshes) free(model->meshes);

#ifdef __cplusplus

Base code for loading MD3 models using my code:

MD3Model model;
const char* modelToLoad = "something_to_load.md3";
if (!(readMD3ModelDataInto(modelToLoad,&model)))
//it loaded, so you can do stuff here
//clean up

Share this post

Link to post
Share on other sites
i found it a bit cluttering to use your code, since i am coding in c++.. but anyway.. you made me go through the code and specs once more.. and i actually found my problem :P.

I created up an array for the surface, but i was including the header for the surface aswell, for each surface.. which it totaly wrong :). i just miss-read the specs :P

thanks for answering!


Share this post

Link to post
Share on other sites
Sign in to follow this  

  • Advertisement