www.pudn.com > md2Class.rar > MD2.cpp


/*  *  Texture.cpp  *  MD2 File Loading  *  *  Created by Seth Willits on 9/11/04.  *  Copyright 2004 Freak Software. All rights reserved.  *  *  Portions of this file are from the MD2 file loading routines  *  found in Chapter 18 of OpenGL Game Programming by Kevin Hawkins  *  and Dave Astle.   *  This includes the vector operations, SetupSkin, CalculateNormal,  *  and the Draw function.  */   #include "MD2.h"     // vector subtraction MD2Vector operator-(MD2Vector a, MD2Vector b) { 	MD2Vector c;  	c.point[0] = a.point[0] - b.point[0]; 	c.point[1] = a.point[1] - b.point[1]; 	c.point[2] = a.point[2] - b.point[2];  	return c; }  // scalar-vector multiplication MD2Vector operator*(float f, MD2Vector b) { 	MD2Vector c;  	c.point[0] = f * b.point[0]; 	c.point[1] = f * b.point[1]; 	c.point[2] = f * b.point[2];  	return c; }  // vector division MD2Vector operator/(MD2Vector a, MD2Vector b) { 	MD2Vector c;  	c.point[0] = a.point[0] / b.point[0]; 	c.point[1] = a.point[1] / b.point[1]; 	c.point[2] = a.point[2] / b.point[2];  	return c; }   // vector addition MD2Vector operator+(MD2Vector a, MD2Vector b) { 	MD2Vector c;  	c.point[0] = a.point[0] + b.point[0]; 	c.point[1] = a.point[1] + b.point[1]; 	c.point[2] = a.point[2] + b.point[2];  	return c; }   // MD2Model constructor MD2Model::MD2Model() { 	NumVertices = 0;		// vertices 	NumTriangles = 0;		// triangles 	NumFrames = 0;			// frames 	NumTexCoords = 0;		// texture coordinates 	FrameSize = 0;			// needed? 	TrianglesIndex = NULL;   // triangle indices 	TextureCoords = NULL;	// texture coordinate indices 	VertexList = NULL;		// vertices 	ModelTex = NULL;		// skin/texture }      // MD2Model destructor MD2Model::~MD2Model() { 	if (TrianglesIndex != NULL) free(TrianglesIndex); 	if (VertexList != NULL) free(VertexList); 	if (TextureCoords != NULL) free(TextureCoords); }  // MD2Model::SetupSkin() // access: private // desc: sets up the model skin/texture for OpenGL void MD2Model::SetupSkin(MD2Texture *thisTexture) { 	// set the proper parameters for an MD2 texture 	glGenTextures(1, (GLuint*) &(thisTexture->texID)); 	glBindTexture(GL_TEXTURE_2D, thisTexture->texID); 	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP); 	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP); 	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); 	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); 	 	switch (thisTexture->textureType) 	{ 		case PCX: 			gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, thisTexture->width, thisTexture->height, GL_RGBA, GL_UNSIGNED_BYTE, thisTexture->data); 		default: 			break; 	} }   short MD2Model::ReadShort(FILE *filePtr) { 	short value = 0; 	fread(&value, sizeof(short), 1, filePtr); 	 	#if MD2_BYTEORDER == MD2_BIG_ENDIAN 		value = MD2SwapShort(value); 	#endif 	 	return value; }   int MD2Model::ReadInt(FILE *filePtr) { 	int value = 0; 	fread(&value, sizeof(int), 1, filePtr); 	 	#if MD2_BYTEORDER == MD2_BIG_ENDIAN 		value = MD2SwapInt(value); 	#endif 	 	return value; }   float MD2Model::ReadFloat(FILE *filePtr) { 	float value = 0; 	fread(&value, sizeof(float), 1, filePtr); 	 	#if MD2_BYTEORDER == MD2_BIG_ENDIAN 		value = MD2SwapFloat(value); 	#endif 	 	return value; }   void MD2Model::ReadHeader(FILE *filePtr, MD2ModelHeader & header) { 	// Go to Beginning of File 	fseek(filePtr, 0, SEEK_SET); 	 	// Read Header 	header.ident = ReadInt(filePtr); 	header.version = ReadInt(filePtr); 	header.skinwidth = ReadInt(filePtr); 	header.skinheight = ReadInt(filePtr); 	header.framesize = ReadInt(filePtr); 	header.NumSkins = ReadInt(filePtr); 	header.NumVertices = ReadInt(filePtr); 	header.NumTexCoords = ReadInt(filePtr); 	header.NumTriangles = ReadInt(filePtr); 	header.NumGLCmds = ReadInt(filePtr); 	header.NumFrames = ReadInt(filePtr); 	header.offsetSkins = ReadInt(filePtr); 	header.offsetST = ReadInt(filePtr); 	header.offsetTriangles = ReadInt(filePtr); 	header.offsetFrames = ReadInt(filePtr); 	header.offsetGLCmds = ReadInt(filePtr); 	header.offsetEndOfFile = ReadInt(filePtr); }   // MD2Model::Load() // access: public // desc: loads model and skin bool MD2Model::Load(char *modelFile, char *skinFile) { 	FILE *filePtr; 				// file pointer 	int fileLength;				// length of model file 	MD2ModelHeader header;		// model header 	MD2Frame frame;				// frame data 	MD2Vector * vectors;		//  	int i, j;					// index variables 	 	 	// Open the Model File 	filePtr = fopen(modelFile, "rb"); 	if (filePtr == NULL) 		return false; 	 	 	// Find Length of File 	fseek(filePtr, 0, SEEK_END); 	fileLength = ftell(filePtr); 	 	 	// Extract model file header from buffer 	ReadHeader(filePtr, header); 	 	 	// Save Some Header Information 	NumVertices = header.NumVertices; 	NumFrames = header.NumFrames; 	FrameSize = header.framesize; 	NumTexCoords = header.NumTexCoords; 	NumTriangles = header.NumTriangles; 	 	 	// Create Vertex List 	VertexList = new MD2Vector [NumVertices * NumFrames]; 	 	// For Each Frame 	frame.fp = NULL; 	for (j = 0; j < NumFrames; j++) { 		 		// Move to Frame in File 		fseek(filePtr, header.offsetFrames + FrameSize * j, SEEK_SET); 		 		// Read Frame 		// framePtr = (MD2Frame*) &(buffer[header.offsetFrames + FrameSize * j]); 		frame.scale[0] = ReadFloat(filePtr); 		frame.scale[1] = ReadFloat(filePtr); 		frame.scale[2] = ReadFloat(filePtr); 		frame.translate[0] = ReadFloat(filePtr); 		frame.translate[1] = ReadFloat(filePtr); 		frame.translate[2] = ReadFloat(filePtr); 		fread(&frame.name, sizeof(char), 16, filePtr); 		if (frame.fp != NULL) free(frame.fp); 		frame.fp = (MD2FramePoint *) calloc(NumVertices, sizeof(MD2FramePoint)); 		fread(frame.fp, sizeof(MD2FramePoint), NumVertices, filePtr); 		 		 		// Save the Vertices 		vectors = (MD2Vector*) &VertexList[NumVertices * j]; 		for (i = 0; i < NumVertices; i++) { 			 			VertexList[NumVertices * j + i].point[0] = frame.scale[0] * frame.fp[i].v[0] + frame.translate[0]; 			VertexList[NumVertices * j + i].point[1] = frame.scale[1] * frame.fp[i].v[1] + frame.translate[1]; 			VertexList[NumVertices * j + i].point[2] = frame.scale[2] * frame.fp[i].v[2] + frame.translate[2]; 		} 	} 	 	 	// Textures 	ModelTex = LoadTexture(skinFile); 	if (ModelTex != NULL) 		SetupSkin(ModelTex); 	else 		return false; 	 	 	// Create Texture Coords 	TextureCoords = new MD2TextureCoord [NumTexCoords]; 		 	// Move to Texture Coordinates in File 	fseek(filePtr, header.offsetST, SEEK_SET); 	 	// Read in Texture Coordinate List 	for (i = 0; i < NumTexCoords; i++) { 		TextureCoords[i].s = (float)ReadShort(filePtr) / (float)ModelTex->width; 		TextureCoords[i].t = (float)ReadShort(filePtr) / (float)ModelTex->height; 	} 	 	 	 	 	// Triangles 	TrianglesIndex = new MD2Mesh [NumFrames * NumTriangles]; 	 	// Move to Triangles in File 	// bufIndexPtr = (MD2Mesh*)&buffer[header.offsetTriangles]; 	fseek(filePtr, header.offsetTriangles, SEEK_SET); 	 	// Create a Mesh (triangle) List 	for (i = 0; i < NumTriangles; i++) { 		TrianglesIndex[i].meshIndex[0] = ReadShort(filePtr); 		TrianglesIndex[i].meshIndex[1] = ReadShort(filePtr); 		TrianglesIndex[i].meshIndex[2] = ReadShort(filePtr); 		TrianglesIndex[i].stIndex[0] = ReadShort(filePtr); 		TrianglesIndex[i].stIndex[1] = ReadShort(filePtr); 		TrianglesIndex[i].stIndex[2] = ReadShort(filePtr); 	} 	 	 	// Close File and Free Memory 	fclose(filePtr); 	 	 	// File Successfuly Loaded 	return true; }     /////////////////////////////////////////////////////////////////////////// //	CalculateNormal - given 3 points, calculates the normal to the points //	 ///////////////////////////////////////////////////////////////////////////  void MD2Model::CalculateNormal( float *p1, float *p2, float *p3 ) {    float a[3], b[3], result[3];    float length;     a[0] = p1[0] - p2[0];    a[1] = p1[1] - p2[1];    a[2] = p1[2] - p2[2];     b[0] = p1[0] - p3[0];    b[1] = p1[1] - p3[1];    b[2] = p1[2] - p3[2];     result[0] = a[1] * b[2] - b[1] * a[2];    result[1] = b[0] * a[2] - a[0] * b[2];    result[2] = a[0] * b[1] - b[0] * a[1];     // calculate the length of the normal    length = (float)sqrt(result[0]*result[0] + result[1]*result[1] + result[2]*result[2]);     // normalize and specify the normal    glNormal3f(result[0]/length, result[1]/length, result[2]/length); }   // MD2Model::Draw() // access: public // desc: animates the model between the keyframes startFrame and endFrame void MD2Model::Draw(int CurrentFrame, int NextFrame, float Interpolation) { 	MD2Vector *vList;    		// current frame vertices 	MD2Vector *nextVList;		// next frame vertices 	int i;    					// index counter 	float x1, y1, z1;   		// current frame point values 	float x2, y2, z2;			// next frame point values 	MD2Vector vertex[3];  	 	 	 	// Get Vertex list at offset for the current frame 	vList = &VertexList[NumVertices*CurrentFrame]; 	 	// Get vertex list at offset for the next frame 	nextVList = &VertexList[NumVertices*NextFrame]; 	 	// Pick our texture 	glBindTexture(GL_TEXTURE_2D, ModelTex->texID); 	 	 	// Draw the Model 	glBegin(GL_TRIANGLES); 	for (i = 0; i < NumTriangles; i++) { 		 		// get first points of each frame 		x1 = vList[TrianglesIndex[i].meshIndex[0]].point[0]; 		y1 = vList[TrianglesIndex[i].meshIndex[0]].point[1]; 		z1 = vList[TrianglesIndex[i].meshIndex[0]].point[2]; 		x2 = nextVList[TrianglesIndex[i].meshIndex[0]].point[0]; 		y2 = nextVList[TrianglesIndex[i].meshIndex[0]].point[1]; 		z2 = nextVList[TrianglesIndex[i].meshIndex[0]].point[2]; 		 		// store first interpolated vertex of triangle 		vertex[0].point[0] = x1 + Interpolation * (x2 - x1); 		vertex[0].point[1] = y1 + Interpolation * (y2 - y1); 		vertex[0].point[2] = z1 + Interpolation * (z2 - z1); 		 		// get second points of each frame 		x1 = vList[TrianglesIndex[i].meshIndex[2]].point[0]; 		y1 = vList[TrianglesIndex[i].meshIndex[2]].point[1]; 		z1 = vList[TrianglesIndex[i].meshIndex[2]].point[2]; 		x2 = nextVList[TrianglesIndex[i].meshIndex[2]].point[0]; 		y2 = nextVList[TrianglesIndex[i].meshIndex[2]].point[1]; 		z2 = nextVList[TrianglesIndex[i].meshIndex[2]].point[2]; 		 		// store second interpolated vertex of triangle 		vertex[2].point[0] = x1 + Interpolation * (x2 - x1); 		vertex[2].point[1] = y1 + Interpolation * (y2 - y1); 		vertex[2].point[2] = z1 + Interpolation * (z2 - z1);    		 		// get third points of each frame 		x1 = vList[TrianglesIndex[i].meshIndex[1]].point[0]; 		y1 = vList[TrianglesIndex[i].meshIndex[1]].point[1]; 		z1 = vList[TrianglesIndex[i].meshIndex[1]].point[2]; 		x2 = nextVList[TrianglesIndex[i].meshIndex[1]].point[0]; 		y2 = nextVList[TrianglesIndex[i].meshIndex[1]].point[1]; 		z2 = nextVList[TrianglesIndex[i].meshIndex[1]].point[2]; 		 		// store third interpolated vertex of triangle 		vertex[1].point[0] = x1 + Interpolation * (x2 - x1); 		vertex[1].point[1] = y1 + Interpolation * (y2 - y1); 		vertex[1].point[2] = z1 + Interpolation * (z2 - z1); 		 		// calculate the normal of the triangle 		CalculateNormal(vertex[0].point, vertex[2].point, vertex[1].point); 		 		// render properly textured triangle 		glTexCoord2f(TextureCoords[TrianglesIndex[i].stIndex[0]].s, TextureCoords[TrianglesIndex[i].stIndex[0]].t); 		glVertex3fv(vertex[0].point); 		 		glTexCoord2f(TextureCoords[TrianglesIndex[i].stIndex[2]].s, TextureCoords[TrianglesIndex[i].stIndex[2]].t); 		glVertex3fv(vertex[2].point); 		 		glTexCoord2f(TextureCoords[TrianglesIndex[i].stIndex[1]].s, TextureCoords[TrianglesIndex[i].stIndex[1]].t); 		glVertex3fv(vertex[1].point); 	} 	glEnd(); }