www.pudn.com > Gimcrack-v0.0051-Source.zip > md2.cpp
#include#include #include #include #include "md2.h" #include "gmdformat.h" #include "../math/point.h" #include "../math/math.h" using namespace std; //////////////////////////////////////////////////////////////////////////////////////////// GcMD2::GcMD2() { triIndex = NULL; texCrds = NULL; vertexList = NULL; texture = NULL; } //////////////////////////////////////////////////////////////////////////////////////////// GcMD2::~GcMD2() { // Clear up the memory Destroy(); } //////////////////////////////////////////////////////////////////////////////////////////// bool GcMD2::Load(char *fileName, char *texName) { int fileLen; byte *buffer; MD2Header *header; MD2Frame *frame; int i,j; // Open the model file ifstream file(fileName, ios::in | ios::binary); // Check for success if(!file) { return false; } // Get file lenght file.seekg(0, ios::end); fileLen = file.tellg(); file.seekg(0, ios::beg); // Allocate memory for the buffer buffer = new byte[fileLen+1]; // Read the file into the buffer file.read((char*)buffer, fileLen); // Extract the header header = (MD2Header*)buffer; /* Calculate and save the vertex data */ // Save important model data numVertices = header->numVertices; numFrames = header->numFrames; frameSize = header->frameSize; // Allocate memory for the vertex list vertexList = new GcPoint3[numVertices * numFrames]; GcPoint3 *vertexStart; for(i = 0; i < numFrames; i++) { // Extract the fram form the buffer frame = (MD2Frame*)&buffer[header->offsetFrames + frameSize * i]; vertexStart = (GcPoint3*)&vertexList[numVertices * i]; for(j = 0; j < numVertices; j++) { // Calculate the vertex vertexStart[j].x = frame->scale.x * frame->fp[j].v[0] + frame->translate.x; vertexStart[j].y = frame->scale.y * frame->fp[j].v[1] + frame->translate.y; vertexStart[j].z = frame->scale.z * frame->fp[j].v[2] + frame->translate.z; } } /* Calculate and save the texture data */ // Create the texture texture = new GcTexture[1]; // Loade the texture texture[0].Create(texName); // Save the number of texture coordinates numTexCrds = header->numTexCoords; // Allocate memory for the texture coordinates texCrds = new GcPoint2[numTexCrds]; // Point to the begining of the texture coords MD2TexInd *texStart = (MD2TexInd*)&buffer[header->offsetTexCoords]; // Calcualte the texutre coords for(i = 0; i < numTexCrds; i++) { texCrds[i].x = (float)texStart[i].x / (float)texture[0].Width(); texCrds[i].y = (float)texStart[i].y / (float)texture[0].Height(); } /* Calculate and save the triangle data */ // Get the number of trinagles numTris = header->numTris; // Allocate memory for the trinagles (well, the indicec for the tringles triIndex = new MD2Tri[numTris]; // Point to the start of the triangle indices MD2Tri *triStart = (MD2Tri*)&buffer[header->offsetTris]; // Save the trinagle indeces for(i = 0; i < numTris; i++) { // Save the triangle indices triIndex[i].triInd[0] = triStart[i].triInd[0]; triIndex[i].triInd[1] = triStart[i].triInd[1]; triIndex[i].triInd[2] = triStart[i].triInd[2]; // Save the texture coordinates indices of the trinagle triIndex[i].texCrdInd[0] = triStart[i].texCrdInd[0]; triIndex[i].texCrdInd[1] = triStart[i].texCrdInd[1]; triIndex[i].texCrdInd[2] = triStart[i].texCrdInd[2]; } /* Cleen up temporary files */ // Close the file file.close(); // Free upp memory delete [] buffer; /* Set model vars */ currentFrame = 0; nextFrame = 1; interpol = 0.0f; activeSkin = 0; numSkins = 1; /* Find the extreme points for the bounding box */ GcVector3 extreme(0, 0, 0); GcPoint3 currPoint; for(i = 0; i < numTris; i++) { // Get the first points from this fram and the next currPoint.x = vertexList[triIndex[i].triInd[0]].x; currPoint.y = vertexList[triIndex[i].triInd[0]].y; currPoint.z = vertexList[triIndex[i].triInd[0]].z; if(currPoint.x > extreme.x) { extreme.x = currPoint.x; } if(currPoint.y > extreme.y) { extreme.y = currPoint.y; } if(currPoint.z > extreme.z) { extreme.z = currPoint.z; } } g_Debug->Log("Extreme x: %f - y: %f - z: %f\n", extreme.x, extreme.y, extreme.z ); SetExtents(extreme); return true; } //////////////////////////////////////////////////////////////////////////////////////////// bool GcMD2::Load(char *fileName) { int fileLen; char *buffer; MD2Header *header; MD2Frame *frame; int i,j; // Open the model file ifstream file(fileName, ios::in | ios::binary); // Check for success if(!file) { return false; } // Get file lenght file.seekg(0, ios::end); fileLen = file.tellg(); file.seekg(0, ios::beg); // Allocate memory for the buffer buffer = new char[fileLen+1]; // Read the file into the buffer //file.read((char *)buffer, fileLen); file.read(buffer, fileLen); // Extract the header header = (MD2Header*)buffer; /* Calculate and save the vertex data */ // Save important model data numVertices = header->numVertices; numFrames = header->numFrames; frameSize = header->frameSize; // Allocate memory for the vertex list vertexList = new GcPoint3[numVertices * numFrames]; GcPoint3 *vertexStart; for(i = 0; i < numFrames; i++) { // Extract the fram form the buffer frame = (MD2Frame*)&buffer[header->offsetFrames + frameSize * i]; vertexStart = (GcPoint3*)&vertexList[numVertices * i]; for(j = 0; j < numVertices; j++) { // Calculate the vertex vertexStart[j].x = frame->scale.x * frame->fp[j].v[0] + frame->translate.x; vertexStart[j].y = frame->scale.y * frame->fp[j].v[1] + frame->translate.y; vertexStart[j].z = frame->scale.z * frame->fp[j].v[2] + frame->translate.z; } } /* Calculate and save the texture data (load it now, to use when the other skins */ /* are loaded) */ // Save the number of texture coordinates numTexCrds = header->numTexCoords; // Allocate memory for the texture coordinates texCrds = new GcPoint2[numTexCrds]; // Point to the begining of the texture coords MD2TexInd *texStart = (MD2TexInd*)&buffer[header->offsetTexCoords]; // Calcualte the texutre coords for(i = 0; i < numTexCrds; i++) { texCrds[i].x = (float)texStart[i].x; texCrds[i].y = (float)texStart[i].y; } /* Calculate and save the triangle data */ // Get the number of trinagles numTris = header->numTris; // Allocate memory for the trinagles (well, the indicec for the tringles triIndex = new MD2Tri[numTris]; // Point to the start of the triangle indices MD2Tri *triStart = (MD2Tri*)&buffer[header->offsetTris]; // Save the trinagle indeces for(i = 0; i < numTris; i++) { // Save the triangle indices triIndex[i].triInd[0] = triStart[i].triInd[0]; triIndex[i].triInd[1] = triStart[i].triInd[1]; triIndex[i].triInd[2] = triStart[i].triInd[2]; // Save the texture coordinates indices of the trinagle triIndex[i].texCrdInd[0] = triStart[i].texCrdInd[0]; triIndex[i].texCrdInd[1] = triStart[i].texCrdInd[1]; triIndex[i].texCrdInd[2] = triStart[i].texCrdInd[2]; } /* Cleen up temporary files */ // Close the file file.close(); // Free upp memory delete [] buffer; /* Set model vars */ currentFrame = 0; nextFrame = 1; interpol = 0.0f; numSkins = 0; /* Find the extreme points for the bounding box */ GcVector3 extreme(0, 0, 0); GcPoint3 currPoint; for(i = 0; i < numTris; i++) { // Get the first points from this fram and the next currPoint.x = vertexList[triIndex[i].triInd[0]].x; currPoint.y = vertexList[triIndex[i].triInd[0]].y; currPoint.z = vertexList[triIndex[i].triInd[0]].z; if(currPoint.x > extreme.x) { extreme.x = currPoint.x; } if(currPoint.y > extreme.y) { extreme.y = currPoint.y; } if(currPoint.z > extreme.z) { extreme.z = currPoint.z; } } g_Debug->Log("Extreme x: %f - y: %f - z: %f\n", extreme.x, extreme.y, extreme.z ); SetExtents(extreme); return true; } /////////////////////////////////////////////////////////////////////////////////////////// bool GcMD2::LoadSkin(char *skinName, uint index) { // Check to see that the skin is valid and that a texture space for it exist if((texture == NULL) || (index > numSkins - 1)) { g_Debug->Log("Failed to load skin %d\n", index); return false; } // Create the skin texture[index].Create(skinName); // Calcualte the texutre coords for(int i = 0; i < numTexCrds; i++) { texCrds[i].x /= texture[index].Width(); texCrds[i].y /= texture[index].Height(); } return true; } /////////////////////////////////////////////////////////////////////////////////////////// void GcMD2::SetNumberOfSkins(uint num) { // Delete previus textures if needed if(texture != NULL) { delete [] texture; } // Create new textures texture = new GcTexture[num]; // Save the number of skins numSkins = num; } //////////////////////////////////////////////////////////////////////////////////////////// bool GcMD2::Animate(int startFrame, int endFrame, float percent) { GcPoint3 *currList; // Holds the current frame's vertices GcPoint3 *nextList; // Holds the next frame's vertices GcPoint3 currPoint; GcPoint3 nextPoint; GcPoint3 vertex[3]; // The vertex's to be rendered GcVector3 normal; // The vertex normal if(startFrame > currentFrame) { currentFrame = startFrame; } if((startFrame < 0) || (endFrame < 0)) { return false; } if((startFrame >= numFrames) || (endFrame >= numFrames)) { return false; } if(interpol >= 1.0f) { // Re-set the interpolation interpol = 0.0f; // Another fram has gone by currentFrame++; // Time to start the animation over? if(currentFrame >= endFrame) { currentFrame = startFrame; } // Set the next frame nextFrame = currentFrame + 1; // Time to start the animation over? if(nextFrame >= endFrame) { nextFrame = startFrame; } } // Set the pointers to point to this frame's vertices, and the next currList = &vertexList[numVertices*currentFrame]; nextList = &vertexList[numVertices*nextFrame]; // Bind the texture for the model if(numSkins > 0) { texture[activeSkin].Bind(); } glPushMatrix(); glMultMatrixf(m_worldMatrix); glBegin(GL_TRIANGLES); for(int i = 0; i < numTris; i++) { // Get the first points from this fram and the next currPoint.x = currList[triIndex[i].triInd[0]].x; currPoint.y = currList[triIndex[i].triInd[0]].y; currPoint.z = currList[triIndex[i].triInd[0]].z; nextPoint.x = nextList[triIndex[i].triInd[0]].x; nextPoint.y = nextList[triIndex[i].triInd[0]].y; nextPoint.z = nextList[triIndex[i].triInd[0]].z; // Claculate the first interpolated vertex vertex[0] = (nextPoint - currPoint) * interpol + currPoint; // Get the first points from this fram and the next currPoint.x = currList[triIndex[i].triInd[1]].x; currPoint.y = currList[triIndex[i].triInd[1]].y; currPoint.z = currList[triIndex[i].triInd[1]].z; nextPoint.x = nextList[triIndex[i].triInd[1]].x; nextPoint.y = nextList[triIndex[i].triInd[1]].y; nextPoint.z = nextList[triIndex[i].triInd[1]].z; // Claculate the second interpolated vertex vertex[1] = (nextPoint - currPoint) * interpol + currPoint; // Get the first points from this fram and the next currPoint.x = currList[triIndex[i].triInd[2]].x; currPoint.y = currList[triIndex[i].triInd[2]].y; currPoint.z = currList[triIndex[i].triInd[2]].z; nextPoint.x = nextList[triIndex[i].triInd[2]].x; nextPoint.y = nextList[triIndex[i].triInd[2]].y; nextPoint.z = nextList[triIndex[i].triInd[2]].z; // Claculate the first interpolated vertex vertex[2] = (nextPoint - currPoint) * interpol + currPoint; // Calculate the normal normal = GcMath::ClaculateNormal(vertex[0], vertex[1], vertex[3]); // Give the normal to open gl glNormal3f(normal.x, normal.y, normal.z); // Render the triangle glTexCoord2f(texCrds[triIndex[i].texCrdInd[0]].x, texCrds[triIndex[i].texCrdInd[0]].y); glVertex3fv(vertex[0].array); glTexCoord2f(texCrds[triIndex[i].texCrdInd[2]].x, texCrds[triIndex[i].texCrdInd[2]].y); glVertex3fv(vertex[2].array); glTexCoord2f(texCrds[triIndex[i].texCrdInd[1]].x, texCrds[triIndex[i].texCrdInd[1]].y); glVertex3fv(vertex[1].array); } glEnd(); interpol += percent; glPopMatrix(); return true; } //////////////////////////////////////////////////////////////////////////////////////////// bool GcMD2::RenderKeyFrame(int frame) { GcPoint3 *currList; // Holds the current frame's vertices GcPoint3 vertex[3]; // The vertices to be rendered GcVector3 normal; // The triangle normal // Check for a valid frame if(frame < 0 || frame > numFrames) { return false; } // Set the pointers to point to this frame's vertices currList = &vertexList[numVertices * frame]; // Bind the texture for the model if(numSkins > 0) { texture[activeSkin].Bind(); } glPushMatrix(); glMultMatrixf(m_worldMatrix); glBegin(GL_TRIANGLES); for(int i = 0; i < numTris; i++) { // Get the first point from this frame vertex[0].x = currList[triIndex[i].triInd[0]].x; vertex[0].y = currList[triIndex[i].triInd[0]].y; vertex[0].z = currList[triIndex[i].triInd[0]].z; // Get the second point from this frame vertex[1].x = currList[triIndex[i].triInd[1]].x; vertex[1].y = currList[triIndex[i].triInd[1]].y; vertex[1].z = currList[triIndex[i].triInd[1]].z; // Get the third point from this frame vertex[2].x = currList[triIndex[i].triInd[2]].x; vertex[2].y = currList[triIndex[i].triInd[2]].y; vertex[2].z = currList[triIndex[i].triInd[2]].z; // Calculate the normal normal = GcMath::ClaculateNormal(vertex[0], vertex[1], vertex[3]); // Give the normal to OpenGL glNormal3f(normal.x, normal.y, normal.z); // Render the triangle glTexCoord2f(texCrds[triIndex[i].texCrdInd[0]].x, texCrds[triIndex[i].texCrdInd[0]].y); glVertex3fv(vertex[0].array); glTexCoord2f(texCrds[triIndex[i].texCrdInd[2]].x, texCrds[triIndex[i].texCrdInd[2]].y); glVertex3fv(vertex[2].array); glTexCoord2f(texCrds[triIndex[i].texCrdInd[1]].x, texCrds[triIndex[i].texCrdInd[1]].y); glVertex3fv(vertex[1].array); } glEnd(); glPopMatrix(); return true; } //////////////////////////////////////////////////////////////////////////////////////////// void GcMD2::Destroy() { // Clear up the memory if(triIndex != NULL) { delete [] triIndex; triIndex = NULL; } if(texCrds != NULL) { delete [] texCrds; texCrds = NULL; } if(vertexList != NULL) { delete [] vertexList; vertexList = NULL; } if(texture != NULL) { delete [] texture; texture = NULL; } } //////////////////////////////////////////////////////////////////////////////////////////// bool GcMD2::SaveAsGMD(char *fileName) { // Open the file for writing ofstream file(fileName, ios::out | ios::binary); // Check for success if(!file.is_open()) { return false; } // Create a GMD header GMDHeader *header = new GMDHeader; header->ident = GMD_IDENT; header->numFrames = numFrames; header->numTexCoords = numTexCrds; header->numTris = numTris; header->numVertices = numVertices; header->offsetEnd = sizeof(GMDHeader) + sizeof(GcPoint3) * numVertices * numFrames + sizeof(GcPoint2) * numTexCrds + sizeof(MD2Tri) * numTris; header->offsetFrames = sizeof(GMDHeader); header->offsetTexCoords = sizeof(GMDHeader) + sizeof(GcPoint3) * numVertices * numFrames; header->offsetTris = sizeof(GMDHeader) + sizeof(GcPoint3) * numVertices * numFrames + sizeof(GcPoint2) * numTexCrds; // Write the header to the file file.write((char*)header, sizeof(GMDHeader)); // Write the frames (vertices to the list) file.write((char*)vertexList, sizeof(GMDVertex) * header->numVertices * header->numFrames); // Write the texture coordinates to the file file.write((char*)texCrds, sizeof(GMDTexCoord) * header->numTexCoords); // Write the trinagle indeices to the file file.write((char*)triIndex, sizeof(GMDTri) * header->numTris); // Close the file file.close(); // Clean up temporary files delete header; return true; } ////////////////////////////////////////////////////////////////////////////////////////////