diff --git a/radiantcore/rendersystem/backend/SurfaceRenderer.h b/radiantcore/rendersystem/backend/SurfaceRenderer.h index 63a0bb4428..0938b02bfc 100644 --- a/radiantcore/rendersystem/backend/SurfaceRenderer.h +++ b/radiantcore/rendersystem/backend/SurfaceRenderer.h @@ -9,18 +9,117 @@ class SurfaceRenderer : public ISurfaceRenderer { private: - struct VertexBuffer + class VertexBuffer { - GLenum mode; - std::vector vertices; - std::vector indices; + private: + GLenum _mode; + + std::vector _vertices; + std::vector _indices; + public: + VertexBuffer(GLenum mode) : + _mode(mode) + {} + + bool empty() const + { + return _indices.empty(); + } + + void render() const + { + if (_indices.empty()) return; + + 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(_mode, static_cast(_indices.size()), GL_UNSIGNED_INT, &_indices.front()); + } + + void renderIndexRange(std::size_t firstIndex, std::size_t numIndices) const + { + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_COLOR_ARRAY); + + glFrontFace(GL_CW); + + 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(_mode, static_cast(numIndices), GL_UNSIGNED_INT, &_indices[firstIndex]); + glDisableClientState(GL_NORMAL_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + // Returns the vertex and index offsets in this buffer + std::pair addSurface(const std::vector& vertices, + const std::vector& indices) + { + auto vertexOffset = _vertices.size(); + auto indexOffset = _indices.size(); + + std::copy(vertices.begin(), vertices.end(), std::back_inserter(_vertices)); + + for (auto index : indices) + { + _indices.push_back(index + static_cast(vertexOffset)); + } + + return { vertexOffset, indexOffset }; + } + + void updateSurface(std::size_t firstVertex, std::size_t firstIndex, + const std::vector& vertices, + const std::vector& indices) + { + // Copy the data to the correct slot in the array + std::copy(vertices.begin(), vertices.end(), _vertices.begin() + firstVertex); + + // Before assignment, the indices need to be shifted to match the array offset of the vertices + auto targetIndex = _indices.begin() + firstIndex; + auto indexShift = static_cast(firstVertex); + + for (auto index : indices) + { + *targetIndex++ = index + indexShift; + } + } + + // Cuts out the vertices and indices, adjusts all indices located to the right of the cut + void removeSurface(std::size_t firstVertex, std::size_t numVertices, std::size_t firstIndex, std::size_t numIndices) + { + // Cut out the vertices + auto firstVertexToRemove = _vertices.begin() + firstVertex; + _vertices.erase(firstVertexToRemove, firstVertexToRemove + numVertices); + + // Shift all indices to the left, offsetting their values by the number of removed vertices + auto offsetToApply = -static_cast(numVertices); + + auto targetIndex = _indices.begin() + firstIndex; + auto indexToMove = targetIndex + numIndices; + + auto indexEnd = _indices.end(); + while (indexToMove != indexEnd) + { + *targetIndex++ = *indexToMove++ + offsetToApply; + } + + // Cut off the tail of the indices + _indices.resize(_indices.size() - numIndices); + } }; - VertexBuffer _triangleBuffer; - VertexBuffer _quadBuffer; + std::vector _buffers; static constexpr std::size_t InvalidVertexIndex = std::numeric_limits::max(); + // Internal information about where the chunk of indexed vertex data is located: + // Which buffer they're in, and the data offset and count within the buffer. + // This is enough information to access, replace or remove the data at a later point. struct SlotInfo { std::uint8_t bucketIndex; @@ -38,13 +137,18 @@ class SurfaceRenderer : SurfaceRenderer() : _freeSlotMappingHint(InvalidSlotMapping) { - _triangleBuffer.mode = GL_TRIANGLES; - _quadBuffer.mode = GL_QUADS; + _buffers.emplace_back(GL_TRIANGLES); + _buffers.emplace_back(GL_QUADS); } bool empty() const { - return _triangleBuffer.vertices.empty() && _quadBuffer.vertices.empty(); + for (const auto& buffer : _buffers) + { + if (!buffer.empty()) return false; + } + + return true; } Slot addSurface(SurfaceIndexingType indexType, const std::vector& vertices, @@ -54,26 +158,17 @@ class SurfaceRenderer : auto& bucket = getBucketByIndex(bucketIndex); // Allocate a slot - auto oldVertexSize = bucket.vertices.size(); - auto oldIndexSize = bucket.indices.size(); - auto newSlotIndex = getNextFreeSlotMapping(); - auto& slot = _slots.at(newSlotIndex); - + + auto [vertexOffset, indexOffset] = bucket.addSurface(vertices, indices); + slot.bucketIndex = bucketIndex; - slot.firstVertex = oldVertexSize; + slot.firstVertex = vertexOffset; slot.numVertices = vertices.size(); - slot.firstIndex = oldIndexSize; + slot.firstIndex = indexOffset; slot.numIndices = indices.size(); - std::copy(vertices.begin(), vertices.end(), std::back_inserter(bucket.vertices)); - - for (auto index : indices) - { - bucket.indices.push_back(index + static_cast(oldVertexSize)); - } - return newSlotIndex; } @@ -82,24 +177,7 @@ class SurfaceRenderer : auto& slotInfo = _slots.at(slot); auto& bucket = getBucketByIndex(slotInfo.bucketIndex); - // Cut out the vertices - 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(slotInfo.numVertices); - - auto targetIndex = bucket.indices.begin() + slotInfo.firstIndex; - auto indexToMove = targetIndex + slotInfo.numIndices; - - auto indexEnd = bucket.indices.end(); - while (indexToMove != indexEnd) - { - *targetIndex++ = *indexToMove++ + offsetToApply; - } - - // Cut off the tail of the indices - bucket.indices.resize(bucket.indices.size() - slotInfo.numIndices); + bucket.removeSurface(slotInfo.firstVertex, slotInfo.numVertices, slotInfo.firstIndex, slotInfo.numIndices); // Adjust all offsets in other slots for (auto& slot : _slots) @@ -129,23 +207,15 @@ class SurfaceRenderer : 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(), bucket.vertices.begin() + slotInfo.firstVertex); - - // Before assignment, the indices need to be shifted to match the array offset of the vertices - auto targetIndex = bucket.indices.begin() + slotInfo.firstIndex; - auto indexShift = static_cast(slotInfo.firstVertex); - - for (auto index : indices) - { - *targetIndex++ = index + indexShift; - } + bucket.updateSurface(slotInfo.firstVertex, slotInfo.firstIndex, vertices, indices); } void render() { - renderBuffer(_triangleBuffer); - renderBuffer(_quadBuffer); + for (auto& buffer : _buffers) + { + buffer.render(); + } } void renderSurface(Slot slot) override @@ -153,36 +223,10 @@ class SurfaceRenderer : auto& slotInfo = _slots.at(slot); auto& buffer = getBucketByIndex(slotInfo.bucketIndex); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_COLOR_ARRAY); - - glFrontFace(GL_CW); - - 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(buffer.mode, static_cast(slotInfo.numIndices), GL_UNSIGNED_INT, &buffer.indices[slotInfo.firstIndex]); - glDisableClientState(GL_NORMAL_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); + buffer.renderIndexRange(slotInfo.firstIndex, slotInfo.numIndices); } private: - - void renderBuffer(const VertexBuffer& buffer) - { - 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(buffer.mode, static_cast(buffer.indices.size()), GL_UNSIGNED_INT, &buffer.indices.front()); - } - } - constexpr static std::uint8_t GetBucketIndexForIndexType(SurfaceIndexingType indexType) { return indexType == SurfaceIndexingType::Triangles ? 0 : 1; @@ -190,7 +234,7 @@ class SurfaceRenderer : VertexBuffer& getBucketByIndex(std::uint8_t bucketIndex) { - return bucketIndex == 0 ? _triangleBuffer : _quadBuffer; + return _buffers[bucketIndex]; } ISurfaceRenderer::Slot getNextFreeSlotMapping()