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(); }