From 3c324a5f32ec181ab535df6af60201ecc575f79c Mon Sep 17 00:00:00 2001 From: codereader Date: Mon, 1 Nov 2021 19:23:38 +0100 Subject: [PATCH] #5584: Each Shader is now maintaining VBOs to store the surface data --- libs/render/IndexedVertexBuffer.h | 40 ++++++++++++- radiantcore/patch/PatchRenderables.cpp | 18 +++--- radiantcore/patch/PatchRenderables.h | 13 ----- .../rendersystem/backend/OpenGLShader.cpp | 56 ++++++++++++++----- .../rendersystem/backend/OpenGLShader.h | 10 ++-- .../rendersystem/backend/OpenGLShaderPass.cpp | 28 +--------- 6 files changed, 96 insertions(+), 69 deletions(-) diff --git a/libs/render/IndexedVertexBuffer.h b/libs/render/IndexedVertexBuffer.h index 970fdcf2c9..f2c2210e29 100644 --- a/libs/render/IndexedVertexBuffer.h +++ b/libs/render/IndexedVertexBuffer.h @@ -1,6 +1,8 @@ #pragma once +#include "render.h" #include +#include "render/VBO.h" #include "GLProgramAttributes.h" @@ -17,7 +19,7 @@ namespace render * raw vertex geometry. */ template -class IndexedVertexBuffer +class IndexedVertexBuffer final { public: typedef std::vector Vertices; @@ -80,6 +82,11 @@ class IndexedVertexBuffer std::copy(begin, end, std::back_inserter(_vertices)); } + typename Vertices::size_type getNumVertices() const + { + return _vertices.size(); + } + /// Add a batch of indices template void addIndexBatch(Iter_T begin, std::size_t count) @@ -101,6 +108,37 @@ class IndexedVertexBuffer } } + /// Add a batch of indices + template + void addIndicesToLastBatch(Iter_T begin, std::size_t count, Indices::value_type offset = 0) + { + if (_batches.empty()) + { + addIndexBatch(begin, count); + return; + } + + if (count < 1) + { + throw std::logic_error("Batch must contain at least one index"); + } + + auto& batch = *_batches.rbegin(); + batch.size += count; + + // Append the indices + _indices.reserve(_indices.size() + count); + + for (Iter_T i = begin; i < begin + count; ++i) + { + _indices.push_back(*i + offset); + } + + // Invalidate the vertex and index buffers + deleteVBO(_vertexVBO); + deleteVBO(_indexVBO); + } + /** * \brief * Replace all data with that from another IndexedVertexBuffer diff --git a/radiantcore/patch/PatchRenderables.cpp b/radiantcore/patch/PatchRenderables.cpp index e7ad9db1a2..19d39fc040 100644 --- a/radiantcore/patch/PatchRenderables.cpp +++ b/radiantcore/patch/PatchRenderables.cpp @@ -171,8 +171,8 @@ void RenderablePatchTesselation::update() _needsUpdate = false; // Load all the vertices into the target vector - _vertices = _tess.vertices; - _indices.reserve((_tess.height - 1) * (_tess.width - 1) * 6); // 6 => 2 triangles per quad + std::vector indices; + indices.reserve((_tess.height - 1) * (_tess.width - 1) * 6); // 6 => 2 triangles per quad // Generate the indices to define the triangles in clockwise order for (std::size_t h = 0; h < _tess.height - 1; ++h) @@ -181,15 +181,15 @@ void RenderablePatchTesselation::update() for (std::size_t w = 0; w < _tess.width - 1; ++w) { - _indices.push_back(static_cast(rowOffset + w + _tess.width)); - _indices.push_back(static_cast(rowOffset + w + 1)); - _indices.push_back(static_cast(rowOffset + w)); + indices.push_back(static_cast(rowOffset + w + _tess.width)); + indices.push_back(static_cast(rowOffset + w + 1)); + indices.push_back(static_cast(rowOffset + w)); - _indices.push_back(static_cast(rowOffset + w + _tess.width)); - _indices.push_back(static_cast(rowOffset + w + _tess.width + 1)); - _indices.push_back(static_cast(rowOffset + w + 1)); + indices.push_back(static_cast(rowOffset + w + _tess.width)); + indices.push_back(static_cast(rowOffset + w + _tess.width + 1)); + indices.push_back(static_cast(rowOffset + w + 1)); } } - _shader->addSurface(_vertices, _indices); + _shader->addSurface(_tess.vertices, indices); } diff --git a/radiantcore/patch/PatchRenderables.h b/radiantcore/patch/PatchRenderables.h index 42ccfab9e5..833437e397 100644 --- a/radiantcore/patch/PatchRenderables.h +++ b/radiantcore/patch/PatchRenderables.h @@ -100,9 +100,6 @@ class RenderablePatchTesselation bool _needsUpdate; ShaderPtr _shader; - std::vector _vertices; - std::vector _indices; - public: RenderablePatchTesselation(const PatchTesselation& tess) : _tess(tess), @@ -111,14 +108,4 @@ class RenderablePatchTesselation void update(); void setShader(const ShaderPtr& shader); - - const std::vector& getVertexArray() const - { - return _vertices; - } - - const std::vector& getIndexArray() const - { - return _indices; - } }; diff --git a/radiantcore/rendersystem/backend/OpenGLShader.cpp b/radiantcore/rendersystem/backend/OpenGLShader.cpp index a165f56c08..46955e75c3 100644 --- a/radiantcore/rendersystem/backend/OpenGLShader.cpp +++ b/radiantcore/rendersystem/backend/OpenGLShader.cpp @@ -75,6 +75,7 @@ OpenGLRenderSystem& OpenGLShader::getRenderSystem() void OpenGLShader::destroy() { + _vertexBuffer.reset(); _materialChanged.disconnect(); _material.reset(); _shaderPasses.clear(); @@ -112,28 +113,55 @@ void OpenGLShader::addRenderable(const OpenGLRenderable& renderable, void OpenGLShader::addSurface(const std::vector& vertices, const std::vector& indices) { - // Offset all incoming vertices with a given offset - auto indexOffset = static_cast(_vertices.size()); - - _vertices.reserve(_vertices.size() + vertices.size()); - _indices.reserve(_indices.size() + indices.size()); - - _vertices.insert(_vertices.end(), vertices.begin(), vertices.end()); - - for (const auto index : indices) + if (!_vertexBuffer) { - _indices.push_back(indexOffset + index); + _vertexBuffer = std::make_unique>(); } + + // Offset all incoming vertices with a given offset + auto indexOffset = static_cast(_vertexBuffer->getNumVertices()); + + // Pump the data to the VBO + _vertexBuffer->addVertices(vertices.begin(), vertices.end()); + _vertexBuffer->addIndicesToLastBatch(indices.begin(), indices.size(), indexOffset); } -const std::vector& OpenGLShader::getVertices() const +void OpenGLShader::drawSurfaces() { - return _vertices; + if (hasSurfaces()) + { + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glEnableClientState(GL_NORMAL_ARRAY); + + _vertexBuffer->renderAllBatches(GL_TRIANGLES, false); +#if 0 + // Render all triangles + + glBindBuffer(GL_VERTEX_ARRAY, _vbo); + + // Set the vertex pointer first + glVertexPointer(3, GL_DOUBLE, sizeof(ArbitraryMeshVertex), &_vertices.front().vertex); + glNormalPointer(GL_DOUBLE, sizeof(ArbitraryMeshVertex), &_vertices.front().normal); + glTexCoordPointer(2, GL_DOUBLE, sizeof(ArbitraryMeshVertex), &_vertices.front().texcoord); + //glVertexAttribPointer(ATTR_TEXCOORD, 2, GL_DOUBLE, 0, sizeof(ArbitraryMeshVertex), &vertices.front().texcoord); + //glVertexAttribPointer(ATTR_TANGENT, 3, GL_DOUBLE, 0, sizeof(ArbitraryMeshVertex), &vertices.front().tangent); + //glVertexAttribPointer(ATTR_BITANGENT, 3, GL_DOUBLE, 0, sizeof(ArbitraryMeshVertex), &vertices.front().bitangent); + + glDrawElements(GL_TRIANGLES, static_cast(_indices.size()), GL_UNSIGNED_INT, _indices.data()); + + //glDisableClientState(GL_NORMAL_ARRAY); + //glDisableClientState(GL_TEXTURE_COORD_ARRAY); + //glDisableClientState(GL_VERTEX_ARRAY); + + glBindBuffer(GL_VERTEX_ARRAY, 0); +#endif + } } -const std::vector OpenGLShader::getIndices() const +bool OpenGLShader::hasSurfaces() const { - return _indices; + return _vertexBuffer && _vertexBuffer->getNumVertices() > 0; } void OpenGLShader::setVisible(bool visible) diff --git a/radiantcore/rendersystem/backend/OpenGLShader.h b/radiantcore/rendersystem/backend/OpenGLShader.h index 090adbb39e..db43b9c8d4 100644 --- a/radiantcore/rendersystem/backend/OpenGLShader.h +++ b/radiantcore/rendersystem/backend/OpenGLShader.h @@ -5,6 +5,7 @@ #include "irender.h" #include "ishaders.h" #include "string/string.h" +#include "render/IndexedVertexBuffer.h" #include #include @@ -44,9 +45,7 @@ class OpenGLShader final : typedef std::set Observers; Observers _observers; - // Hacky triangle soup - std::vector _vertices; - std::vector _indices; + std::unique_ptr> _vertexBuffer; private: @@ -101,9 +100,8 @@ class OpenGLShader final : const IRenderEntity* entity) override; void addSurface(const std::vector& vertices, const std::vector& indices) override; - - const std::vector& getVertices() const; - const std::vector getIndices() const; + bool hasSurfaces() const; + void drawSurfaces(); void setVisible(bool visible) override; bool isVisible() const override; diff --git a/radiantcore/rendersystem/backend/OpenGLShaderPass.cpp b/radiantcore/rendersystem/backend/OpenGLShaderPass.cpp index e144ecfd23..1b4b6e8b3d 100644 --- a/radiantcore/rendersystem/backend/OpenGLShaderPass.cpp +++ b/radiantcore/rendersystem/backend/OpenGLShaderPass.cpp @@ -576,31 +576,7 @@ void OpenGLShaderPass::render(OpenGLState& current, // Apply our state to the current state object applyState(current, flagsMask, viewer, time, NULL); -#if 1 - if (!_owner.getVertices().empty()) - { - // Render all triangles - const auto& vertices = _owner.getVertices(); - const auto& indices = _owner.getIndices(); - glEnableClientState(GL_VERTEX_ARRAY); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glEnableClientState(GL_NORMAL_ARRAY); - - // Set the vertex pointer first - glVertexPointer(3, GL_DOUBLE, sizeof(ArbitraryMeshVertex), &vertices.front().vertex); - glNormalPointer(GL_DOUBLE, sizeof(ArbitraryMeshVertex), &vertices.front().normal); - glTexCoordPointer(2, GL_DOUBLE, sizeof(ArbitraryMeshVertex), &vertices.front().texcoord); - //glVertexAttribPointer(ATTR_TEXCOORD, 2, GL_DOUBLE, 0, sizeof(ArbitraryMeshVertex), &vertices.front().texcoord); - //glVertexAttribPointer(ATTR_TANGENT, 3, GL_DOUBLE, 0, sizeof(ArbitraryMeshVertex), &vertices.front().tangent); - //glVertexAttribPointer(ATTR_BITANGENT, 3, GL_DOUBLE, 0, sizeof(ArbitraryMeshVertex), &vertices.front().bitangent); - - glDrawElements(GL_TRIANGLES, static_cast(indices.size()), GL_UNSIGNED_INT, indices.data()); - - //glDisableClientState(GL_NORMAL_ARRAY); - //glDisableClientState(GL_TEXTURE_COORD_ARRAY); - //glDisableClientState(GL_VERTEX_ARRAY); - } -#endif + _owner.drawSurfaces(); if (!_renderablesWithoutEntity.empty()) { @@ -628,7 +604,7 @@ void OpenGLShaderPass::render(OpenGLState& current, bool OpenGLShaderPass::empty() { - return _renderables.empty() && _renderablesWithoutEntity.empty() && _owner.getVertices().empty(); + return _renderables.empty() && _renderablesWithoutEntity.empty() && _owner.hasSurfaces(); } bool OpenGLShaderPass::stateIsActive()