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

📄 terrain.cpp

📁 小型的3D游戏引擎
💻 CPP
📖 第 1 页 / 共 2 页
字号:
#include "../texture.h"
#include "../loader/Bitmap.h"
#include "../global.h"
#include "../math/vector.h"
#include "quadtree.h"
#include "terrain.h"


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

GcTerrain::GcTerrain():
mapWidth(0),
squareWidth(17),
scale(200),
heightScale(20),
index(NULL),
colorArray(NULL),
textArray(NULL),
vertexArray(NULL),
normalArray(NULL),
fogCoordArray(NULL),
heightField(NULL)
{
	/* Constructing the terrain object */
}

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

GcTerrain::~GcTerrain()
{
	// Free the terrain
	//Close();
}

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

bool GcTerrain::Init(GcQuadtree *tree, char *heightFile, char *landTex, char *detailTex)
{
	// Initialize the height field
	InitHeightField(heightFile);

	// Initialize the nodes
	InitNodes(tree);

	// Create a memory pool (on the gfx card if posible)
	memPool.Init(CalcMemReq(), GcSettings::VideoMemory());

	// Init the vertex, texture coordinates and color array
	InitVertTextColArray();

	// Init the index array
	InitIndexArray();

	// Init the normal array
	if(GcSettings::Light())
	{
		InitNormalArray();
	}

	// Init the fog array
	if(GcSettings::Fog()) {
		InitFogArray();
	}

	// Create the textures
	landTexture.Create(landTex);
	detailTexture.Create(detailTex);

	// Calculate the triangle count
	totalTri = (mapWidth - 1) * (mapWidth - 1) * 2;

	return true;
}

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

bool GcTerrain::Close()
{
	// Shut down the memory pool
	memPool.ShutDown();

	normalArray = NULL;
	colorArray = NULL;
	textArray = NULL;
	vertexArray = NULL;
	fogCoordArray = NULL;

	if(heightField) {
		delete [] heightField;
		heightField = NULL;
	}

	if(index) {
		delete [] index;
		index = NULL;
	}

	return true;
}

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

float GcTerrain::Height(float sX, float sZ)
{
	// Make sure that the coords are in the map
	int x = int(sX / scale) % mapWidth;
	int z = int(sZ / scale) % mapWidth;

	// Return the height
	return heightField[x + (z * mapWidth)];
}

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

bool GcTerrain::InitHeightField(char *heightFile)
{
	unsigned int x, z, i = 0;

	// Creat a bitmap for loading the 
	GcBitmap *bitmap = new GcBitmap;

	// Load the bitmap
	bitmap->Load(heightFile);

	// Check to make sure that the bitmap is a square
	if(bitmap->Width() != bitmap->Height()) 
	{
		MessageBox(NULL, "Height map must be a square", "Error", MB_OK);
		bitmap->Destroy();
		delete bitmap;
		return false;
	}

	// Save the width of the height map
	mapWidth = bitmap->Width();

	// Create the height field
	heightField = new float[mapWidth * mapWidth];

	// Init the vertex and texture coord array
	for(z = 0; z < mapWidth; z++)
	{
		for(x = 0; x < mapWidth; x++)
		{
			// Assing the hight value to the height file
			heightField[i++] = bitmap->Image((mapWidth * z) + x) * heightScale;
		}
	}

	// Free up the bitmap memPoolory
	g_Debug->Memory(-sizeof(GcBitmap));
	bitmap->Destroy();
	delete bitmap;

	return true;
}

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

bool GcTerrain::InitVertTextColArray()
{	
	unsigned int x, z, j = 0, i = 0;

	// Create the vertex and texture cordinate array
	vertexArray = (float*)memPool.Allocate(mapWidth * mapWidth * 3 * sizeof(float));
	textArray	= (float*)memPool.Allocate(mapWidth * mapWidth * 2 * sizeof(float));
	
	if(GcSettings::ColorArray()) { 
		colorArray	= (float*)memPool.Allocate(mapWidth * mapWidth * 3 * sizeof(float));
	}

	if(vertexArray == NULL || textArray == NULL) {
		MessageBox(NULL, "Memmory allocation to vertexArray, texArray failed", "Error", MB_OK);
		return false;
	}

	// Init the vertex and texture coord array
	for(z = 0; z < mapWidth; z++)
	{
		for(x = 0; x < mapWidth; x++)
		{
			// Calculate the vertex
			vertexArray[j]	 = (float)x * scale;
			vertexArray[j+1] = heightField[(mapWidth * z) + x];
			vertexArray[j+2] = (float)z * scale;

			if(GcSettings::ColorArray())
			{
				// Calculate the color array
				colorArray[j]   = (heightField[(mapWidth * z) + x] / heightScale) / 255.0f;
				colorArray[j+1] = (heightField[(mapWidth * z) + x] / heightScale) / 255.0f;
				colorArray[j+2] = (heightField[(mapWidth * z) + x] / heightScale) / 255.0f;
			}

			// Calculate the texture coordinte
			textArray[i]   =  (float)x / (float)mapWidth;
			textArray[i+1] = -(float)z / (float)mapWidth;

			j += 3;
			i += 2;
		}
	}

	return true;
}

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

void GcTerrain::InitIndexArray()
{
	unsigned int x, z;
	unsigned int j = 0;

	// Create the indices array
	index = new unsigned short int[numVertex];

	// Init the indices array
	for(z = 0; z < squareWidth; z++)
	{
		for(x = 0; x < squareWidth; x++)
		{
			index[j++] = ((mapWidth * z) + x);
			index[j++] = ((mapWidth * z) + x) + mapWidth;
		}
	}
}

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

void GcTerrain::InitNormalArray()
{
	/* This function is extremely slow and should */
	/* not be used in its current form. I'm not   */
	/* even entierly sure it works as it should.  */

	unsigned int x, z, j = 0, i = 0;

	int	point[3];
	GcVector3 vect1, vect2, normal;
	GcVector3 *tempNormal = new GcVector3[(mapWidth - 1)*(mapWidth - 1)*2];
	normalArray	 = (float*)memPool.Allocate(mapWidth * mapWidth * 3 * sizeof(float));

	// Calculate normals
	for(z = 0; z < mapWidth - 1; z++)
	{
		for(x = 0; x < mapWidth - 1; x++)
		{
			// Find which points to use (first traingle in square)
			point[0]   = ((z * mapWidth) + x);
			point[1] = ((z * mapWidth) + x) + 1;
			point[2] = ((z * mapWidth) + x) + mapWidth;

			// Translate the points into two vectors
			vect1.x = vertexArray[point[0]*3] - vertexArray[point[2]*3];
			vect1.y = vertexArray[point[0]*3+1] - vertexArray[point[2]*3+1];
			vect1.z = vertexArray[point[0]*3+2] - vertexArray[point[2]*3+2];

			vect2.x = vertexArray[point[2]*3] - vertexArray[point[1]*3];
			vect2.y = vertexArray[point[2]*3+1] - vertexArray[point[1]*3+1];
			vect2.z = vertexArray[point[2]*3+2] - vertexArray[point[1]*3+2];

			// Calculate the face normal (not normalized)
			vect1.CrossProduct(vect2);

			// Insert the normal into the array
			tempNormal[j] = vect1;

			// Find which points to use (second trinagle in square)
			point[0] = ((z * mapWidth) + x) + 1;
			point[1] = ((z * mapWidth) + x) + mapWidth;
			point[2] = ((z * mapWidth) + x) + mapWidth + 1;

			// Translate the points into two vectors
			vect1.x = vertexArray[point[0]*3] - vertexArray[point[2]*3];
			vect1.y = vertexArray[point[0]*3+1] - vertexArray[point[2]*3+1];
			vect1.z = vertexArray[point[0]*3+2] - vertexArray[point[2]*3+2];

			vect2.x = vertexArray[point[2]*3] - vertexArray[point[1]*3];
			vect2.y = vertexArray[point[2]*3+1] - vertexArray[point[1]*3+1];
			vect2.z = vertexArray[point[2]*3+2] - vertexArray[point[1]*3+2];

			// Calculate the face normal
			vect1.CrossProduct(vect2);

			// Insert the normal into the array
			tempNormal[j+1] = vect1;

			j += 2;
		}
	}


	GcVector3 sum(0.0f, 0.0f, 0.0f);
	GcVector3 zero = sum;
	int shared = 0;
	j = 0;

	// Calculate each vertex normal by averaging the face normals that that vertex share
	for(i = 0; i < mapWidth * mapWidth; i++)
	{
		for(int z = 0; z < mapWidth - 1; z++)
		{
			for(int x = 0; x < mapWidth - 1; x++)
			{
				// Find the vertex index
				point[0] = ((z * mapWidth) + x);
				point[1] = ((z * mapWidth) + x) + 1;
				point[2] = ((z * mapWidth) + x) + mapWidth;

				// How many times is it shared?
				if(point[0] == i || point[1] == i || point[2] == i)
				{
					// Add the shared normals together
					sum += tempNormal[((mapWidth - 1)*z)+x];
					shared++;
				}
			
				// Find the vertex index
				point[0] = ((z * mapWidth) + x) + 1;
				point[1] = ((z * mapWidth) + x) + mapWidth;
				point[2] = ((z * mapWidth) + x) + mapWidth + 1;

				// How many times is it shared?
				if(point[0] == i || point[1] == i || point[2] == i)
				{
					// Add the shared normals together
					sum += tempNormal[((mapWidth - 1)*z)+x+1];
					shared++;
				}
			}
		}

		// Find the vertex normal
		normal /= shared;

		// Normalize it
		normal.Normalize();

		// Save the normal in the array
		normalArray[j]	 = normal.x;

⌨️ 快捷键说明

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