Terrain: decoupled Chunk from QuadTreeNode.

actorid
scrawl 11 years ago
parent 2a4e99c069
commit 97c3efb3ba

@ -75,7 +75,7 @@ add_component_dir (translation
add_definitions(-DTERRAIN_USE_SHADER=1)
add_component_dir (terrain
quadtreenode chunk world storage material
quadtreenode chunk world storage material buffercache compositemap defs
)
add_component_dir (loadinglistener

@ -0,0 +1,200 @@
#include "buffercache.hpp"
#include <OgreHardwareBufferManager.h>
#include "defs.hpp"
namespace Terrain
{
Ogre::HardwareVertexBufferSharedPtr BufferCache::getUVBuffer()
{
if (mUvBufferMap.find(mNumVerts) != mUvBufferMap.end())
{
return mUvBufferMap[mNumVerts];
}
int vertexCount = mNumVerts * mNumVerts;
std::vector<float> uvs;
uvs.reserve(vertexCount*2);
for (unsigned int col = 0; col < mNumVerts; ++col)
{
for (unsigned int row = 0; row < mNumVerts; ++row)
{
uvs.push_back(col / static_cast<float>(mNumVerts-1)); // U
uvs.push_back(row / static_cast<float>(mNumVerts-1)); // V
}
}
Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr();
Ogre::HardwareVertexBufferSharedPtr buffer = mgr->createVertexBuffer(
Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2),
vertexCount, Ogre::HardwareBuffer::HBU_STATIC);
buffer->writeData(0, buffer->getSizeInBytes(), &uvs[0], true);
mUvBufferMap[mNumVerts] = buffer;
return buffer;
}
Ogre::HardwareIndexBufferSharedPtr BufferCache::getIndexBuffer(int flags)
{
unsigned int verts = mNumVerts;
if (mIndexBufferMap.find(flags) != mIndexBufferMap.end())
{
return mIndexBufferMap[flags];
}
// LOD level n means every 2^n-th vertex is kept
size_t lodLevel = (flags >> (4*4));
size_t lodDeltas[4];
for (int i=0; i<4; ++i)
lodDeltas[i] = (flags >> (4*i)) & (0xf);
bool anyDeltas = (lodDeltas[North] || lodDeltas[South] || lodDeltas[West] || lodDeltas[East]);
size_t increment = 1 << lodLevel;
assert(increment < verts);
std::vector<short> indices;
indices.reserve((verts-1)*(verts-1)*2*3 / increment);
size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1;
// If any edge needs stitching we'll skip all edges at this point,
// mainly because stitching one edge would have an effect on corners and on the adjacent edges
if (anyDeltas)
{
colStart += increment;
colEnd -= increment;
rowEnd -= increment;
rowStart += increment;
}
for (size_t row = rowStart; row < rowEnd; row += increment)
{
for (size_t col = colStart; col < colEnd; col += increment)
{
indices.push_back(verts*col+row);
indices.push_back(verts*(col+increment)+row+increment);
indices.push_back(verts*col+row+increment);
indices.push_back(verts*col+row);
indices.push_back(verts*(col+increment)+row);
indices.push_back(verts*(col+increment)+row+increment);
}
}
size_t innerStep = increment;
if (anyDeltas)
{
// Now configure LOD transitions at the edges - this is pretty tedious,
// and some very long and boring code, but it works great
// South
size_t row = 0;
size_t outerStep = 1 << (lodDeltas[South] + lodLevel);
for (size_t col = 0; col < verts-1; col += outerStep)
{
indices.push_back(verts*col+row);
indices.push_back(verts*(col+outerStep)+row);
// Make sure not to touch the right edge
if (col+outerStep == verts-1)
indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep);
else
indices.push_back(verts*(col+outerStep)+row+innerStep);
for (size_t i = 0; i < outerStep; i += innerStep)
{
// Make sure not to touch the left or right edges
if (col+i == 0 || col+i == verts-1-innerStep)
continue;
indices.push_back(verts*(col)+row);
indices.push_back(verts*(col+i+innerStep)+row+innerStep);
indices.push_back(verts*(col+i)+row+innerStep);
}
}
// North
row = verts-1;
outerStep = 1 << (lodDeltas[North] + lodLevel);
for (size_t col = 0; col < verts-1; col += outerStep)
{
indices.push_back(verts*(col+outerStep)+row);
indices.push_back(verts*col+row);
// Make sure not to touch the left edge
if (col == 0)
indices.push_back(verts*(col+innerStep)+row-innerStep);
else
indices.push_back(verts*col+row-innerStep);
for (size_t i = 0; i < outerStep; i += innerStep)
{
// Make sure not to touch the left or right edges
if (col+i == 0 || col+i == verts-1-innerStep)
continue;
indices.push_back(verts*(col+i)+row-innerStep);
indices.push_back(verts*(col+i+innerStep)+row-innerStep);
indices.push_back(verts*(col+outerStep)+row);
}
}
// West
size_t col = 0;
outerStep = 1 << (lodDeltas[West] + lodLevel);
for (size_t row = 0; row < verts-1; row += outerStep)
{
indices.push_back(verts*col+row+outerStep);
indices.push_back(verts*col+row);
// Make sure not to touch the top edge
if (row+outerStep == verts-1)
indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep);
else
indices.push_back(verts*(col+innerStep)+row+outerStep);
for (size_t i = 0; i < outerStep; i += innerStep)
{
// Make sure not to touch the top or bottom edges
if (row+i == 0 || row+i == verts-1-innerStep)
continue;
indices.push_back(verts*col+row);
indices.push_back(verts*(col+innerStep)+row+i);
indices.push_back(verts*(col+innerStep)+row+i+innerStep);
}
}
// East
col = verts-1;
outerStep = 1 << (lodDeltas[East] + lodLevel);
for (size_t row = 0; row < verts-1; row += outerStep)
{
indices.push_back(verts*col+row);
indices.push_back(verts*col+row+outerStep);
// Make sure not to touch the bottom edge
if (row == 0)
indices.push_back(verts*(col-innerStep)+row+innerStep);
else
indices.push_back(verts*(col-innerStep)+row);
for (size_t i = 0; i < outerStep; i += innerStep)
{
// Make sure not to touch the top or bottom edges
if (row+i == 0 || row+i == verts-1-innerStep)
continue;
indices.push_back(verts*col+row+outerStep);
indices.push_back(verts*(col-innerStep)+row+i+innerStep);
indices.push_back(verts*(col-innerStep)+row+i);
}
}
}
Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr();
Ogre::HardwareIndexBufferSharedPtr buffer = mgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT,
indices.size(), Ogre::HardwareBuffer::HBU_STATIC);
buffer->writeData(0, buffer->getSizeInBytes(), &indices[0], true);
mIndexBufferMap[flags] = buffer;
return buffer;
}
}

@ -0,0 +1,36 @@
#ifndef COMPONENTS_TERRAIN_BUFFERCACHE_H
#define COMPONENTS_TERRAIN_BUFFERCACHE_H
#include <OgreHardwareIndexBuffer.h>
#include <OgreHardwareVertexBuffer.h>
#include <map>
namespace Terrain
{
/// @brief Implements creation and caching of vertex buffers for terrain chunks.
class BufferCache
{
public:
BufferCache(unsigned int numVerts) : mNumVerts(numVerts) {}
/// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each)
/// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices)
Ogre::HardwareIndexBufferSharedPtr getIndexBuffer (int flags);
Ogre::HardwareVertexBufferSharedPtr getUVBuffer ();
private:
// Index buffers are shared across terrain batches where possible. There is one index buffer for each
// combination of LOD deltas and index buffer LOD we may need.
std::map<int, Ogre::HardwareIndexBufferSharedPtr> mIndexBufferMap;
std::map<int, Ogre::HardwareVertexBufferSharedPtr> mUvBufferMap;
unsigned int mNumVerts;
};
}
#endif

@ -4,31 +4,17 @@
#include <OgreHardwareBufferManager.h>
#include <OgreRenderQueue.h>
#include "quadtreenode.hpp"
#include "world.hpp"
#include "storage.hpp"
#include "world.hpp" // FIXME: for LoadResponseData, move to backgroundloader.hpp
namespace Terrain
{
Chunk::Chunk(QuadTreeNode* node, const LoadResponseData& data)
: mNode(node)
, mVertexLod(node->getNativeLodLevel())
, mAdditionalLod(0)
Chunk::Chunk(Ogre::HardwareVertexBufferSharedPtr uvBuffer, const Ogre::AxisAlignedBox& bounds, const LoadResponseData& data)
: mBounds(bounds)
{
mVertexData = OGRE_NEW Ogre::VertexData;
mVertexData->vertexStart = 0;
unsigned int verts = mNode->getTerrain()->getStorage()->getCellVertices();
size_t lodLevel = mNode->getNativeLodLevel();
// Set the total number of vertices
size_t numVertsOneSide = mNode->getSize() * (verts-1);
numVertsOneSide /= 1 << lodLevel;
numVertsOneSide += 1;
assert(numVertsOneSide == verts);
mVertexData->vertexCount = numVertsOneSide * numVertsOneSide;
mVertexData->vertexCount = data.mPositions.size()/3;
// Set up the vertex declaration, which specifies the info for each vertex (normals, colors, UVs, etc)
Ogre::VertexDeclaration* vertexDecl = mVertexData->vertexDeclaration;
@ -40,15 +26,16 @@ namespace Terrain
vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT3, Ogre::VES_POSITION);
mVertexBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC);
// Normals
vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT3, Ogre::VES_NORMAL);
mNormalBuffer = mgr->createVertexBuffer(Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT3),
mVertexData->vertexCount, Ogre::HardwareBuffer::HBU_STATIC);
// UV texture coordinates
vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_FLOAT2,
Ogre::VES_TEXTURE_COORDINATES, 0);
Ogre::HardwareVertexBufferSharedPtr uvBuf = mNode->getTerrain()->getVertexBuffer(numVertsOneSide);
// Colours
vertexDecl->addElement(nextBuffer++, 0, Ogre::VET_COLOUR, Ogre::VES_DIFFUSE);
@ -61,54 +48,17 @@ namespace Terrain
mVertexData->vertexBufferBinding->setBinding(0, mVertexBuffer);
mVertexData->vertexBufferBinding->setBinding(1, mNormalBuffer);
mVertexData->vertexBufferBinding->setBinding(2, uvBuf);
mVertexData->vertexBufferBinding->setBinding(2, uvBuffer);
mVertexData->vertexBufferBinding->setBinding(3, mColourBuffer);
mIndexData = OGRE_NEW Ogre::IndexData();
mIndexData->indexStart = 0;
}
void Chunk::updateIndexBuffer()
void Chunk::setIndexBuffer(Ogre::HardwareIndexBufferSharedPtr buffer)
{
// Fetch a suitable index buffer (which may be shared)
size_t ourLod = mVertexLod + mAdditionalLod;
int flags = 0;
for (int i=0; i<4; ++i)
{
QuadTreeNode* neighbour = mNode->getNeighbour((Direction)i);
// If the neighbour isn't currently rendering itself,
// go up until we find one. NOTE: We don't need to go down,
// because in that case neighbour's detail would be higher than
// our detail and the neighbour would handle stitching by itself.
while (neighbour && !neighbour->hasChunk())
neighbour = neighbour->getParent();
size_t lod = 0;
if (neighbour)
lod = neighbour->getActualLodLevel();
if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are -
lod = 0; // neighbours with more detail will do the stitching themselves
// Use 4 bits for each LOD delta
if (lod > 0)
{
assert (lod - ourLod < (1 << 4));
flags |= int(lod - ourLod) << (4*i);
}
}
flags |= ((int)mAdditionalLod) << (4*4);
size_t numIndices;
mIndexBuffer = mNode->getTerrain()->getIndexBuffer(flags, numIndices);
mIndexData->indexCount = numIndices;
mIndexData->indexBuffer = mIndexBuffer;
mIndexData->indexBuffer = buffer;
mIndexData->indexCount = buffer->getNumIndexes();
}
Chunk::~Chunk()
@ -124,12 +74,12 @@ namespace Terrain
const Ogre::AxisAlignedBox& Chunk::getBoundingBox(void) const
{
return mNode->getBoundingBox();
return mBounds;
}
Ogre::Real Chunk::getBoundingRadius(void) const
{
return mNode->getBoundingBox().getHalfSize().length();
return mBounds.getHalfSize().length();
}
void Chunk::_updateRenderQueue(Ogre::RenderQueue* queue)
@ -150,7 +100,7 @@ namespace Terrain
void Chunk::getRenderOperation(Ogre::RenderOperation& op)
{
assert (!mIndexBuffer.isNull() && "Trying to render, but no index buffer set!");
assert (!mIndexData->indexBuffer.isNull() && "Trying to render, but no index buffer set!");
op.useIndexes = true;
op.operationType = Ogre::RenderOperation::OT_TRIANGLE_LIST;
op.vertexData = mVertexData;

@ -7,7 +7,7 @@
namespace Terrain
{
class QuadTreeNode;
class BufferCache;
struct LoadResponseData;
/**
@ -16,18 +16,13 @@ namespace Terrain
class Chunk : public Ogre::Renderable, public Ogre::MovableObject
{
public:
Chunk (QuadTreeNode* node, const LoadResponseData& data);
Chunk (Ogre::HardwareVertexBufferSharedPtr uvBuffer, const Ogre::AxisAlignedBox& bounds, const LoadResponseData& data);
virtual ~Chunk();
void setMaterial (const Ogre::MaterialPtr& material);
/// Set additional LOD applied on top of vertex LOD. \n
/// This is achieved by changing the index buffer to omit vertices.
void setAdditionalLod (size_t lod) { mAdditionalLod = lod; }
size_t getAdditionalLod() { return mAdditionalLod; }
void updateIndexBuffer();
void setIndexBuffer(Ogre::HardwareIndexBufferSharedPtr buffer);
// Inherited from MovableObject
virtual const Ogre::String& getMovableType(void) const { static Ogre::String t = "MW_TERRAIN"; return t; }
@ -45,18 +40,14 @@ namespace Terrain
virtual const Ogre::LightList& getLights(void) const;
private:
QuadTreeNode* mNode;
Ogre::AxisAlignedBox mBounds;
Ogre::MaterialPtr mMaterial;
size_t mVertexLod;
size_t mAdditionalLod;
Ogre::VertexData* mVertexData;
Ogre::IndexData* mIndexData;
Ogre::HardwareVertexBufferSharedPtr mVertexBuffer;
Ogre::HardwareVertexBufferSharedPtr mNormalBuffer;
Ogre::HardwareVertexBufferSharedPtr mColourBuffer;
Ogre::HardwareIndexBufferSharedPtr mIndexBuffer;
};
}

@ -36,6 +36,14 @@ namespace Terrain
}
}
enum Direction
{
North = 0,
East = 1,
South = 2,
West = 3
};
struct LayerInfo
{
std::string mDiffuseMap;

@ -9,7 +9,7 @@
#include "world.hpp"
#include "chunk.hpp"
#include "storage.hpp"
#include "buffercache.hpp"
#include "material.hpp"
using namespace Terrain;
@ -372,7 +372,7 @@ void QuadTreeNode::load(const LoadResponseData &data)
assert (!mChunk);
std::cout << "loading " << std::endl;
mChunk = new Chunk(this, data);
mChunk = new Chunk(mTerrain->getBufferCache().getUVBuffer(), mBounds, data);
mChunk->setVisibilityFlags(mTerrain->getVisiblityFlags());
mChunk->setCastShadows(true);
mSceneNode->attachObject(mChunk);
@ -429,7 +429,38 @@ void QuadTreeNode::unload()
void QuadTreeNode::updateIndexBuffers()
{
if (hasChunk())
mChunk->updateIndexBuffer();
{
// Fetch a suitable index buffer (which may be shared)
size_t ourLod = getActualLodLevel();
int flags = 0;
for (int i=0; i<4; ++i)
{
QuadTreeNode* neighbour = getNeighbour((Direction)i);
// If the neighbour isn't currently rendering itself,
// go up until we find one. NOTE: We don't need to go down,
// because in that case neighbour's detail would be higher than
// our detail and the neighbour would handle stitching by itself.
while (neighbour && !neighbour->hasChunk())
neighbour = neighbour->getParent();
size_t lod = 0;
if (neighbour)
lod = neighbour->getActualLodLevel();
if (lod <= ourLod) // We only need to worry about neighbours less detailed than we are -
lod = 0; // neighbours with more detail will do the stitching themselves
// Use 4 bits for each LOD delta
if (lod > 0)
{
assert (lod - ourLod < (1 << 4));
flags |= int(lod - ourLod) << (4*i);
}
}
flags |= 0 /*((int)mAdditionalLod)*/ << (4*4);
mChunk->setIndexBuffer(mTerrain->getBufferCache().getIndexBuffer(flags));
}
else if (hasChildren())
{
for (int i=0; i<4; ++i)
@ -445,7 +476,7 @@ bool QuadTreeNode::hasChunk()
size_t QuadTreeNode::getActualLodLevel()
{
assert(hasChunk() && "Can't get actual LOD level if this node has no render chunk");
return mLodLevel + mChunk->getAdditionalLod();
return mLodLevel /* + mChunk->getAdditionalLod() */;
}
void QuadTreeNode::ensureLayerInfo()

@ -5,6 +5,8 @@
#include <OgreVector2.h>
#include <OgreTexture.h>
#include "defs.hpp"
namespace Ogre
{
class Rectangle2D;
@ -17,14 +19,6 @@ namespace Terrain
class MaterialGenerator;
struct LoadResponseData;
enum Direction
{
North = 0,
East = 1,
South = 2,
West = 3
};
enum ChildDirection
{
NW = 0,

@ -2,7 +2,6 @@
#include <OgreAxisAlignedBox.h>
#include <OgreCamera.h>
#include <OgreHardwareBufferManager.h>
#include <OgreHardwarePixelBuffer.h>
#include <OgreTextureManager.h>
#include <OgreRenderTexture.h>
@ -70,6 +69,7 @@ namespace Terrain
, mMinY(0)
, mChunksLoading(0)
, mWorkQueueChannel(0)
, mCache(storage->getCellVertices())
{
#if TERRAIN_USE_SHADER == 0
if (mShaders)
@ -197,201 +197,6 @@ namespace Terrain
return node->getWorldBoundingBox();
}
Ogre::HardwareVertexBufferSharedPtr World::getVertexBuffer(int numVertsOneSide)
{
if (mUvBufferMap.find(numVertsOneSide) != mUvBufferMap.end())
{
return mUvBufferMap[numVertsOneSide];
}
int vertexCount = numVertsOneSide * numVertsOneSide;
std::vector<float> uvs;
uvs.reserve(vertexCount*2);
for (int col = 0; col < numVertsOneSide; ++col)
{
for (int row = 0; row < numVertsOneSide; ++row)
{
uvs.push_back(col / static_cast<float>(numVertsOneSide-1)); // U
uvs.push_back(row / static_cast<float>(numVertsOneSide-1)); // V
}
}
Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr();
Ogre::HardwareVertexBufferSharedPtr buffer = mgr->createVertexBuffer(
Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2),
vertexCount, Ogre::HardwareBuffer::HBU_STATIC);
buffer->writeData(0, buffer->getSizeInBytes(), &uvs[0], true);
mUvBufferMap[numVertsOneSide] = buffer;
return buffer;
}
Ogre::HardwareIndexBufferSharedPtr World::getIndexBuffer(int flags, size_t& numIndices)
{
unsigned int verts = mStorage->getCellVertices();
if (mIndexBufferMap.find(flags) != mIndexBufferMap.end())
{
numIndices = mIndexBufferMap[flags]->getNumIndexes();
return mIndexBufferMap[flags];
}
// LOD level n means every 2^n-th vertex is kept
size_t lodLevel = (flags >> (4*4));
size_t lodDeltas[4];
for (int i=0; i<4; ++i)
lodDeltas[i] = (flags >> (4*i)) & (0xf);
bool anyDeltas = (lodDeltas[North] || lodDeltas[South] || lodDeltas[West] || lodDeltas[East]);
size_t increment = 1 << lodLevel;
assert(increment < verts);
std::vector<short> indices;
indices.reserve((verts-1)*(verts-1)*2*3 / increment);
size_t rowStart = 0, colStart = 0, rowEnd = verts-1, colEnd = verts-1;
// If any edge needs stitching we'll skip all edges at this point,
// mainly because stitching one edge would have an effect on corners and on the adjacent edges
if (anyDeltas)
{
colStart += increment;
colEnd -= increment;
rowEnd -= increment;
rowStart += increment;
}
for (size_t row = rowStart; row < rowEnd; row += increment)
{
for (size_t col = colStart; col < colEnd; col += increment)
{
indices.push_back(verts*col+row);
indices.push_back(verts*(col+increment)+row+increment);
indices.push_back(verts*col+row+increment);
indices.push_back(verts*col+row);
indices.push_back(verts*(col+increment)+row);
indices.push_back(verts*(col+increment)+row+increment);
}
}
size_t innerStep = increment;
if (anyDeltas)
{
// Now configure LOD transitions at the edges - this is pretty tedious,
// and some very long and boring code, but it works great
// South
size_t row = 0;
size_t outerStep = 1 << (lodDeltas[South] + lodLevel);
for (size_t col = 0; col < verts-1; col += outerStep)
{
indices.push_back(verts*col+row);
indices.push_back(verts*(col+outerStep)+row);
// Make sure not to touch the right edge
if (col+outerStep == verts-1)
indices.push_back(verts*(col+outerStep-innerStep)+row+innerStep);
else
indices.push_back(verts*(col+outerStep)+row+innerStep);
for (size_t i = 0; i < outerStep; i += innerStep)
{
// Make sure not to touch the left or right edges
if (col+i == 0 || col+i == verts-1-innerStep)
continue;
indices.push_back(verts*(col)+row);
indices.push_back(verts*(col+i+innerStep)+row+innerStep);
indices.push_back(verts*(col+i)+row+innerStep);
}
}
// North
row = verts-1;
outerStep = 1 << (lodDeltas[North] + lodLevel);
for (size_t col = 0; col < verts-1; col += outerStep)
{
indices.push_back(verts*(col+outerStep)+row);
indices.push_back(verts*col+row);
// Make sure not to touch the left edge
if (col == 0)
indices.push_back(verts*(col+innerStep)+row-innerStep);
else
indices.push_back(verts*col+row-innerStep);
for (size_t i = 0; i < outerStep; i += innerStep)
{
// Make sure not to touch the left or right edges
if (col+i == 0 || col+i == verts-1-innerStep)
continue;
indices.push_back(verts*(col+i)+row-innerStep);
indices.push_back(verts*(col+i+innerStep)+row-innerStep);
indices.push_back(verts*(col+outerStep)+row);
}
}
// West
size_t col = 0;
outerStep = 1 << (lodDeltas[West] + lodLevel);
for (size_t row = 0; row < verts-1; row += outerStep)
{
indices.push_back(verts*col+row+outerStep);
indices.push_back(verts*col+row);
// Make sure not to touch the top edge
if (row+outerStep == verts-1)
indices.push_back(verts*(col+innerStep)+row+outerStep-innerStep);
else
indices.push_back(verts*(col+innerStep)+row+outerStep);
for (size_t i = 0; i < outerStep; i += innerStep)
{
// Make sure not to touch the top or bottom edges
if (row+i == 0 || row+i == verts-1-innerStep)
continue;
indices.push_back(verts*col+row);
indices.push_back(verts*(col+innerStep)+row+i);
indices.push_back(verts*(col+innerStep)+row+i+innerStep);
}
}
// East
col = verts-1;
outerStep = 1 << (lodDeltas[East] + lodLevel);
for (size_t row = 0; row < verts-1; row += outerStep)
{
indices.push_back(verts*col+row);
indices.push_back(verts*col+row+outerStep);
// Make sure not to touch the bottom edge
if (row == 0)
indices.push_back(verts*(col-innerStep)+row+innerStep);
else
indices.push_back(verts*(col-innerStep)+row);
for (size_t i = 0; i < outerStep; i += innerStep)
{
// Make sure not to touch the top or bottom edges
if (row+i == 0 || row+i == verts-1-innerStep)
continue;
indices.push_back(verts*col+row+outerStep);
indices.push_back(verts*(col-innerStep)+row+i+innerStep);
indices.push_back(verts*(col-innerStep)+row+i);
}
}
}
numIndices = indices.size();
Ogre::HardwareBufferManager* mgr = Ogre::HardwareBufferManager::getSingletonPtr();
Ogre::HardwareIndexBufferSharedPtr buffer = mgr->createIndexBuffer(Ogre::HardwareIndexBuffer::IT_16BIT,
numIndices, Ogre::HardwareBuffer::HBU_STATIC);
buffer->writeData(0, buffer->getSizeInBytes(), &indices[0], true);
mIndexBufferMap[flags] = buffer;
return buffer;
}
void World::renderCompositeMap(Ogre::TexturePtr target)
{
mCompositeMapRenderTarget->update();

@ -1,13 +1,12 @@
#ifndef COMPONENTS_TERRAIN_H
#define COMPONENTS_TERRAIN_H
#include <OgreHardwareIndexBuffer.h>
#include <OgreHardwareVertexBuffer.h>
#include <OgreAxisAlignedBox.h>
#include <OgreTexture.h>
#include <OgreWorkQueue.h>
#include "defs.hpp"
#include "buffercache.hpp"
namespace Ogre
{
@ -125,25 +124,12 @@ namespace Terrain
void buildQuadTree(QuadTreeNode* node);
BufferCache mCache;
public:
// ----INTERNAL----
enum IndexBufferFlags
{
IBF_North = 1 << 0,
IBF_East = 1 << 1,
IBF_South = 1 << 2,
IBF_West = 1 << 3
};
/// @param flags first 4*4 bits are LOD deltas on each edge, respectively (4 bits each)
/// next 4 bits are LOD level of the index buffer (LOD 0 = don't omit any vertices)
/// @param numIndices number of indices that were used will be written here
Ogre::HardwareIndexBufferSharedPtr getIndexBuffer (int flags, size_t& numIndices);
Ogre::HardwareVertexBufferSharedPtr getVertexBuffer (int numVertsOneSide);
Ogre::SceneManager* getCompositeMapSceneManager() { return mCompositeMapSceneMgr; }
BufferCache& getBufferCache() { return mCache; }
// Delete all quads
void clearCompositeMapSceneManager();
@ -158,12 +144,6 @@ namespace Terrain
void queueLoad (QuadTreeNode* node);
private:
// Index buffers are shared across terrain batches where possible. There is one index buffer for each
// combination of LOD deltas and index buffer LOD we may need.
std::map<int, Ogre::HardwareIndexBufferSharedPtr> mIndexBufferMap;
std::map<int, Ogre::HardwareVertexBufferSharedPtr> mUvBufferMap;
Ogre::RenderTarget* mCompositeMapRenderTarget;
Ogre::TexturePtr mCompositeMapRenderTexture;
};

Loading…
Cancel
Save