📄 terrain.cpp
字号:
#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 + -