📄 natureterrainpatch.cpp
字号:
/*****************************************************************************
File: NatureTerrainPatch.cpp
Desc: A block ot terrain generated from a heightmap
Date: 2003/02/22
Author: Martin Persson
*****************************************************************************/
#include <iostream>
#include <OgreCamera.h>
#include "NatureTerrainPatch.h"
namespace Ogre
{
//----------------------------------------------------------------------------
NatureTerrainPatch::NatureTerrainPatch()
: NaturePatch(),
mVertexData(0),
mIndexData(0)
{
memset(mQuadTree, 0, sizeof(QuadTreeNode) * QUADTREE_NODES);
mNeedRendering = false;
mDistance = 500.0f;
mColourCache = 0;
mVertexCount = 0;
mIndexCount = 0;
}
//----------------------------------------------------------------------------
NatureTerrainPatch::~NatureTerrainPatch()
{
freeCaches();
}
//----------------------------------------------------------------------------
void NatureTerrainPatch::freeCaches()
{
if (mVertexData)
{
delete mVertexData;
mVertexData = 0;
}
if (mIndexData)
{
delete mIndexData;
mIndexData = 0;
}
if (mColourCache != 0)
{
delete[] mColourCache;
mColourCache = 0;
}
}
//----------------------------------------------------------------------------
bool NatureTerrainPatch::initialise(Vector3 world, Vector3 zone,
Vector3 scale, NaturePatchData *data)
{
// setup pointer to NaturePatchManager
mManager = &NaturePatchManager::getSingleton();
// setup pointer to elevation data
mHeight = data->terrain.pHeightMap;
mMaterial = data->terrain.pMaterial;
// setup world position and scaling info
mWorld = world;
mZone = zone;
mScale = scale;
// save patch data structure
mData = data;
// set bounding box extents, TODO: fix this so y gets set correctly
mBounds.setExtents(mWorld.x * mScale.x,
mWorld.y,
mWorld.z * mScale.z,
mWorld.x * mScale.x + EDGE_LENGTH * mScale.x,
mWorld.y + 255 * mScale.y, // wrong
mWorld.z * mScale.z + EDGE_LENGTH * mScale.z);
// calculate errors for the quadtree
computeError();
return true;
}
//----------------------------------------------------------------------------
int NatureTerrainPatch::calculateError(int cx, int cz, int width)
{
int xAdd = (width >> 1);
int zAdd = (width >> 1) * mData->terrain.heightMapWidth;
// calculate index of center vertex
int cIdx = cz * mData->terrain.heightMapWidth + cx;
int nIdx = cIdx - zAdd; // index of north vertex
int sIdx = cIdx + zAdd; // index of south vertex
int wIdx = cIdx - xAdd; // index of west vertex
int eIdx = cIdx + xAdd; // index of east vertex
int nwIdx = nIdx - xAdd; // index of northwest vertex
int neIdx = nIdx + xAdd; // index of northeast vertex
int swIdx = sIdx - xAdd; // index of southwest vertex
int seIdx = sIdx + xAdd; // index of southeast vertex
int e1, e2;
// north error
e1 = abs((mHeight[nIdx] - ((mHeight[nwIdx] + mHeight[neIdx]) >> 1)));
// south error
e2 = abs((mHeight[sIdx] - ((mHeight[swIdx] + mHeight[seIdx]) >> 1)));
if (e1 < e2) e1 = e2;
// west error
e2 = abs((mHeight[wIdx] - ((mHeight[nwIdx] + mHeight[swIdx]) >> 1)));
if (e1 < e2) e1 = e2;
// east error
e2 = abs((mHeight[eIdx] - ((mHeight[neIdx] + mHeight[seIdx]) >> 1)));
if (e1 < e2) e1 = e2;
// diagonal 1 error
e2 = abs((mHeight[cIdx] - ((mHeight[nwIdx] + mHeight[seIdx]) >> 1)));
if (e1 < e2) e1 = e2;
// diagonal 2 error
e2 = abs((mHeight[cIdx] - ((mHeight[neIdx] + mHeight[swIdx]) >> 1)));
if (e1 < e2) e1 = e2;
// clamp value to [0..127]
if (e1 > 127) return 127;
// return max error
return e1;
}
//----------------------------------------------------------------------------
void NatureTerrainPatch::prepareMesh()
{
if (!mNeedRendering)
{
for (int q = 0; q < QUADTREE_NODES; q++)
mQuadTree[q].disable();
triangulate(EDGE_LENGTH / 2, EDGE_LENGTH / 2, 0, 0);
mNeedRendering = true;
}
}
//----------------------------------------------------------------------------
void NatureTerrainPatch::generateMesh()
{
if (mNeedRendering)
{
// prepare for rendering
mManager->clearVertexLookup();
mVertexCount = 0;
mIndexCount = 0;
// free any previous caches
freeCaches();
render(EDGE_LENGTH / 2, EDGE_LENGTH / 2, 0, 0);
mVertexData = new VertexData;
mVertexData->vertexStart = 0;
mVertexData->vertexCount = mVertexCount;
VertexDeclaration* decl = mVertexData->vertexDeclaration;
VertexBufferBinding* bind = mVertexData->vertexBufferBinding;
size_t offset = 0;
// positions
decl->addElement(0, offset, VET_FLOAT3, VES_POSITION);
offset += VertexElement::getTypeSize(VET_FLOAT3);
#if USE_NORMALS
// normals
decl->addElement(0, offset, VET_FLOAT3, VES_NORMAL);
offset += VertexElement::getTypeSize(VET_FLOAT3);
#endif
#if USE_TEXTURES
// texture coord sets
decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 0);
offset += VertexElement::getTypeSize(VET_FLOAT2);
decl->addElement(0, offset, VET_FLOAT2, VES_TEXTURE_COORDINATES, 1);
offset += VertexElement::getTypeSize(VET_FLOAT2);
#endif
#if USE_COLOURS
// update colours
decl->addElement(1, 0, VET_COLOUR, VES_DIFFUSE);
#endif
HardwareVertexBufferSharedPtr vbuf =
HardwareBufferManager::getSingleton().createVertexBuffer(
offset,
mVertexData->vertexCount,
HardwareBuffer::HBU_STATIC_WRITE_ONLY);
bind->setBinding(0, vbuf);
// update buffer
vbuf->writeData(0, vbuf->getSizeInBytes(), mManager->mDataBuffer);
#if USE_COLOURS
/* TODO
// update colours
mColourCache = new unsigned long[mVertexCount];
// TODO: fix colours... this is just a test
for (int i = 0; i < mVertexCount; i++)
{
int h = static_cast<int>(mVertexCache[(i * 3) + 1] / mScale.y);
if (h > 120)
mColourCache[i] = 0xffffffff;
else if (h > 80)
mColourCache[i] = 0x00ffffff;
else
mColourCache[i] = 0x00000000;
}
*/
#endif
mIndexData = new IndexData;
mIndexData->indexStart = 0;
mIndexData->indexCount = mIndexCount;
mIndexData->indexBuffer =
HardwareBufferManager::getSingleton().createIndexBuffer(
HardwareIndexBuffer::IT_16BIT,
mIndexData->indexCount,
HardwareBuffer::HBU_STATIC_WRITE_ONLY);
// update index buffer
mIndexData->indexBuffer->writeData(0,
mIndexData->indexBuffer->getSizeInBytes(), mManager->mIndexBuffer);
mNeedRendering = false;
}
// saveASC(mVertexCount * 3, mIndexCount);
}
//----------------------------------------------------------------------------
#if 0
// simple, non-seaming version
void NatureTerrainPatch::renderQuad(int cx, int cz, int node, int width)
{
int w2 = (width >> 1), v[6];
int cIdx = cz * mData->heightMapWidth + cx;
int xAdd = w2;
int zAdd = w2 * mData->heightMapWidth;
ushort *indexBuffer = &mManager->mIndexBuffer[mIndexCount];
// add the base vertices
v[1] = addVertex(cx - w2, mHeight[cIdx - xAdd - zAdd], cz - w2);
v[2] = addVertex(cx + w2, mHeight[cIdx + xAdd - zAdd], cz - w2);
v[3] = addVertex(cx - w2, mHeight[cIdx - xAdd + zAdd], cz + w2);
v[4] = addVertex(cx + w2, mHeight[cIdx + xAdd + zAdd], cz + w2);
// figure out which vertices to draw, TODO: check width > 2
if (width > 2 || mQuadTree[node].isEnabled())
{
int neighbor;
// add the center vertex
v[0] = addVertex(cx, mHeight[cIdx], cz);
// render north triangles
neighbor = mManager->mNorthNeighbor[node];
if (neighbor > 0 && mQuadTree[neighbor].isEnabled())
{
v[5] = addVertex(cx, mHeight[cIdx - zAdd], cz - w2);
*indexBuffer++ = v[2];
*indexBuffer++ = v[5];
*indexBuffer++ = v[0];
*indexBuffer++ = v[5];
*indexBuffer++ = v[1];
*indexBuffer++ = v[0];
}
else if
{
*indexBuffer++ = v[2];
*indexBuffer++ = v[1];
*indexBuffer++ = v[0];
}
// render south triangles
neighbor = mManager->mSouthNeighbor[node];
if (neighbor > 0 && mQuadTree[neighbor].isEnabled())
{
v[5] = addVertex(cx, mHeight[cIdx + zAdd], cz + w2);
*indexBuffer++ = v[3];
*indexBuffer++ = v[5];
*indexBuffer++ = v[0];
*indexBuffer++ = v[5];
*indexBuffer++ = v[4];
*indexBuffer++ = v[0];
}
else if
{
*indexBuffer++ = v[3];
*indexBuffer++ = v[4];
*indexBuffer++ = v[0];
}
// render west triangles
neighbor = mManager->mWestNeighbor[node];
if (neighbor > 0 && mQuadTree[neighbor].isEnabled())
{
v[5] = addVertex(cx - w2, mHeight[cIdx - xAdd], cz);
*indexBuffer++ = v[1];
*indexBuffer++ = v[5];
*indexBuffer++ = v[0];
*indexBuffer++ = v[5];
*indexBuffer++ = v[3];
*indexBuffer++ = v[0];
}
else if
{
*indexBuffer++ = v[1];
*indexBuffer++ = v[3];
*indexBuffer++ = v[0];
}
// render east triangles
neighbor = mManager->mEastNeighbor[node];
if (neighbor > 0 && mQuadTree[neighbor].isEnabled())
{
v[5] = addVertex(cx + w2, mHeight[cIdx + xAdd], cz);
*indexBuffer++ = v[4];
*indexBuffer++ = v[5];
*indexBuffer++ = v[0];
*indexBuffer++ = v[5];
*indexBuffer++ = v[2];
*indexBuffer++ = v[0];
}
else if
{
*indexBuffer++ = v[4];
*indexBuffer++ = v[2];
*indexBuffer++ = v[0];
}
}
else // quad disabled, just render 2 tri's
{
// find how we should draw the diagonal
int child = (node - 1) & 0x03;
if (child == 0 || child == 3)
{
*indexBuffer++ = v[2];
*indexBuffer++ = v[1];
*indexBuffer++ = v[4];
*indexBuffer++ = v[1];
*indexBuffer++ = v[3];
*indexBuffer++ = v[4];
}
else
{
*indexBuffer++ = v[2];
*indexBuffer++ = v[1];
*indexBuffer++ = v[3];
*indexBuffer++ = v[3];
*indexBuffer++ = v[4];
*indexBuffer++ = v[2];
}
}
// update index counter
mIndexCount += (indexBuffer - (&mManager->mIndexBuffer[mIndexCount]));
}
#endif
//----------------------------------------------------------------------------
void NatureTerrainPatch::renderQuad(int cx, int cz, int node, int width)
{
int w2 = (width >> 1), v[6];
int cIdx = cz * mData->terrain.heightMapWidth + cx;
int xAdd = w2;
int zAdd = w2 * mData->terrain.heightMapWidth;
ushort *indexBuffer = &mManager->mIndexBuffer[mIndexCount];
// add the base vertices
v[1] = addVertex(cx - w2, mHeight[cIdx - xAdd - zAdd], cz - w2);
v[2] = addVertex(cx + w2, mHeight[cIdx + xAdd - zAdd], cz - w2);
v[3] = addVertex(cx - w2, mHeight[cIdx - xAdd + zAdd], cz + w2);
v[4] = addVertex(cx + w2, mHeight[cIdx + xAdd + zAdd], cz + w2);
// figure out which vertices to draw, TODO: check width > 2
if (width > 2 || mQuadTree[node].isEnabled())
{
int neighbor;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -