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.