www.pudn.com > Gimcrack-v0.0051-Source.zip > gmd.cpp


#include  
#include  
#include "gmdformat.h" 
#include "gmd.h" 
#include "../math/vector.h" 
#include "../math/math.h" 
using namespace std; 
 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
GcGMD::GcGMD(): 
triangles(NULL), 
vertices(NULL), 
texCoords(NULL), 
texture(NULL), 
interpol(0.0f), 
activeSkin(0) 
{ 
 
} 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
GcGMD::~GcGMD() 
{ 
	// Destroy the model 
	Destroy(); 
} 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
bool GcGMD::Load(char *fileName, char *skinName) 
{ 
	// Load the model 
	Load(fileName); 
 
	// Allocate memory for the skin 
	texture = new GcTexture[1]; 
 
	// Create the texture 
	texture[0].Create(skinName); 
 
	// Set the active skin 
	activeSkin = 0; 
	header.numSkins = 1; 
 
	return true; 
} 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
bool GcGMD::Load(char *fileName) 
{ 
	// Open the file for reading 
	ifstream file(fileName, ios::in | ios::binary); 
 
	// Check for success 
	if(!file) { 
		return false; 
	} 
 
	// Read the head from the file 
	file.read((char*)&header, sizeof(GMDHeader)); 
 
	// Allocate memory from the vertices 
	vertices = new GcPoint3[header.numVertices * header.numFrames]; 
 
	// Read the vertices from the file 
	file.read((char*)vertices, sizeof(GcPoint3) * header.numVertices * header.numFrames); 
 
	// Allocate memory for the texture coordinates 
	texCoords = new GcPoint2[header.numTexCoords]; 
 
	// Read the texture coordinates from the file 
	file.read((char*)texCoords, sizeof(GcPoint2) * header.numTexCoords); 
 
	// Allocate memory for the triangles 
	triangles = new GMDTri[header.numTris]; 
 
	// Find the correct reading position 
	file.seekg(header.offsetTris, ios::beg); 
 
	// Read the triangles from the file 
	file.read((char*)triangles, sizeof(GMDTri) * header.numTris); 
 
	// No skin was loaded 
	header.numSkins = 0; 
 
 
	/* Find the extreme points for the bounding box */ 
	GcVector3 extreme(0, 0, 0); 
	GcPoint3 currPoint; 
 
	for(int i = 0; i < header.numTris; i++) 
	{ 
		// Get the first points from this fram and the next 
		currPoint.x = vertices[triangles[i].triInd[0]].x; 
		currPoint.y = vertices[triangles[i].triInd[0]].y; 
		currPoint.z = vertices[triangles[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 GcGMD::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 > header.numSkins - 1)) { 
		g_Debug->Log("Failed to load skin %d\n", index); 
		return false; 
	} 
 
	// Create the skin 
	texture[index].Create(skinName); 
 
	return true; 
} 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
void GcGMD::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 
	header.numSkins = num; 
} 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
bool GcGMD::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 >= header.numFrames) || (endFrame >= header.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 = &vertices[header.numVertices * currentFrame]; 
	nextList = &vertices[header.numVertices * nextFrame]; 
 
	// Bind the texture for the model 
	if(header.numSkins > 0) { 
		texture[activeSkin].Bind(); 
	} 
 
	glPushMatrix(); 
	 
		glMultMatrixf(m_worldMatrix); 
	 
		glBegin(GL_TRIANGLES); 
			 
			for(int i = 0; i < header.numTris; i++) 
			{ 
				// Get the first points from this fram and the next 
				currPoint.x = currList[triangles[i].triInd[0]].x; 
				currPoint.y = currList[triangles[i].triInd[0]].y; 
				currPoint.z = currList[triangles[i].triInd[0]].z; 
				nextPoint.x = nextList[triangles[i].triInd[0]].x; 
				nextPoint.y = nextList[triangles[i].triInd[0]].y; 
				nextPoint.z = nextList[triangles[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[triangles[i].triInd[1]].x; 
				currPoint.y = currList[triangles[i].triInd[1]].y; 
				currPoint.z = currList[triangles[i].triInd[1]].z; 
				nextPoint.x = nextList[triangles[i].triInd[1]].x; 
				nextPoint.y = nextList[triangles[i].triInd[1]].y; 
				nextPoint.z = nextList[triangles[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[triangles[i].triInd[2]].x; 
				currPoint.y = currList[triangles[i].triInd[2]].y; 
				currPoint.z = currList[triangles[i].triInd[2]].z; 
				nextPoint.x = nextList[triangles[i].triInd[2]].x; 
				nextPoint.y = nextList[triangles[i].triInd[2]].y; 
				nextPoint.z = nextList[triangles[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 OpenGL 
				glNormal3f(normal.x, normal.y, normal.z); 
 
				// Render the triangle 
				glTexCoord2f(texCoords[triangles[i].texCrdInd[0]].x,  
							 texCoords[triangles[i].texCrdInd[0]].y); 
				glVertex3fv(vertex[0].array); 
 
				glTexCoord2f(texCoords[triangles[i].texCrdInd[2]].x,  
							 texCoords[triangles[i].texCrdInd[2]].y); 
				glVertex3fv(vertex[2].array); 
 
				glTexCoord2f(texCoords[triangles[i].texCrdInd[1]].x,  
							 texCoords[triangles[i].texCrdInd[1]].y); 
				glVertex3fv(vertex[1].array); 
			} 
 
		glEnd(); 
 
	glPopMatrix(); 
 
	interpol += percent; 
 
	return true; 
} 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
bool GcGMD::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 > header.numFrames) { 
		return false; 
	} 
 
	// Set the pointers to point to this frame's vertices 
	currList = &vertices[header.numVertices * frame]; 
 
	// Bind the texture for the model 
	if(header.numSkins > 0) { 
		texture[activeSkin].Bind(); 
	} 
 
	glPushMatrix(); 
	 
		glMultMatrixf(m_worldMatrix); 
 
		glBegin(GL_TRIANGLES); 
			 
			for(int i = 0; i < header.numTris; i++) 
			{ 
				// Get the first point from this frame 
				vertex[0].x = currList[triangles[i].triInd[0]].x; 
				vertex[0].y = currList[triangles[i].triInd[0]].y; 
				vertex[0].z = currList[triangles[i].triInd[0]].z; 
 
				// Get the second point from this frame 
				vertex[1].x = currList[triangles[i].triInd[1]].x; 
				vertex[1].y = currList[triangles[i].triInd[1]].y; 
				vertex[1].z = currList[triangles[i].triInd[1]].z; 
 
				// Get the third point from this frame 
				vertex[2].x = currList[triangles[i].triInd[2]].x; 
				vertex[2].y = currList[triangles[i].triInd[2]].y; 
				vertex[2].z = currList[triangles[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(texCoords[triangles[i].texCrdInd[0]].x,  
							 texCoords[triangles[i].texCrdInd[0]].y); 
				glVertex3fv(vertex[0].array); 
 
				glTexCoord2f(texCoords[triangles[i].texCrdInd[2]].x,  
							 texCoords[triangles[i].texCrdInd[2]].y); 
				glVertex3fv(vertex[2].array); 
 
				glTexCoord2f(texCoords[triangles[i].texCrdInd[1]].x,  
							 texCoords[triangles[i].texCrdInd[1]].y); 
				glVertex3fv(vertex[1].array); 
			} 
 
		glEnd(); 
 
	glPopMatrix(); 
 
	return true; 
} 
 
/////////////////////////////////////////////////////////////////////////////////////////// 
 
void GcGMD::Destroy() 
{ 
	// Clean up the memory 
	if(triangles != NULL) { 
		delete [] triangles; 
		triangles = NULL; 
	} 
 
	if(vertices != NULL) { 
		delete [] vertices; 
		vertices = NULL; 
	} 
 
	if(texCoords != NULL) { 
		delete [] texCoords; 
		texCoords = NULL; 
	} 
 
	if(texture != NULL) { 
		delete [] texture; 
		texture = NULL; 
	} 
} 
 
///////////////////////////////////////////////////////////////////////////////////////////