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

📄 natureterrainpatch.cpp

📁 使用stl技术,(还没看,是听说的)
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*****************************************************************************

	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 + -