This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

 

  MD2 Model Loader
  Submitted by



Well i thought it might be useful for some people so i wrote it in my spare time (after office). Currently all you have to do is simply call

md2Model obj;

obj.Load("path//tris.md2"); obj.Draw();

// and in case you want to change to a particular frame simply do obj.SetFrame(3); // base zero.



I didn't had the time to put together the Texture mapping section but i think it can be done easily. It's a preety messed up code but i think you guyz can get throught it. Thanks for all flipcodian.. :)
Any comments are welcome on <saad_faisal@c4.com>

Currently browsing [md2Loader.zip] (3,447 bytes) - [md2Model.h] - (2,423 bytes)

#ifndef __MD2_MODEL_H__
#define __MD2_MODEL_H__

#define MD2_MAGIC_NO ('I'+('D'<<8)+('P'<<16)+('2'<<24))

#define MAX_NO_SKIN 5 #define MAX_SKIN_NAME 64

#define FRAME_HEADER_SIZE (sizeof(float)*6+16)

typedef unsigned char byte; typedef short* pshort;

typedef struct _md2Header { int magic; int version; int skinWidth; int skinHeight; int frameSize;

int numSkins; int numVertices; int numTexCoords; int numTriangles; int numGlCommands; int numFrames;

int offsetSkins; int offsetTexCoord; int offsetTriangles; int offsetFrames; int offsetGlCommands; int offsetEnd; }md2Header,*pmd2Header;

typedef struct _md2TriangleVertex { byte vertex[3]; byte lightNormalIndex; }md2TriangleVertex,*pmd2TriangleVertex;

typedef struct _md2Frame { float scale[3]; float translate[3]; char name[16]; pmd2TriangleVertex pvertices; }md2Frame,*pmd2Frame;

typedef struct _md2Triangle { short vertexIndices[3]; short textureIndices[3]; }md2Triangle,*pmd2Triangle;

typedef struct _md2TextureCoord { short s,t; }md2TextureCoord,*pmd2TextureCoord;

typedef struct _md2GLCommand { float s,t; int vertexIndex; }md2GLCommand,*pmd2GLCommand;

typedef struct _md2GLVertex { float x,y,z; }md2GLVertex,*pmd2GLVertex;

class md2Model { public: md2Model(); ~md2Model();

int Load(const char* fileName); int GetNumFrames(); void Draw(); void SetFrame(int frame); // base zero

private: void* md2Malloc(size_t size); void md2Free(void** p); int md2ReadFile(const char* fileName); int md2ReadHeader(byte *buffer,pmd2Header phead); long md2FileSize(FILE *fp); void md2DumpHeader(const pmd2Header phead);

void md2InitData(); void md2LoadData(); void md2LoadSkinNames(); void md2LoadTextureCoord(); void md2LoadFrames(); void md2LoadTriangles(); void md2LoadGLCommands(); void md2LoadTextures(const char* md2FileName); void md2ProcessData(); void md2WriteLog(const char* fileName);

private: byte* m_buffer; md2Header m_header; char m_skinName[MAX_NO_SKIN][MAX_SKIN_NAME]; pmd2TextureCoord m_texData; pmd2Triangle m_triData; pmd2TriangleVertex m_vertData; pmd2Frame m_frameData;

pmd2GLVertex m_glVertexData; pshort m_glIndicesData;

unsigned int m_listID; };

#endif //__MD2_MODEL_H__

Currently browsing [md2Loader.zip] (3,447 bytes) - [md2Model.cpp] - (10,095 bytes)

#include "md2Model.h"

md2Model::md2Model() { m_buffer =NULL; m_texData =NULL; m_triData =NULL; m_vertData =NULL; m_frameData =NULL; m_glVertexData=NULL; m_glIndicesData=NULL; }

md2Model::~md2Model() { md2Free((void**)&m_buffer); md2Free((void**)&m_texData); md2Free((void**)&m_triData); md2Free((void**)&m_vertData); md2Free((void**)&m_glVertexData); md2Free((void**)&m_glIndicesData); for (int index=0;index<m_header.numFrames;index++) md2Free((void**)&m_frameData[index].pvertices); md2Free((void**)&m_frameData); }

/* Name : Load */ int md2Model::Load(const char* fileName) { int result=0;

result=md2ReadFile(fileName); if (result!=0) return result;

result=md2ReadHeader(m_buffer,&m_header); if (result!=0) return result; md2InitData(); md2LoadData(); md2ProcessData(); md2WriteLog(fileName); SetFrame(0); // Initially set it to Point to First Frame return 0; }

/* Name : md2Malloc */ void* md2Model::md2Malloc(size_t size) { void* p=malloc(size); if (p==NULL) return p; memset(p,0,size);

return p; }

/* Name : md2Free */ void md2Model::md2Free(void** p) { if (*p!=NULL) { free(*p); *p=NULL; } }

/* Name : md2ReadFile */ int md2Model::md2ReadFile(const char* fileName) { FILE *fp;

fp=fopen(fileName,"rb"); if (!fp) return 1;

md2Free((void**)&m_buffer);

long fileSize= md2FileSize(fp); if (fileSize<=0) return 1;

m_buffer=(byte*)md2Malloc(fileSize); if (!m_buffer) return 1;

if (fread(m_buffer,1,fileSize,fp)!=(size_t)fileSize) return 1;

fclose(fp); return 0; }

/* Name : md2FileSize */ long md2Model::md2FileSize(FILE *fp) { long oldpos=ftell(fp); fseek(fp,0,SEEK_END); long curpos=ftell(fp); fseek(fp,oldpos,SEEK_SET); return curpos; }



/* Name : md2ReadHeader */ int md2Model::md2ReadHeader(byte *buffer,pmd2Header phead) { memcpy(phead,buffer,sizeof(*phead));

if (phead->magic != MD2_MAGIC_NO) return 1;

return 0; }

/* Name : md2InitData */ void md2Model::md2InitData() { int index=0;

for (index=0;index<MAX_NO_SKIN;index++) memset(this->m_skinName[index],0,MAX_SKIN_NAME);

md2Free((void**)&m_texData); md2Free((void**)&m_triData); md2Free((void**)&m_vertData); md2Free((void**)&m_frameData); if (m_frameData!=NULL) { for (int index=0;index<m_header.numFrames;index++) md2Free((void**)&m_frameData[index].pvertices); md2Free((void**)&m_frameData); } }

/* Name : md2LoadData */ void md2Model::md2LoadData() { md2LoadSkinNames(); md2LoadTextureCoord(); md2LoadTriangles(); md2LoadFrames(); md2LoadGLCommands(); }

/* Name : md2LoadFrames */ void md2Model::md2LoadFrames() { int index=0; byte *buf_t = m_buffer+ m_header.offsetFrames; long frameHeaderSize = m_header.numFrames * sizeof(md2Frame); long frameVertSize = m_header.numVertices * sizeof(md2TriangleVertex);

m_frameData =(pmd2Frame)md2Malloc(frameHeaderSize); if (!m_frameData) return;

for (index=0;index< m_header.numFrames;index++) { m_frameData[index].pvertices = (pmd2TriangleVertex)md2Malloc(frameVertSize); if (!m_frameData[index].pvertices) return; }

for (index=0;index< m_header.numFrames;index++) { memcpy(&m_frameData[index],buf_t, FRAME_HEADER_SIZE); buf_t+= FRAME_HEADER_SIZE; memcpy(m_frameData[index].pvertices, buf_t, frameVertSize); buf_t+=frameVertSize; } }

/* Name : md2LoadTriangles */ void md2Model::md2LoadTriangles() { byte *buf_t = m_buffer+ m_header.offsetTriangles; long totalsize = m_header.numTriangles * sizeof(md2Triangle);

m_triData = (pmd2Triangle)md2Malloc(totalsize); if (!m_triData) return;

memcpy(m_triData, buf_t, totalsize); }

/* Name : md2LoadTextureCoord */ void md2Model::md2LoadTextureCoord() { int index=0; byte *buf_t=m_buffer+m_header.offsetTexCoord; long totalsize = m_header.numTexCoords*sizeof(md2TextureCoord);

m_texData=(pmd2TextureCoord)md2Malloc(totalsize); if (!m_texData) return;

memcpy(m_texData,buf_t,totalsize); }

/* Name : md2LoadSkinNames */ void md2Model::md2LoadSkinNames() { int index=0; byte* buf_t=m_buffer+m_header.offsetSkins;

for (index=0;index<m_header.numSkins;index++,buf_t+=MAX_SKIN_NAME) strcpy(m_skinName[index],(const char*)buf_t); }

/* Name : md2LoadGLCommands */ void md2Model::md2LoadGLCommands() { return; }

/* Name : md2ProcessData */ void md2Model::md2ProcessData() { md2Free((void**)&m_glVertexData); m_glVertexData = (pmd2GLVertex) md2Malloc(m_header.numVertices*sizeof(md2GLVertex)); if (!m_glVertexData) { printf("Error at md2ProcessData\n"); return; } }

void md2Model::SetFrame(int frame) { if (frame<0 || frame>= m_header.numFrames) return;

int index=0; if (m_glVertexData!=NULL) { memset(m_glVertexData,0,sizeof(md2GLVertex)*m_header.numVertices);

for (index=0;index<m_header.numVertices;index++) { // Every vertex of frame is multiplied by it's respective scale and then the translation is added. m_glVertexData[index].x = (m_frameData[frame].pvertices[index].vertex[0] * m_frameData[frame].scale[0])+m_frameData[frame].translate[0]; m_glVertexData[index].y = (m_frameData[frame].pvertices[index].vertex[1] * m_frameData[frame].scale[1])+m_frameData[frame].translate[1]; m_glVertexData[index].z = (m_frameData[frame].pvertices[index].vertex[2] * m_frameData[frame].scale[2])+m_frameData[frame].translate[2]; } } }

/* Name : md2WriteLog */ void md2Model::md2WriteLog(const char* fileName) { char data[512]={0}; char logfname[255]={0}; FILE *fp; int index=0; pmd2Header phead= &m_header;

strcpy(logfname,fileName); strcpy(logfname+strlen(fileName)-3,"log");

fp=fopen(logfname,"w"); if (!fp) return;

sprintf(data,"File Name : %s\n", fileName);fwrite(data,strlen(data),1,fp); sprintf(data,"magic : %c%c%c%c\n", (phead->magic&0xFF),((phead->magic>>8)&0xFF),((phead->magic>>16)&0xFF),((phead->magic>>24)&0xFF));fwrite(data,strlen(data),1,fp); sprintf(data,"version : %d\n", phead->version);fwrite(data,strlen(data),1,fp); sprintf(data,"skinWidth : %d\n", phead->skinWidth);fwrite(data,strlen(data),1,fp); sprintf(data,"skinHeight : %d\n", phead->skinHeight);fwrite(data,strlen(data),1,fp); sprintf(data,"frameSize : %d\n", phead->frameSize);fwrite(data,strlen(data),1,fp); sprintf(data,"numSkins : %d\n", phead->numSkins);fwrite(data,strlen(data),1,fp); sprintf(data,"numVertices : %d\n", phead->numVertices);fwrite(data,strlen(data),1,fp); sprintf(data,"numTexCoords : %d\n", phead->numTexCoords);fwrite(data,strlen(data),1,fp); sprintf(data,"numTriangles : %d\n", phead->numTriangles);fwrite(data,strlen(data),1,fp); sprintf(data,"numGlCommands : %d\n", phead->numGlCommands);fwrite(data,strlen(data),1,fp); sprintf(data,"numFrames : %d\n", phead->numFrames);fwrite(data,strlen(data),1,fp); sprintf(data,"---------------------\n");fwrite(data,strlen(data),1,fp); sprintf(data,"offsetSkins : %d\n", phead->offsetSkins);fwrite(data,strlen(data),1,fp); sprintf(data,"offsetTexCoord : %d\n", phead->offsetTexCoord);fwrite(data,strlen(data),1,fp); sprintf(data,"offsetTriangles : %d\n", phead->offsetTriangles);fwrite(data,strlen(data),1,fp); sprintf(data,"offsetFrames : %d\n", phead->offsetFrames);fwrite(data,strlen(data),1,fp); sprintf(data,"offsetGlCommands: %d\n", phead->offsetGlCommands);fwrite(data,strlen(data),1,fp); sprintf(data,"offsetEnd : %d\n", phead->offsetEnd);fwrite(data,strlen(data),1,fp);

sprintf(data,"Total Frames : %.3d\n----------------------\n", m_header.numFrames);fwrite(data,strlen(data),1,fp); for (index=0;index< m_header.numFrames;index++) { sprintf(data, "[%3d] %s\n", (index+1), m_frameData[index].name); fwrite(data,strlen(data),1,fp); }

fclose(fp); }

/* Name : GetNumFrames */ int md2Model::GetNumFrames() { return this->m_header.numFrames; }

/* Name : Draw() // frame : is base zero index */ void md2Model::Draw() { GLfloat v1[3],v2[3],v3[3];

/* glCallList(m_listID);

GLenum ret=glGetError(); if (ret!=GL_NO_ERROR) printf("An error has occured\n"); */
int index=0; glBegin(GL_TRIANGLES); for (index=0;index< m_header.numTriangles;index++) { // Calculate the two vertex out of 3 by [v1 - v2] & [v2 - v3] (Read Bernard Koleman Elementary Linear Algebra P-193) v1[0] = m_glVertexData[m_triData[index].vertexIndices[2]].x - m_glVertexData[m_triData[index].vertexIndices[1]].x; v1[1] = m_glVertexData[m_triData[index].vertexIndices[2]].y - m_glVertexData[m_triData[index].vertexIndices[1]].y; v1[2] = m_glVertexData[m_triData[index].vertexIndices[2]].z - m_glVertexData[m_triData[index].vertexIndices[1]].z;

v2[0] = m_glVertexData[m_triData[index].vertexIndices[1]].x - m_glVertexData[m_triData[index].vertexIndices[0]].x; v2[1] = m_glVertexData[m_triData[index].vertexIndices[1]].y - m_glVertexData[m_triData[index].vertexIndices[0]].y; v2[2] = m_glVertexData[m_triData[index].vertexIndices[1]].z - m_glVertexData[m_triData[index].vertexIndices[0]].z;

// Take the Cross Product of v1 x v2 v3[0] = v1[1]*v2[2] - v1[2]*v2[1]; v3[1] = v1[2]*v2[0] - v1[0]*v2[2]; v3[2] = v1[0]*v2[1] - v1[1]*v2[0]; // glNormal3fv(v3); glVertex3f( m_glVertexData[m_triData[index].vertexIndices[2]].x, m_glVertexData[m_triData[index].vertexIndices[2]].y, m_glVertexData[m_triData[index].vertexIndices[2]].z); glVertex3f( m_glVertexData[m_triData[index].vertexIndices[1]].x, m_glVertexData[m_triData[index].vertexIndices[1]].y, m_glVertexData[m_triData[index].vertexIndices[1]].z); glVertex3f( m_glVertexData[m_triData[index].vertexIndices[0]].x, m_glVertexData[m_triData[index].vertexIndices[0]].y, m_glVertexData[m_triData[index].vertexIndices[0]].z); } glEnd(); }


The zip file viewer built into the Developer Toolbox made use of the zlib library, as well as the zlibdll source additions.

 

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.