⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gmd.cpp

📁 小型的3D游戏引擎
💻 CPP
字号:
#include <iostream>
#include <fstream>
#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;
	}
}

///////////////////////////////////////////////////////////////////////////////////////////

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -