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; 
} 
 
////////////////////////////////////////////////////////////////////////////////////////////