www.pudn.com > ATimeToKill.rar > md2.cpp
#include "md2.h"
// CalculateNormal()
// desc: given 3 points, calculates the normal to the points
void 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);
}
// vector subtraction
vector_t operator-(vector_t a, vector_t b)
{
vector_t 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
vector_t operator*(float f, vector_t b)
{
vector_t 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
vector_t operator/(vector_t a, vector_t b)
{
vector_t 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
vector_t operator+(vector_t a, vector_t b)
{
vector_t 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;
}
// CMD2Model constructor
CMD2Model::CMD2Model()
{
numVertices = 0; // vertices
numTriangles = 0; // triangles
numFrames = 0; // frames
numST = 0; // texture coordinates
frameSize = 0; // needed?
currentFrame = 0; // current keyframe
nextFrame = 1; // next keyframe
interpol = 0.0; // interpolation percent
triIndex = NULL; // triangle indices
st = NULL; // texture coordinate indices
vertexList = NULL; // vertices
modelTex = new CTexture; // skin/texture
modelState = MODEL_IDLE;
}
// CMD2Model destructor
CMD2Model::~CMD2Model()
{
Unload();
}
// CMD2Model::SetupSkin()
// access: private
// desc: sets up the model skin/texture for OpenGL
void CMD2Model::SetupSkin(CTexture *thisTexture)
{
// set the proper parameters for an MD2 texture
glGenTextures(1, &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_MIPMAP_NEAREST);
switch (thisTexture->textureType)
{
case BMP:
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, thisTexture->width, thisTexture->height,
GL_RGB, GL_UNSIGNED_BYTE, thisTexture->data);
break;
case PCX:
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGBA, thisTexture->width, thisTexture->height,
GL_RGBA, GL_UNSIGNED_BYTE, thisTexture->data);
break;
case TGA:
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, thisTexture->width, thisTexture->height,
GL_RGB, GL_UNSIGNED_BYTE, thisTexture->data);
break;
default:
break;
}
}
// CMD2Model::Load()
// access: public
// desc: loads model and skin
int CMD2Model::Load(char *modelFile, char *skinFile)
{
FILE *filePtr; // file pointer
int fileLen; // length of model file
char *buffer; // file buffer
modelHeader_t *modelHeader; // model header
stIndex_t *stPtr; // texture data
frame_t *frame; // frame data
vector_t *vertexListPtr; // index variable
mesh_t *bufIndexPtr; // index variables
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);
fileLen = ftell(filePtr);
fseek(filePtr, 0, SEEK_SET);
// read entire file into buffer
buffer = new char [fileLen+1];
fread(buffer, sizeof(char), fileLen, filePtr);
// extract model file header from buffer
modelHeader = (modelHeader_t*)buffer;
vertexList = new vector_t [modelHeader->numXYZ * modelHeader->numFrames];
numVertices = modelHeader->numXYZ;
numFrames = modelHeader->numFrames;
frameSize = modelHeader->framesize;
for (j = 0; j < numFrames; j++)
{
frame = (frame_t*)&buffer[modelHeader->offsetFrames + frameSize * j];
vertexListPtr = (vector_t*)&vertexList[numVertices * j];
for (i = 0; i < numVertices; i++)
{
vertexListPtr[i].point[0] = frame->scale[0] * frame->fp[i].v[0] + frame->translate[0];
vertexListPtr[i].point[1] = frame->scale[1] * frame->fp[i].v[1] + frame->translate[1];
vertexListPtr[i].point[2] = frame->scale[2] * frame->fp[i].v[2] + frame->translate[2];
}
}
modelTex->LoadTexture(skinFile);// = LoadTexture(skinFile);
if (modelTex != NULL)
SetupSkin(modelTex);
else
return FALSE;
numST = modelHeader->numST;
st = new texCoord_t [numST];
stPtr = (stIndex_t*)&buffer[modelHeader->offsetST];
for (i = 0; i < numST; i++)
{
st[i].s = (float)stPtr[i].s / (float)modelTex->width;
st[i].t = (float)stPtr[i].t / (float)modelTex->height;
}
numTriangles = modelHeader->numTris;
triIndex = new mesh_t [numTriangles];
// point to triangle indexes in buffer
bufIndexPtr = (mesh_t*)&buffer[modelHeader->offsetTris];
// create a mesh (triangle) list
for (j = 0; j < numFrames; j++)
{
// for all triangles in each frame
for(i = 0; i < numTriangles; i++)
{
triIndex[i].meshIndex[0] = bufIndexPtr[i].meshIndex[0];
triIndex[i].meshIndex[1] = bufIndexPtr[i].meshIndex[1];
triIndex[i].meshIndex[2] = bufIndexPtr[i].meshIndex[2];
triIndex[i].stIndex[0] = bufIndexPtr[i].stIndex[0];
triIndex[i].stIndex[1] = bufIndexPtr[i].stIndex[1];
triIndex[i].stIndex[2] = bufIndexPtr[i].stIndex[2];
}
}
// close file and free memory
fclose(filePtr);
delete buffer;
currentFrame = 0;
nextFrame = 1;
interpol = 0.0;
return TRUE;
}
// CMD2Model::LoadModel()
// access: public
// desc: loads model from file
int CMD2Model::LoadModel(char *modelFile)
{
FILE *filePtr; // file pointer
int fileLen; // length of model file
char *buffer; // file buffer
modelHeader_t *modelHeader; // model header
stIndex_t *stPtr; // texture data
frame_t *frame; // frame data
vector_t *vertexListPtr; // index variable
mesh_t *triIndex, *bufIndexPtr; // index variables
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);
fileLen = ftell(filePtr);
fseek(filePtr, 0, SEEK_SET);
// read entire file into buffer
buffer = new char [fileLen+1];
fread(buffer, sizeof(char), fileLen, filePtr);
// extract model file header from buffer
modelHeader = (modelHeader_t*)buffer;
// allocate vertex list
vertexList = new vector_t [modelHeader->numXYZ * modelHeader->numFrames];
numVertices = modelHeader->numXYZ;
numFrames = modelHeader->numFrames;
frameSize = modelHeader->framesize;
for (j = 0; j < numFrames; j++)
{
frame = (frame_t*)&buffer[modelHeader->offsetFrames + frameSize * j];
vertexListPtr = (vector_t*)&vertexList[numVertices * j];
for (i = 0; i < numVertices; i++)
{
vertexListPtr[i].point[0] = frame->scale[0] * frame->fp[i].v[0] + frame->translate[0];
vertexListPtr[i].point[1] = frame->scale[1] * frame->fp[i].v[1] + frame->translate[1];
vertexListPtr[i].point[2] = frame->scale[2] * frame->fp[i].v[2] + frame->translate[2];
}
}
numST = modelHeader->numST;
st = new texCoord_t [numST];
stPtr = (stIndex_t*)&buffer[modelHeader->offsetST];
for (i = 0; i < numST; i++)
{
st[i].s = 0.0;
st[i].t = 0.0;
}
numTriangles = modelHeader->numTris;
triIndex = new mesh_t [numTriangles];
// point to triangle indexes in buffer
bufIndexPtr = (mesh_t*)&buffer[modelHeader->offsetTris];
// create a mesh (triangle) list
for (j = 0; j < numFrames; j++)
{
// for all triangles in each frame
for(i = 0; i < numTriangles; i++)
{
triIndex[i].meshIndex[0] = bufIndexPtr[i].meshIndex[0];
triIndex[i].meshIndex[1] = bufIndexPtr[i].meshIndex[1];
triIndex[i].meshIndex[2] = bufIndexPtr[i].meshIndex[2];
triIndex[i].stIndex[0] = bufIndexPtr[i].stIndex[0];
triIndex[i].stIndex[1] = bufIndexPtr[i].stIndex[1];
triIndex[i].stIndex[2] = bufIndexPtr[i].stIndex[2];
}
}
// close file and free memory
fclose(filePtr);
delete buffer;
modelTex = NULL;
currentFrame = 0;
nextFrame = 1;
interpol = 0.0;
return 0;
}
// CMD2Model::LoadSkin()
// access: public
// desc: loads a skin for the model
int CMD2Model::LoadSkin(char *skinFile)
{
int i;
modelTex->LoadTexture(skinFile);
if (modelTex != NULL)
SetupSkin(modelTex);
else
return -1;
for (i = 0; i < numST; i++)
{
st[i].s /= (float)modelTex->width;
st[i].t /= (float)modelTex->height;
}
return 0;
}
// CMD2Model::SetTexture()
// access: public
// desc: sets a new texture object
int CMD2Model::SetTexture(CTexture *texture)
{
int i;
if (texture != NULL)
{
free(modelTex);
modelTex = texture;
}
else
return -1;
SetupSkin(modelTex);
for (i = 0; i < numST; i++)
{
st[i].s /= (float)modelTex->width;
st[i].t /= (float)modelTex->height;
}
return 0;
}
// CMD2Model::Animate()
// access: public
// desc: animates the model between the keyframes startFrame and endFrame
int CMD2Model::AnimateModel(int startFrame, int endFrame, float percent)
{
vector_t *vList; // current frame vertices
vector_t *nextVList; // next frame vertices
int i; // index counter
float x1, y1, z1; // current frame point values
float x2, y2, z2; // next frame point values
vector_t vertex[3];
if ((startFrame > currentFrame))
currentFrame = startFrame;
if ((startFrame < 0) || (endFrame < 0))
return -1;
if ((startFrame >= numFrames) || (endFrame >= numFrames))
return -1;
if (interpol >= 1.0)
{
interpol = 0.0f;
currentFrame++;
if (currentFrame >= endFrame)
currentFrame = startFrame;
nextFrame = currentFrame + 1;
if (nextFrame >= endFrame)
nextFrame = startFrame;
}
vList = &vertexList[numVertices*currentFrame];
nextVList = &vertexList[numVertices*nextFrame];
glColor4f(1.0, 1.0, 1.0, 1.0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, modelTex->texID);
glBegin(GL_TRIANGLES);
for (i = 0; i < numTriangles; i++)
{
// get first points of each frame
x1 = vList[triIndex[i].meshIndex[0]].point[0];
y1 = vList[triIndex[i].meshIndex[0]].point[1];
z1 = vList[triIndex[i].meshIndex[0]].point[2];
x2 = nextVList[triIndex[i].meshIndex[0]].point[0];
y2 = nextVList[triIndex[i].meshIndex[0]].point[1];
z2 = nextVList[triIndex[i].meshIndex[0]].point[2];
// store first interpolated vertex of triangle
vertex[0].point[0] = x1 + interpol * (x2 - x1);
vertex[0].point[1] = y1 + interpol * (y2 - y1);
vertex[0].point[2] = z1 + interpol * (z2 - z1);
// get second points of each frame
x1 = vList[triIndex[i].meshIndex[2]].point[0];
y1 = vList[triIndex[i].meshIndex[2]].point[1];
z1 = vList[triIndex[i].meshIndex[2]].point[2];
x2 = nextVList[triIndex[i].meshIndex[2]].point[0];
y2 = nextVList[triIndex[i].meshIndex[2]].point[1];
z2 = nextVList[triIndex[i].meshIndex[2]].point[2];
// store second interpolated vertex of triangle
vertex[2].point[0] = x1 + interpol * (x2 - x1);
vertex[2].point[1] = y1 + interpol * (y2 - y1);
vertex[2].point[2] = z1 + interpol * (z2 - z1);
// get third points of each frame
x1 = vList[triIndex[i].meshIndex[1]].point[0];
y1 = vList[triIndex[i].meshIndex[1]].point[1];
z1 = vList[triIndex[i].meshIndex[1]].point[2];
x2 = nextVList[triIndex[i].meshIndex[1]].point[0];
y2 = nextVList[triIndex[i].meshIndex[1]].point[1];
z2 = nextVList[triIndex[i].meshIndex[1]].point[2];
// store third interpolated vertex of triangle
vertex[1].point[0] = x1 + interpol * (x2 - x1);
vertex[1].point[1] = y1 + interpol * (y2 - y1);
vertex[1].point[2] = z1 + interpol * (z2 - z1);
// calculate the normal of the triangle
CalculateNormal(vertex[0].point, vertex[2].point, vertex[1].point);
// render properly textured triangle
glTexCoord2f(st[triIndex[i].stIndex[0]].s,
st[triIndex[i].stIndex[0]].t);
glVertex3fv(vertex[0].point);
glTexCoord2f(st[triIndex[i].stIndex[2]].s ,
st[triIndex[i].stIndex[2]].t);
glVertex3fv(vertex[2].point);
glTexCoord2f(st[triIndex[i].stIndex[1]].s,
st[triIndex[i].stIndex[1]].t);
glVertex3fv(vertex[1].point);
}
glEnd();
glDisable(GL_TEXTURE_2D);
interpol += percent; // increase percentage of interpolation between frames
return 0;
}
// RenderFrame()
// desc: renders a single key frame
int CMD2Model::RenderFrame(int keyFrame)
{
vector_t *vList;
int i;
// create a pointer to the frame we want to show
vList = &vertexList[numVertices * keyFrame];
if (modelTex != NULL)
// set the texture
glBindTexture(GL_TEXTURE_2D, modelTex->texID);
// display the textured model with proper lighting normals
glBegin(GL_TRIANGLES);
for(i = 0; i < numTriangles; i++)
{
CalculateNormal(vList[triIndex[i].meshIndex[0]].point,
vList[triIndex[i].meshIndex[2]].point,
vList[triIndex[i].meshIndex[1]].point);
if (modelTex != NULL)
glTexCoord2f(st[triIndex[i].stIndex[0]].s,
st[triIndex[i].stIndex[0]].t);
glVertex3fv(vList[triIndex[i].meshIndex[0]].point);
if (modelTex != NULL)
glTexCoord2f(st[triIndex[i].stIndex[2]].s ,
st[triIndex[i].stIndex[2]].t);
glVertex3fv(vList[triIndex[i].meshIndex[2]].point);
if (modelTex != NULL)
glTexCoord2f(st[triIndex[i].stIndex[1]].s,
st[triIndex[i].stIndex[1]].t);
glVertex3fv(vList[triIndex[i].meshIndex[1]].point);
}
glEnd();
return 0;
}
// Unload()
// desc: unloads model data from memory
void CMD2Model::Unload()
{
if (triIndex != NULL)
delete [] triIndex;
if (vertexList != NULL)
delete [] vertexList;
if (st != NULL)
delete [] st;
if (modelTex != NULL)
delete modelTex;
}
// SetState()
// desc: set the model state
void CMD2Model::SetState(modelState_t state)
{
modelState = state;
}
// GetState()
// desc: retrieve the model state
modelState_t CMD2Model::GetState()
{
return modelState;
}