Skip to content

Commit

Permalink
#5584: Add SurfaceRenderer ability to store two separate surface inde…
Browse files Browse the repository at this point in the history
…x types, one buffer for GL_TRIANGLES, one for GL_QUADS.
  • Loading branch information
codereader committed Nov 15, 2021
1 parent f2b4d08 commit fe06fe7
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 29 deletions.
10 changes: 9 additions & 1 deletion include/isurfacerenderer.h
Expand Up @@ -8,6 +8,12 @@
namespace render
{

enum class SurfaceIndexingType
{
Triangles,
Quads,
};

/**
* A surface renderer accepts a variable number of indexed surfaces and arranges
* them into one or more continuous blocks of vertices for efficient rendering.
Expand All @@ -26,7 +32,9 @@ class ISurfaceRenderer

// Allocate a slot to hold the given surface data of the given size
// Returns the handle which can be used to update or deallocate the data later
virtual Slot addSurface(const std::vector<ArbitraryMeshVertex>& vertices,
// The indexType determines the primitive GLenum that is chosen to render this surface
virtual Slot addSurface(SurfaceIndexingType indexType,
const std::vector<ArbitraryMeshVertex>& vertices,
const std::vector<unsigned int>& indices) = 0;

// Releases a previously allocated slot. This invalidates the handle.
Expand Down
2 changes: 1 addition & 1 deletion radiantcore/patch/PatchRenderables.cpp
Expand Up @@ -272,7 +272,7 @@ void RenderablePatchTesselation::update(const ShaderPtr& shader)

if (_surfaceSlot == render::ISurfaceRenderer::InvalidSlot)
{
_surfaceSlot = shader->addSurface(_tess.vertices, indices);
_surfaceSlot = shader->addSurface(render::SurfaceIndexingType::Triangles, _tess.vertices, indices);
}
else
{
Expand Down
6 changes: 3 additions & 3 deletions radiantcore/rendersystem/backend/OpenGLShader.cpp
Expand Up @@ -208,10 +208,10 @@ bool OpenGLShader::hasSurfaces() const
return !SurfaceRenderer::empty() || _vertexBuffer && _vertexBuffer->getNumVertices() > 0;
}

ISurfaceRenderer::Slot OpenGLShader::addSurface(const std::vector<ArbitraryMeshVertex>& vertices,
const std::vector<unsigned int>& indices)
ISurfaceRenderer::Slot OpenGLShader::addSurface(SurfaceIndexingType indexType,
const std::vector<ArbitraryMeshVertex>& vertices, const std::vector<unsigned int>& indices)
{
return SurfaceRenderer::addSurface(vertices, indices);
return SurfaceRenderer::addSurface(indexType, vertices, indices);
}

void OpenGLShader::removeSurface(ISurfaceRenderer::Slot slot)
Expand Down
3 changes: 2 additions & 1 deletion radiantcore/rendersystem/backend/OpenGLShader.h
Expand Up @@ -115,7 +115,8 @@ class OpenGLShader final :
bool hasSurfaces() const;
void drawSurfaces();

ISurfaceRenderer::Slot addSurface(const std::vector<ArbitraryMeshVertex>& vertices, const std::vector<unsigned int>& indices) override;
ISurfaceRenderer::Slot addSurface(SurfaceIndexingType indexType,
const std::vector<ArbitraryMeshVertex>& vertices, const std::vector<unsigned int>& indices) override;
void removeSurface(ISurfaceRenderer::Slot slot) override;
void updateSurface(ISurfaceRenderer::Slot slot, const std::vector<ArbitraryMeshVertex>& vertices,
const std::vector<unsigned int>& indices) override;
Expand Down
78 changes: 55 additions & 23 deletions radiantcore/rendersystem/backend/SurfaceRenderer.h
Expand Up @@ -9,13 +9,20 @@ class SurfaceRenderer :
public ISurfaceRenderer
{
private:
std::vector<ArbitraryMeshVertex> _vertices;
std::vector<unsigned int> _indices;
struct VertexBuffer
{
std::vector<ArbitraryMeshVertex> vertices;
std::vector<unsigned int> indices;
};

VertexBuffer _triangleBuffer;
VertexBuffer _quadBuffer;

static constexpr std::size_t InvalidVertexIndex = std::numeric_limits<std::size_t>::max();

struct SlotInfo
{
std::uint8_t bucketIndex;
std::size_t firstVertex;
std::size_t numVertices;
std::size_t firstIndex;
Expand All @@ -33,34 +40,38 @@ class SurfaceRenderer :

bool empty() const
{
return _vertices.empty();
return _triangleBuffer.vertices.empty() && _quadBuffer.vertices.empty();
}

Slot addSurface(const std::vector<ArbitraryMeshVertex>& vertices,
Slot addSurface(SurfaceIndexingType indexType, const std::vector<ArbitraryMeshVertex>& vertices,
const std::vector<unsigned int>& indices) override
{
auto bucketIndex = GetBucketIndexForIndexType(indexType);
auto& bucket = getBucketByIndex(bucketIndex);

// Allocate a slot
auto oldVertexSize = _vertices.size();
auto oldIndexSize = _indices.size();
auto oldVertexSize = bucket.vertices.size();
auto oldIndexSize = bucket.indices.size();

auto newSlotIndex = getNextFreeSlotMapping();

auto& slot = _slots.at(newSlotIndex);

slot.bucketIndex = bucketIndex;
slot.firstVertex = oldVertexSize;
slot.numVertices = vertices.size();
slot.firstIndex = oldIndexSize;
slot.numIndices = indices.size();

_vertices.reserve(oldVertexSize + vertices.size()); // reserve() never shrinks
std::copy(vertices.begin(), vertices.end(), std::back_inserter(_vertices));
bucket.vertices.reserve(oldVertexSize + vertices.size()); // reserve() never shrinks
std::copy(vertices.begin(), vertices.end(), std::back_inserter(bucket.vertices));

// Allocate, copy and offset indices
_indices.reserve(oldIndexSize + indices.size());
bucket.indices.reserve(oldIndexSize + indices.size());

for (auto index : indices)
{
_indices.push_back(index + static_cast<unsigned int>(oldVertexSize));
bucket.indices.push_back(index + static_cast<unsigned int>(oldVertexSize));
}

return newSlotIndex;
Expand All @@ -69,25 +80,26 @@ class SurfaceRenderer :
void removeSurface(Slot slot) override
{
auto& slotInfo = _slots.at(slot);
auto& bucket = getBucketByIndex(slotInfo.bucketIndex);

// Cut out the vertices
auto firstVertexToRemove = _vertices.begin() + slotInfo.firstVertex;
_vertices.erase(firstVertexToRemove, firstVertexToRemove + slotInfo.numVertices);
auto firstVertexToRemove = bucket.vertices.begin() + slotInfo.firstVertex;
bucket.vertices.erase(firstVertexToRemove, firstVertexToRemove + slotInfo.numVertices);

// Shift all indices to the left, offsetting their values by the number of removed vertices
auto offsetToApply = -static_cast<int>(slotInfo.numVertices);

auto targetIndex = _indices.begin() + slotInfo.firstIndex;
auto targetIndex = bucket.indices.begin() + slotInfo.firstIndex;
auto indexToMove = targetIndex + slotInfo.numIndices;

auto indexEnd = _indices.end();
auto indexEnd = bucket.indices.end();
while (indexToMove != indexEnd)
{
*targetIndex++ = *indexToMove++ + offsetToApply;
}

// Cut off the tail of the indices
_indices.resize(_indices.size() - slotInfo.numIndices);
bucket.indices.resize(bucket.indices.size() - slotInfo.numIndices);

// Adjust all offsets in other slots
for (auto& slot : _slots)
Expand Down Expand Up @@ -115,12 +127,13 @@ class SurfaceRenderer :
const std::vector<unsigned int>& indices) override
{
auto& slotInfo = _slots.at(slot);
auto& bucket = getBucketByIndex(slotInfo.bucketIndex);

// Copy the data to the correct slot in the array
std::copy(vertices.begin(), vertices.end(), _vertices.begin() + slotInfo.firstVertex);
std::copy(vertices.begin(), vertices.end(), bucket.vertices.begin() + slotInfo.firstVertex);

// Before assignment, the indices need to be shifted to match the array offset of the vertices
auto targetIndex = _indices.begin() + slotInfo.firstIndex;
auto targetIndex = bucket.indices.begin() + slotInfo.firstIndex;
auto indexShift = static_cast<unsigned int>(slotInfo.firstVertex);

for (auto index : indices)
Expand All @@ -131,15 +144,34 @@ class SurfaceRenderer :

void render()
{
// Vertex pointer includes whole vertex buffer
glVertexPointer(3, GL_DOUBLE, sizeof(ArbitraryMeshVertex), &_vertices.front().vertex);
glTexCoordPointer(2, GL_DOUBLE, sizeof(ArbitraryMeshVertex), &_vertices.front().texcoord);
glNormalPointer(GL_DOUBLE, sizeof(ArbitraryMeshVertex), &_vertices.front().normal);

glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(_indices.size()), GL_UNSIGNED_INT, &_indices.front());
renderBuffer(_triangleBuffer, GL_TRIANGLES);
renderBuffer(_quadBuffer, GL_QUADS);
}

private:

void renderBuffer(const VertexBuffer& buffer, GLenum mode)
{
if (!buffer.indices.empty())
{
glVertexPointer(3, GL_DOUBLE, sizeof(ArbitraryMeshVertex), &buffer.vertices.front().vertex);
glTexCoordPointer(2, GL_DOUBLE, sizeof(ArbitraryMeshVertex), &buffer.vertices.front().texcoord);
glNormalPointer(GL_DOUBLE, sizeof(ArbitraryMeshVertex), &buffer.vertices.front().normal);

glDrawElements(mode, static_cast<GLsizei>(buffer.indices.size()), GL_UNSIGNED_INT, &buffer.indices.front());
}
}

constexpr static std::uint8_t GetBucketIndexForIndexType(SurfaceIndexingType indexType)
{
return indexType == SurfaceIndexingType::Triangles ? 0 : 1;
}

VertexBuffer& getBucketByIndex(std::uint8_t bucketIndex)
{
return bucketIndex == 0 ? _triangleBuffer : _quadBuffer;
}

ISurfaceRenderer::Slot getNextFreeSlotMapping()
{
auto numSlots = _slots.size();
Expand Down

0 comments on commit fe06fe7

Please sign in to comment.