DynamicGrowingBuffers
From Ogre Wiki
From DWORD: I don't know if this can help you, but I once wrote a DynamicRenderable class derived from SimpleRenderable. It provides mechanisms to allow for dynamically growing hardware buffers. Simply put, you tell on update how many vertices/indices you want, and it reallocates the buffers (only) if necessary. It's quite flexible, as you can create your own vertex declaration etc.
From baxissimo: The original version posted here was unable to decrease the capacity of the buffers, but I have edited it to now automatically decrease the size when there's excessive capacity. I also posted a "dynamic line drawing example" implemented as a subclass of this.
Here we go:
DynamicRenderable.h
#ifndef DYNAMIC_RENDERABLE_H
#define DYNAMIC_RENDERABLE_H
#include <OgreSimpleRenderable.h>
/// Abstract base class providing mechanisms for dynamically growing hardware buffers.
class DynamicRenderable : public Ogre::SimpleRenderable
{
public:
/// Constructor
DynamicRenderable();
/// Virtual destructor
virtual ~DynamicRenderable();
/** Initializes the dynamic renderable.
@remarks
This function should only be called once. It initializes the
render operation, and calls the abstract function
createVertexDeclaration().
@param operationType The type of render operation to perform.
@param useIndices Specifies whether to use indices to determine the
vertices to use as input. */
void initialize(Ogre::RenderOperation::OperationType operationType,
bool useIndices);
/// Implementation of Ogre::SimpleRenderable
virtual Ogre::Real getBoundingRadius(void) const;
/// Implementation of Ogre::SimpleRenderable
virtual Ogre::Real getSquaredViewDepth(const Ogre::Camera* cam) const;
protected:
/// Maximum capacity of the currently allocated vertex buffer.
size_t mVertexBufferCapacity;
/// Maximum capacity of the currently allocated index buffer.
size_t mIndexBufferCapacity;
/** Creates the vertex declaration.
@remarks
Override and set mRenderOp.vertexData->vertexDeclaration here.
mRenderOp.vertexData will be created for you before this method
is called. */
virtual void createVertexDeclaration() = 0;
/** Prepares the hardware buffers for the requested vertex and index counts.
@remarks
This function must be called before locking the buffers in
fillHardwareBuffers(). It guarantees that the hardware buffers
are large enough to hold at least the requested number of
vertices and indices (if using indices). The buffers are
possibly reallocated to achieve this.
@par
The vertex and index count in the render operation are set to
the values of vertexCount and indexCount respectively.
@param vertexCount The number of vertices the buffer must hold.
@param indexCount The number of indices the buffer must hold. This
parameter is ignored if not using indices. */
void prepareHardwareBuffers(size_t vertexCount, size_t indexCount);
/** Fills the hardware vertex and index buffers with data.
@remarks
This function must call prepareHardwareBuffers() before locking
the buffers to ensure the they are large enough for the data to
be written. Afterwards the vertex and index buffers (if using
indices) can be locked, and data can be written to them. */
virtual void fillHardwareBuffers() = 0;
};
#endif // DYNAMIC_RENDERABLE_H
DynamicRenderable.cpp
#include "DynamicRenderable.h"
#include <OgreCamera.h>
#include <OgreHardwareBufferManager.h>
using namespace Ogre;
DynamicRenderable::DynamicRenderable()
{
}
DynamicRenderable::~DynamicRenderable()
{
delete mRenderOp.vertexData;
delete mRenderOp.indexData;
}
void DynamicRenderable::initialize(RenderOperation::OperationType operationType,
bool useIndices)
{
// Initialize render operation
mRenderOp.operationType = operationType;
mRenderOp.useIndexes = useIndices;
mRenderOp.vertexData = new VertexData;
if (mRenderOp.useIndexes)
mRenderOp.indexData = new IndexData;
// Reset buffer capacities
mVertexBufferCapacity = 0;
mIndexBufferCapacity = 0;
// Create vertex declaration
createVertexDeclaration();
}
void DynamicRenderable::prepareHardwareBuffers(size_t vertexCount,
size_t indexCount)
{
// Prepare vertex buffer
size_t newVertCapacity = mVertexBufferCapacity;
if ((vertexCount > mVertexBufferCapacity) ||
(!mVertexBufferCapacity))
{
// vertexCount exceeds current capacity!
// It is necessary to reallocate the buffer.
// Check if this is the first call
if (!newVertCapacity)
newVertCapacity = 1;
// Make capacity the next power of two
while (newVertCapacity < vertexCount)
newVertCapacity <<= 1;
}
else if (vertexCount < mVertexBufferCapacity>>1) {
// Make capacity the previous power of two
while (vertexCount < newVertCapacity>>1)
newVertCapacity >>= 1;
}
if (newVertCapacity != mVertexBufferCapacity)
{
mVertexBufferCapacity = newVertCapacity;
// Create new vertex buffer
HardwareVertexBufferSharedPtr vbuf =
HardwareBufferManager::getSingleton().createVertexBuffer(
mRenderOp.vertexData->vertexDeclaration->getVertexSize(0),
mVertexBufferCapacity,
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // TODO: Custom HBU_?
// Bind buffer
mRenderOp.vertexData->vertexBufferBinding->setBinding(0, vbuf);
}
// Update vertex count in the render operation
mRenderOp.vertexData->vertexCount = vertexCount;
if (mRenderOp.useIndexes)
{
OgreAssert(indexCount <= std::numeric_limits<unsigned short>::max(), "indexCount exceeds 16 bit");
size_t newIndexCapacity = mIndexBufferCapacity;
// Prepare index buffer
if ((indexCount > newIndexCapacity) ||
(!newIndexCapacity))
{
// indexCount exceeds current capacity!
// It is necessary to reallocate the buffer.
// Check if this is the first call
if (!newIndexCapacity)
newIndexCapacity = 1;
// Make capacity the next power of two
while (newIndexCapacity < indexCount)
newIndexCapacity <<= 1;
}
else if (indexCount < newIndexCapacity>>1)
{
// Make capacity the previous power of two
while (indexCount < newIndexCapacity>>1)
newIndexCapacity >>= 1;
}
if (newIndexCapacity != mIndexBufferCapacity)
{
mIndexBufferCapacity = newIndexCapacity;
// Create new index buffer
mRenderOp.indexData->indexBuffer =
HardwareBufferManager::getSingleton().createIndexBuffer(
HardwareIndexBuffer::IT_16BIT,
mIndexBufferCapacity,
HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY); // TODO: Custom HBU_?
}
// Update index count in the render operation
mRenderOp.indexData->indexCount = indexCount;
}
}
Real DynamicRenderable::getBoundingRadius(void) const
{
return Math::Sqrt(std::max(mBox.getMaximum().squaredLength(), mBox.getMinimum().squaredLength()));
}
Real DynamicRenderable::getSquaredViewDepth(const Camera* cam) const
{
Vector3 vMin, vMax, vMid, vDist;
vMin = mBox.getMinimum();
vMax = mBox.getMaximum();
vMid = ((vMax - vMin) * 0.5) + vMin;
vDist = cam->getDerivedPosition() - vMid;
return vDist.squaredLength();
}

