diff options
author | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-04-22 19:06:42 +0100 |
---|---|---|
committer | Dan Goodliffe <dan@randomdan.homeip.net> | 2023-04-22 19:06:42 +0100 |
commit | d1f79b4c438ebf0822741e103b2cb06bdee4514e (patch) | |
tree | a4d574d12cd81d5e33886ce7ca961f7dbe872fcf /gfx | |
parent | Rename lots of shader files (diff) | |
parent | Keep the instance unused vector sorted and binary search it (diff) | |
download | ilt-d1f79b4c438ebf0822741e103b2cb06bdee4514e.tar.bz2 ilt-d1f79b4c438ebf0822741e103b2cb06bdee4514e.tar.xz ilt-d1f79b4c438ebf0822741e103b2cb06bdee4514e.zip |
Merge branch 'instancing'
Diffstat (limited to 'gfx')
-rw-r--r-- | gfx/gl/instanceVertices.h | 211 | ||||
-rw-r--r-- | gfx/gl/sceneRenderer.cpp | 6 | ||||
-rw-r--r-- | gfx/gl/sceneShader.cpp | 29 | ||||
-rw-r--r-- | gfx/gl/sceneShader.h | 3 | ||||
-rw-r--r-- | gfx/gl/shaders/dynamicPointInst.vs | 21 | ||||
-rw-r--r-- | gfx/gl/shaders/spotLight.vs | 2 | ||||
-rw-r--r-- | gfx/gl/vertexArrayObject.hpp | 107 | ||||
-rw-r--r-- | gfx/models/mesh.cpp | 27 | ||||
-rw-r--r-- | gfx/models/mesh.h | 4 |
9 files changed, 347 insertions, 63 deletions
diff --git a/gfx/gl/instanceVertices.h b/gfx/gl/instanceVertices.h new file mode 100644 index 0000000..228020d --- /dev/null +++ b/gfx/gl/instanceVertices.h @@ -0,0 +1,211 @@ +#pragma once + +#include "glArrays.h" +#include <iterator> +#include <span> +#include <special_members.hpp> +#include <utility> +#include <vector> + +template<typename T> class InstanceVertices { +public: + InstanceVertices(size_t initialSize = 16) + { + allocBuffer(initialSize); + } + + class [[nodiscard]] InstanceProxy { + public: + InstanceProxy(InstanceVertices * iv, std::size_t idx) : instances {iv}, index {idx} { } + InstanceProxy(InstanceProxy && other) : instances {std::exchange(other.instances, nullptr)}, index {other.index} + { + } + NO_COPY(InstanceProxy); + + ~InstanceProxy() + { + if (instances) { + instances->release(index); + } + } + + InstanceProxy & + operator=(InstanceProxy && other) + { + if (instances) { + instances->release(index); + } + instances = std::exchange(other.instances, nullptr); + index = other.index; + return *this; + } + template<typename U> + T & + operator=(U && v) + { + return instances->at(index) = std::forward<U>(v); + } + + [[nodiscard]] + operator T &() + { + return instances->at(index); + } + [[nodiscard]] operator const T &() const + { + return instances->at(index); + } + [[nodiscard]] T * + get() + { + return &instances->at(index); + } + [[nodiscard]] const T * + get() const + { + return &instances->at(index); + } + [[nodiscard]] T * + operator->() + { + return get(); + } + [[nodiscard]] const T * + operator->() const + { + return get(); + } + [[nodiscard]] T & + operator*() + { + return instances->at(index); + } + [[nodiscard]] const T & + operator*() const + { + return instances->at(index); + } + + private: + InstanceVertices<T> * instances; + std::size_t index; + }; + + template<typename... Params> + [[nodiscard]] InstanceProxy + acquire(Params &&... params) + { + map(); + if (!unused.empty()) { + auto idx = unused.back(); + unused.pop_back(); + index[idx] = next++; + new (&at(idx)) T(std::forward<Params>(params)...); + return InstanceProxy {this, idx}; + } + if (next >= capacity) { + resize(capacity * 2); + } + index.emplace_back(next++); + new (data + index.back()) T(std::forward<Params>(params)...); + return InstanceProxy {this, index.size() - 1}; + } + + [[nodiscard]] const auto & + bufferName() const + { + return buffer; + } + + [[nodiscard]] auto + count() const + { + unmap(); + return next; + } + +protected: + friend InstanceProxy; + + void + release(const size_t pidx) + { + // Destroy p's object + at(pidx).~T(); + if (--next != index[pidx]) { + // Move last object into p's slot + new (&at(pidx)) T {std::move(data[next])}; + (data[next]).~T(); + *std::find_if(index.begin(), index.end(), [this](const auto & i) { + return i == next && !std::binary_search(unused.begin(), unused.end(), &i - index.data()); + }) = index[pidx]; + } + if (pidx == index.size() - 1) { + index.pop_back(); + } + else { + // Remember p.index is free index now, keeping it sorted + unused.insert(std::upper_bound(unused.begin(), unused.end(), pidx), pidx); + } + } + + void + allocBuffer(std::size_t newCapacity) + { + glBindBuffer(GL_ARRAY_BUFFER, buffer); + glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(T) * newCapacity), nullptr, GL_DYNAMIC_DRAW); + glBindBuffer(GL_ARRAY_BUFFER, 0); + capacity = newCapacity; + data = nullptr; + } + + void + resize(size_t newCapacity) + { + const auto maintain = std::min(newCapacity, capacity); + std::vector<T> existing; + const auto maintaind = static_cast<typename decltype(existing)::difference_type>(maintain); + existing.reserve(maintain); + map(); + std::move(data, data + maintain, std::back_inserter(existing)); + allocBuffer(newCapacity); + map(); + std::move(existing.begin(), existing.begin() + maintaind, data); + capacity = newCapacity; + } + + [[nodiscard]] T & + at(size_t pindex) + { + map(); + return data[index[pindex]]; + } + + void + map() const + { + if (!data) { + data = static_cast<T *>(glMapNamedBuffer(buffer, GL_READ_WRITE)); + } + } + + void + unmap() const + { + if (data) { + glUnmapNamedBuffer(buffer); + data = nullptr; + } + } + + glBuffer buffer; + mutable T * data {}; + // Size of buffer + std::size_t capacity {}; + // # used of capacity + std::size_t next {}; + // Index into buffer given to nth proxy + std::vector<size_t> index; + // List of free spaces in index + std::vector<size_t> unused; +}; diff --git a/gfx/gl/sceneRenderer.cpp b/gfx/gl/sceneRenderer.cpp index 873dc5b..6542bea 100644 --- a/gfx/gl/sceneRenderer.cpp +++ b/gfx/gl/sceneRenderer.cpp @@ -18,7 +18,7 @@ SceneRenderer::SceneRenderer(glm::ivec2 s, GLuint o) : lighting {lighting_vs, lighting_fs}, shadowMapper {{2048, 2048}} { shader.setViewPort({0, 0, size.x, size.y}); - VertexArrayObject<glm::i8vec4>::configure(displayVAO, displayVBO, displayVAOdata); + VertexArrayObject {displayVAO}.addAttribs<glm::i8vec4>(displayVBO, displayVAOdata); glBindFramebuffer(GL_FRAMEBUFFER, gBuffer); const auto configuregdata @@ -128,8 +128,8 @@ SceneRenderer::renderQuad() const SceneRenderer::DirectionalLightProgram::DirectionalLightProgram() : Program {lighting_vs, directionalLight_fs}, directionLoc {*this, "lightDirection"}, colourLoc {*this, "lightColour"}, lightViewProjectionLoc {*this, "lightViewProjection"}, - lightViewProjectionCountLoc {*this, "lightViewProjectionCount"}, lightViewShadowMapRegionLoc { - *this, "shadowMapRegion"} + lightViewProjectionCountLoc {*this, "lightViewProjectionCount"}, + lightViewShadowMapRegionLoc {*this, "shadowMapRegion"} { } diff --git a/gfx/gl/sceneShader.cpp b/gfx/gl/sceneShader.cpp index bcd0590..00d9826 100644 --- a/gfx/gl/sceneShader.cpp +++ b/gfx/gl/sceneShader.cpp @@ -8,6 +8,7 @@ #include <gfx/gl/shaders/gs-pointLight.h> #include <gfx/gl/shaders/gs-spotLight.h> #include <gfx/gl/shaders/vs-dynamicPoint.h> +#include <gfx/gl/shaders/vs-dynamicPointInst.h> #include <gfx/gl/shaders/vs-fixedPoint.h> #include <gfx/gl/shaders/vs-pointLight.h> #include <gfx/gl/shaders/vs-spotLight.h> @@ -18,13 +19,17 @@ #include <location.hpp> #include <maths.h> -SceneShader::SceneShader() : landmass {fixedPoint_vs, landmass_fs}, absolute {fixedPoint_vs, material_fs} { } +SceneShader::SceneShader() : + basicInst {dynamicPointInst_vs, material_fs}, landmass {fixedPoint_vs, landmass_fs}, + absolute {fixedPoint_vs, material_fs} +{ +} void SceneShader::setViewProjection(const glm::mat4 & viewProjection) const { - for (const auto & prog : - std::array<const SceneProgram *, 6> {&basic, &water, &landmass, &absolute, &pointLight, &spotLight}) { + for (const auto & prog : std::array<const SceneProgram *, 7> { + &basic, &basicInst, &water, &landmass, &absolute, &pointLight, &spotLight}) { prog->setViewProjection(viewProjection); } } @@ -32,8 +37,8 @@ SceneShader::setViewProjection(const glm::mat4 & viewProjection) const void SceneShader::setViewPort(const glm::ivec4 & viewPort) const { - for (const auto & prog : - std::array<const SceneProgram *, 6> {&basic, &water, &landmass, &absolute, &pointLight, &spotLight}) { + for (const auto & prog : std::array<const SceneProgram *, 7> { + &basic, &basicInst, &water, &landmass, &absolute, &pointLight, &spotLight}) { prog->setViewPort(viewPort); } } @@ -83,7 +88,7 @@ SceneShader::WaterProgram::use(float waveCycle) const SceneShader::PointLightShader::PointLightShader() : SceneProgram {pointLight_vs, pointLight_gs, pointLight_fs}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"} { - VertexArrayObject<glm::vec3>::configure(va, b); + VertexArrayObject {va}.addAttribs<glm::vec3>(b); } void @@ -94,16 +99,16 @@ SceneShader::PointLightShader::add(const glm::vec3 & position, const glm::vec3 & glBindBuffer(GL_ARRAY_BUFFER, b); glUniform3fv(colourLoc, 1, glm::value_ptr(colour)); glUniform1f(kqLoc, kq); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3), glm::value_ptr(position)); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), glm::value_ptr(position), GL_DYNAMIC_DRAW); glDrawArrays(GL_POINTS, 0, 1); } SceneShader::SpotLightShader::SpotLightShader() : - SceneProgram {spotLight_vs, spotLight_gs, spotLight_fs}, colourLoc {*this, "colour"}, kqLoc {*this, "kq"}, - arcLoc {*this, "arc"} + SceneProgram {spotLight_vs, spotLight_gs, spotLight_fs}, directionLoc {*this, "v_direction"}, + colourLoc {*this, "colour"}, kqLoc {*this, "kq"}, arcLoc {*this, "arc"} { using v3pair = std::pair<glm::vec3, glm::vec3>; - VertexArrayObject<v3pair>::configure<&v3pair::first, &v3pair::second>(va, b); + VertexArrayObject {va}.addAttribs<v3pair, &v3pair::first, &v3pair::second>(b); } void @@ -114,9 +119,9 @@ SceneShader::SpotLightShader::add(const glm::vec3 & position, const glm::vec3 & glBindVertexArray(va); glBindBuffer(GL_ARRAY_BUFFER, b); glUniform3fv(colourLoc, 1, glm::value_ptr(colour)); + glUniform3fv(directionLoc, 1, glm::value_ptr(direction)); glUniform1f(kqLoc, kq); glUniform1f(arcLoc, arc); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(glm::vec3), glm::value_ptr(position)); - glBufferSubData(GL_ARRAY_BUFFER, sizeof(glm::vec3), sizeof(glm::vec3), glm::value_ptr(direction)); + glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3), glm::value_ptr(position), GL_DYNAMIC_DRAW); glDrawArrays(GL_POINTS, 0, 1); } diff --git a/gfx/gl/sceneShader.h b/gfx/gl/sceneShader.h index ed1bb79..ead184e 100644 --- a/gfx/gl/sceneShader.h +++ b/gfx/gl/sceneShader.h @@ -69,6 +69,7 @@ class SceneShader { const float arc) const; private: + UniformLocation directionLoc; UniformLocation colourLoc; UniformLocation kqLoc; UniformLocation arcLoc; @@ -81,7 +82,7 @@ public: BasicProgram basic; WaterProgram water; - AbsolutePosProgram landmass, absolute; + AbsolutePosProgram basicInst, landmass, absolute; PointLightShader pointLight; SpotLightShader spotLight; diff --git a/gfx/gl/shaders/dynamicPointInst.vs b/gfx/gl/shaders/dynamicPointInst.vs new file mode 100644 index 0000000..1c66979 --- /dev/null +++ b/gfx/gl/shaders/dynamicPointInst.vs @@ -0,0 +1,21 @@ +#version 330 core + +include(`meshIn.glsl') +layout(location = 5) in mat4 model; +include(`materialInterface.glsl') + +uniform mat4 viewProjection; + +void +main() +{ + vec4 worldPos = model * vec4(position, 1.0); + + FragPos = worldPos.xyz; + TexCoords = texCoord; + Normal = (model * vec4(normal, 0.0)).xyz; + Colour = colour; + Material = material; + + gl_Position = viewProjection * worldPos; +} diff --git a/gfx/gl/shaders/spotLight.vs b/gfx/gl/shaders/spotLight.vs index e648553..dca0854 100644 --- a/gfx/gl/shaders/spotLight.vs +++ b/gfx/gl/shaders/spotLight.vs @@ -1,8 +1,8 @@ #version 330 core layout(location = 0) in vec3 v_position; -layout(location = 1) in vec3 v_direction; +uniform vec3 v_direction; uniform vec3 colour; uniform float kq; uniform float arc; diff --git a/gfx/gl/vertexArrayObject.hpp b/gfx/gl/vertexArrayObject.hpp index 5b9fc60..7ded03e 100644 --- a/gfx/gl/vertexArrayObject.hpp +++ b/gfx/gl/vertexArrayObject.hpp @@ -2,50 +2,65 @@ #include "collections.hpp" #include "gl_traits.hpp" +#include "special_members.hpp" #include <GL/glew.h> -#include <glm/common.hpp> -template<typename Vertex> class VertexArrayObject { +class VertexArrayObject { public: - template<auto Vertex::*... attribs> - static void - configure(const GLuint arrayObject, const GLuint arrayBuffer, const GLuint indexBuffer, - const SequentialCollection<Vertex> auto & vertices, const SequentialCollection<unsigned int> auto & indices) + template<typename T> [[nodiscard]] VertexArrayObject(const T & arrayObject) { glBindVertexArray(arrayObject); - - configure_attribs<attribs...>(arrayBuffer); - data(vertices, arrayBuffer, GL_ARRAY_BUFFER); - data(indices, indexBuffer, GL_ELEMENT_ARRAY_BUFFER); - + } + ~VertexArrayObject() + { glBindVertexArray(0); } + NO_MOVE(VertexArrayObject); + NO_COPY(VertexArrayObject); - template<auto Vertex::*... attribs> - static void - configure(const GLuint arrayObject, const GLuint arrayBuffer, const SequentialCollection<Vertex> auto & vertices) - { - glBindVertexArray(arrayObject); + template<typename m, typename T> struct MP { + constexpr MP(m T::*p) : P {p} { } + operator void *() const + { + return &(static_cast<T *>(nullptr)->*P); + } + m T::*P; + using value_type = m; + }; + template<typename m, typename T> MP(m T::*) -> MP<m, T>; - configure_attribs<attribs...>(arrayBuffer); + template<typename VertexT, MP... attribs> + VertexArrayObject & + addAttribs(const GLuint arrayBuffer, const SequentialCollection<VertexT> auto & vertices, const GLuint divisor = 0) + { + addAttribs<VertexT, attribs...>(arrayBuffer, divisor); data(vertices, arrayBuffer, GL_ARRAY_BUFFER); - - glBindVertexArray(0); + return *this; } - template<auto Vertex::*... attribs> - static void - configure(const GLuint arrayObject, const GLuint arrayBuffer) + template<typename VertexT, MP... attribs> + VertexArrayObject & + addAttribs(const GLuint arrayBuffer, const GLuint divisor = 0) { - glBindVertexArray(arrayObject); + configure_attribs<VertexT, attribs...>(arrayBuffer, divisor); + return *this; + } - configure_attribs<attribs...>(arrayBuffer); - glBufferData(GL_ARRAY_BUFFER, static_cast<GLsizeiptr>(sizeof(Vertex)), nullptr, GL_DYNAMIC_DRAW); + template<typename Indices> + VertexArrayObject & + addIndices(const GLuint arrayBuffer, const Indices & indices) + { + data(indices, arrayBuffer, GL_ELEMENT_ARRAY_BUFFER); + return *this; + } - glBindVertexArray(0); + VertexArrayObject & + addIndices(const GLuint arrayBuffer) + { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrayBuffer); + return *this; } -private: template<typename Data> static void data(const Data & data, const GLuint arrayBuffer, GLenum target) @@ -55,34 +70,40 @@ private: glBufferData(target, static_cast<GLsizeiptr>(sizeof(Value) * data.size()), data.data(), GL_STATIC_DRAW); } - template<typename T> - static void - set_pointer(const GLuint vertexArrayId, const void * ptr) +private: + template<typename VertexT, typename T> + static auto + set_pointer(const GLuint vertexArrayId, const void * ptr, const GLuint divisor) { - glEnableVertexAttribArray(vertexArrayId); using traits = gl_traits<T>; - traits::vertexAttribFunc(vertexArrayId, traits::size, traits::type, sizeof(Vertex), ptr); + const auto usedAttribs + = traits::vertexAttribFunc(vertexArrayId, traits::size, traits::type, sizeof(VertexT), ptr); + for (GLuint i {}; i < usedAttribs; i++) { + glEnableVertexAttribArray(vertexArrayId + i); + glVertexAttribDivisor(vertexArrayId + i, divisor); + } + return usedAttribs; } - template<auto Vertex::*attrib> - static void - set_pointer(const GLuint vertexArrayId) + template<typename VertexT, MP attrib> + static auto + set_pointer(const GLuint vertexArrayId, const GLuint divisor) { - set_pointer<std::decay_t<decltype(std::declval<Vertex>().*attrib)>>( - vertexArrayId, &(static_cast<const Vertex *>(nullptr)->*attrib)); + return set_pointer<VertexT, typename decltype(attrib)::value_type>(vertexArrayId, attrib, divisor); } - template<auto Vertex::*... attribs> - static void - configure_attribs(const GLuint arrayBuffer) + template<typename VertexT, MP... attribs> + void + configure_attribs(const GLuint arrayBuffer, const GLuint divisor) { glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer); if constexpr (sizeof...(attribs) == 0) { - set_pointer<Vertex>(0, nullptr); + vertexArrayId += set_pointer<VertexT, VertexT>(vertexArrayId, nullptr, divisor); } else { - GLuint vertexArrayId {}; - (set_pointer<attribs>(vertexArrayId++), ...); + ((vertexArrayId += set_pointer<VertexT, attribs>(vertexArrayId, divisor)), ...); } } + + GLuint vertexArrayId {}; }; diff --git a/gfx/models/mesh.cpp b/gfx/models/mesh.cpp index 2719211..55759cb 100644 --- a/gfx/models/mesh.cpp +++ b/gfx/models/mesh.cpp @@ -7,9 +7,30 @@ Mesh::Mesh(const std::span<const Vertex> vertices, const std::span<const unsigned int> indices, GLenum m) :
m_numIndices {static_cast<GLsizei>(indices.size())}, mode {m}
{
- VertexArrayObject<Vertex>::configure<&Vertex::pos, &Vertex::texCoord, &Vertex::normal, &Vertex::colour,
- &Vertex::material>(
- m_vertexArrayObject, m_vertexArrayBuffers[0], m_vertexArrayBuffers[1], vertices, indices);
+ VertexArrayObject::data(vertices, m_vertexArrayBuffers[0], GL_ARRAY_BUFFER);
+ VertexArrayObject::data(indices, m_vertexArrayBuffers[1], GL_ARRAY_BUFFER);
+ configureVAO(m_vertexArrayObject);
+}
+
+VertexArrayObject &
+Mesh::configureVAO(VertexArrayObject && vao) const
+{
+ return vao
+ .addAttribs<Vertex, &Vertex::pos, &Vertex::texCoord, &Vertex::normal, &Vertex::colour, &Vertex::material>(
+ m_vertexArrayBuffers[0])
+ .addIndices(m_vertexArrayBuffers[1]);
+}
+
+GLsizei
+Mesh::count() const
+{
+ return m_numIndices;
+}
+
+GLenum
+Mesh::type() const
+{
+ return mode;
}
void
diff --git a/gfx/models/mesh.h b/gfx/models/mesh.h index 25a9064..472b7ed 100644 --- a/gfx/models/mesh.h +++ b/gfx/models/mesh.h @@ -7,12 +7,16 @@ #include <stdTypeDefs.hpp>
class Vertex;
+class VertexArrayObject;
class Mesh : public ConstTypeDefs<Mesh> {
public:
Mesh(const std::span<const Vertex> vertices, const std::span<const unsigned int> indices, GLenum = GL_TRIANGLES);
void Draw() const;
+ VertexArrayObject & configureVAO(VertexArrayObject &&) const;
+ GLsizei count() const;
+ GLenum type() const;
private:
glVertexArray m_vertexArrayObject;
|