diff --git a/.gitignore b/.gitignore index b98dc456..ee08d9f7 100644 --- a/.gitignore +++ b/.gitignore @@ -45,3 +45,4 @@ compile_commands.json *.exe *.out *.app +/.vs diff --git a/include/polyscope/render/engine.h b/include/polyscope/render/engine.h index 48a7493c..6020aeac 100644 --- a/include/polyscope/render/engine.h +++ b/include/polyscope/render/engine.h @@ -36,7 +36,7 @@ enum class DrawMode { TriangleStripInstanced, }; -enum class TextureFormat { RGB8 = 0, RGBA8, RG16F, RGB16F, RGBA16F, RGBA32F, RGB32F, R32F, R16F, DEPTH24 }; +enum class TextureFormat { RGB8 = 0, RGBA8, RG16F, RGB16F, RGBA16F, RGBA32F, RGB32F, R32F, R16F, DEPTH24, R32UI, R32I }; enum class RenderBufferType { Color, ColorAlpha, Depth, Float4 }; enum class DepthMode { Less, LEqual, LEqualReadOnly, Greater, Disable, PassReadOnly }; enum class BlendMode { AlphaOver, OverNoWrite, AlphaUnder, Zero, WeightedAdd, Add, Source, Disable }; @@ -291,12 +291,12 @@ struct ShaderSpecUniform { const RenderDataType type; }; struct ShaderSpecAttribute { - ShaderSpecAttribute(std::string name_, RenderDataType type_) : name(name_), type(type_), arrayCount(1) {} - ShaderSpecAttribute(std::string name_, RenderDataType type_, int arrayCount_) - : name(name_), type(type_), arrayCount(arrayCount_) {} + ShaderSpecAttribute(std::string name_, RenderDataType type_, int arrayCount_ = 1, int attribDivisor = 0) + : name(name_), type(type_), arrayCount(arrayCount_), attribDivisor(attribDivisor) {} const std::string name; const RenderDataType type; const int arrayCount; // number of times this element is repeated in an array + const int attribDivisor; }; struct ShaderSpecTexture { const std::string name; @@ -401,6 +401,7 @@ class ShaderProgram { // Indices virtual void setInstanceCount(uint32_t instanceCount) = 0; + virtual void setInstanceVertexCount(uint32_t instanceVertexCount) = 0; // Call once to initialize GLSL code used by multiple shaders static void initCommonShaders(); // TODO @@ -432,6 +433,7 @@ class ShaderProgram { // instancing uint32_t instanceCount = INVALID_IND_32; + uint32_t instanceVertexCount = INVALID_IND_32; }; @@ -549,6 +551,9 @@ class Engine { unsigned int sizeY_, unsigned int sizeZ_, const float* data) = 0; // 3d + // create buffer texture + virtual std::shared_ptr generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) = 0; + // create render buffers virtual std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) = 0; diff --git a/include/polyscope/render/mock_opengl/mock_gl_engine.h b/include/polyscope/render/mock_opengl/mock_gl_engine.h index bcdb7e3e..7acd96ed 100644 --- a/include/polyscope/render/mock_opengl/mock_gl_engine.h +++ b/include/polyscope/render/mock_opengl/mock_gl_engine.h @@ -139,6 +139,38 @@ class GLTextureBuffer : public TextureBuffer { protected: }; +class GLStorageTextureBuffer : public GLTextureBuffer { +public: + ~GLStorageTextureBuffer() override; + void resize(unsigned newLen) override; + void resize(unsigned newX, unsigned newY) override; + void resize(unsigned newX, unsigned newY, unsigned newZ) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector>& data) override; + void setData(const std::vector>& data) override; + void setData(const std::vector>& data) override; + void setFilterMode(FilterMode newMode) override; + void* getNativeHandle() override; + uint32_t getNativeBufferID() override; + std::vector getDataScalar() override; + std::vector getDataVector2() override; + std::vector getDataVector3() override; + + // Note: underlying buffer uses R32F as the internal format + // to support other formats here resizing, setData and getData need new logic + GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data); +protected: +}; + class GLRenderBuffer : public RenderBuffer { public: GLRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_); @@ -280,8 +312,9 @@ class GLShaderProgram : public ShaderProgram { void setIndex(std::shared_ptr externalBuffer) override; void setPrimitiveRestartIndex(unsigned int restartIndex) override; - // Indices + // Instancing void setInstanceCount(uint32_t instanceCount) override; + void setInstanceVertexCount(uint32_t instanceVertexCount) override; // Textures bool hasTexture(std::string name) override; @@ -384,6 +417,9 @@ class MockGLEngine : public Engine { unsigned int sizeZ_, const float* data) override; // 3d + // create buffer texture + std::shared_ptr generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) override; + // create render buffers std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) override; diff --git a/include/polyscope/render/opengl/gl_engine.h b/include/polyscope/render/opengl/gl_engine.h index ba57b9bd..185641fd 100644 --- a/include/polyscope/render/opengl/gl_engine.h +++ b/include/polyscope/render/opengl/gl_engine.h @@ -30,6 +30,7 @@ namespace backend_openGL3 { // Some very nice typdefs typedef GLuint TextureBufferHandle; +typedef GLuint TextureStorageBufferHandle; typedef GLuint RenderBufferHandle; typedef GLuint FrameBufferHandle; typedef GLuint ShaderHandle; @@ -167,12 +168,52 @@ class GLTextureBuffer : public TextureBuffer { std::vector getDataVector3() override; void bind(); - GLenum textureType(); + virtual GLenum textureType(); TextureBufferHandle getHandle() const { return handle; } protected: TextureBufferHandle handle; + + static GLTextureBuffer createUnintializedTextureBuffer(TextureFormat format, unsigned int size1D); + +private: + GLTextureBuffer(): TextureBuffer(1, TextureFormat::RGB8, 0), handle{0} {} +}; + +class GLStorageTextureBuffer : public GLTextureBuffer { +public: + ~GLStorageTextureBuffer() override; + void resize(unsigned newLen) override; + void resize(unsigned newX, unsigned newY) override; + void resize(unsigned newX, unsigned newY, unsigned newZ) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector& data) override; + void setData(const std::vector>& data) override; + void setData(const std::vector>& data) override; + void setData(const std::vector>& data) override; + void setFilterMode(FilterMode newMode) override; + void* getNativeHandle() override; + uint32_t getNativeBufferID() override; + std::vector getDataScalar() override; + std::vector getDataVector2() override; + std::vector getDataVector3() override; + + GLenum textureType() override; + + // Note: underlying buffer expects a type with 4 bytes and 1 dimension as the internal format + // to support other formats here resizing, setData and getData need new logic + GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data); +protected: + TextureStorageBufferHandle bufferHandle; }; class GLRenderBuffer : public RenderBuffer { @@ -237,6 +278,7 @@ struct GLShaderAttribute { std::string name; RenderDataType type; int arrayCount; + int attribDivisor; AttributeLocation location; // -1 means "no location", usually because it was optimized out std::shared_ptr buff; // the buffer that we will actually use }; @@ -326,6 +368,7 @@ class GLShaderProgram : public ShaderProgram { // Instancing void setInstanceCount(uint32_t instanceCount) override; + void setInstanceVertexCount(uint32_t instanceVertexCount) override; // Textures bool hasTexture(std::string name) override; @@ -403,6 +446,9 @@ class GLEngine : public Engine { unsigned int sizeZ_, const float* data) override; // 3d + // create buffer texture + std::shared_ptr generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) override; + // create render buffers std::shared_ptr generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) override; diff --git a/src/render/engine.cpp b/src/render/engine.cpp index c959a262..a0754afa 100644 --- a/src/render/engine.cpp +++ b/src/render/engine.cpp @@ -25,6 +25,8 @@ int dimension(const TextureFormat& x) { case TextureFormat::RGB32F: return 3; case TextureFormat::RGBA32F: return 4; case TextureFormat::DEPTH24: return 1; + case TextureFormat::R32UI: return 1; + case TextureFormat::R32I: return 1; } // clang-format on exception("bad enum"); @@ -44,6 +46,8 @@ int sizeInBytes(const TextureFormat& f) { case TextureFormat::RGB32F: return 3*4; case TextureFormat::RGBA32F: return 4*4; case TextureFormat::DEPTH24: return 1*3; + case TextureFormat::R32UI: return 1*4; + case TextureFormat::R32I: return 1*4; } // clang-format on return -1; diff --git a/src/render/mock_opengl/mock_gl_engine.cpp b/src/render/mock_opengl/mock_gl_engine.cpp index 405c8366..ebdf9c80 100644 --- a/src/render/mock_opengl/mock_gl_engine.cpp +++ b/src/render/mock_opengl/mock_gl_engine.cpp @@ -519,6 +519,116 @@ void GLTextureBuffer::bind() { checkGLError(); } +GLStorageTextureBuffer::~GLStorageTextureBuffer() {} + +void GLStorageTextureBuffer::resize(unsigned newLen) { + // intentionally skipping the logic of GLTextureBuffer::resize here + TextureBuffer::resize(newLen); // NOLINT(bugprone-parent-virtual-call) + + checkGLError(); +} + +void GLStorageTextureBuffer::resize(unsigned newX, unsigned newY) { + exception("buffer textures only support 1 dimension"); +} + +void GLStorageTextureBuffer::resize(unsigned newX, unsigned newY, unsigned newZ) { + exception("buffer textures only support 1 dimension"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + if (data.size() != getTotalSize()) { + exception("OpenGL error: texture buffer data is not the right size."); + } + + checkGLError(); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector>& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector>& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setData(const std::vector>& data) { + exception("not implemented"); +} + +void GLStorageTextureBuffer::setFilterMode(FilterMode newMode) { + // no-op +} + +void* GLStorageTextureBuffer::getNativeHandle() { + return GLTextureBuffer::getNativeHandle(); +} + +uint32_t GLStorageTextureBuffer::getNativeBufferID() { + return GLTextureBuffer::getNativeBufferID(); +} + +std::vector GLStorageTextureBuffer::getDataScalar() { + std::vector outData; + outData.resize(getTotalSize()); + + return outData; +} + +std::vector GLStorageTextureBuffer::getDataVector2() { + std::vector outData; + outData.resize(getTotalSize()); + exception("not implemented"); + return outData; +} + +std::vector GLStorageTextureBuffer::getDataVector3() { + std::vector outData; + outData.resize(getTotalSize()); + exception("not implemented"); + return outData; +} + +GLStorageTextureBuffer::GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data): GLTextureBuffer{format, size1D} { + if (sizeInBytes(format) != 4 && dimension(format) != 1) exception("Unsupported format specified. Format with 1 dimesnion and 4 bytes expected."); +} + // ============================================================= // ===================== Render buffer ========================= // ============================================================= @@ -1481,6 +1591,9 @@ void GLShaderProgram::validateData() { if (instanceCount == INVALID_IND_32) { throw std::invalid_argument("Must set instance count to use instanced drawing"); } + if (instanceVertexCount == INVALID_IND_32) { + throw std::invalid_argument("Must set instance vertex count to use instanced drawing"); + } } } @@ -1493,6 +1606,7 @@ void GLShaderProgram::setPrimitiveRestartIndex(unsigned int restartIndex_) { } void GLShaderProgram::setInstanceCount(uint32_t instanceCount_) { instanceCount = instanceCount_; } +void GLShaderProgram::setInstanceVertexCount(uint32_t instanceVertexCount_) { instanceVertexCount = instanceVertexCount_; } void GLShaderProgram::activateTextures() { for (GLShaderTexture& t : textures) { @@ -1742,6 +1856,11 @@ std::shared_ptr MockGLEngine::generateTextureBuffer(TextureFormat return std::shared_ptr(newT); } +std::shared_ptr MockGLEngine::generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) { + GLStorageTextureBuffer* newT = new GLStorageTextureBuffer(format, size1D, data); + return std::shared_ptr(newT); +} + std::shared_ptr MockGLEngine::generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) { diff --git a/src/render/opengl/gl_engine.cpp b/src/render/opengl/gl_engine.cpp index eff22285..efb60a89 100644 --- a/src/render/opengl/gl_engine.cpp +++ b/src/render/opengl/gl_engine.cpp @@ -54,6 +54,9 @@ inline GLenum internalFormat(const TextureFormat& x) { case TextureFormat::RGB32F: return GL_RGBA32F; case TextureFormat::RGBA32F: return GL_RGBA32F; case TextureFormat::DEPTH24: return GL_DEPTH_COMPONENT24; + case TextureFormat::R32UI: return GL_R32UI; + case TextureFormat::R32I: return GL_R32I; + break; } exception("bad enum"); return GL_RGB8; @@ -71,6 +74,8 @@ inline GLenum formatF(const TextureFormat& x) { case TextureFormat::RGB32F: return GL_RGB; case TextureFormat::RGBA32F: return GL_RGBA; case TextureFormat::DEPTH24: return GL_DEPTH_COMPONENT; + case TextureFormat::R32UI: return GL_RED; + case TextureFormat::R32I: return GL_RED; } exception("bad enum"); return GL_RGB; @@ -88,6 +93,8 @@ inline GLenum type(const TextureFormat& x) { case TextureFormat::RGB32F: return GL_FLOAT; case TextureFormat::RGBA32F: return GL_FLOAT; case TextureFormat::DEPTH24: return GL_FLOAT; + case TextureFormat::R32UI: return GL_UNSIGNED_INT; + case TextureFormat::R32I: return GL_INT; } exception("bad enum"); return GL_UNSIGNED_BYTE; @@ -770,6 +777,121 @@ void GLTextureBuffer::bind() { checkGLError(); } +GLTextureBuffer GLTextureBuffer::createUnintializedTextureBuffer(TextureFormat format, unsigned int size1D) { + GLTextureBuffer buffer = {}; + buffer.format = format; + buffer.sizeX = size1D; + return buffer; +} + +// ============================================================= +// =================== Storage Texture buffer ================== +// ============================================================= + + + +GLStorageTextureBuffer::~GLStorageTextureBuffer() { + glDeleteBuffers(1, &bufferHandle); +} + +void GLStorageTextureBuffer::setData(const std::vector& data) { + if (data.size() != getTotalSize()) { + exception("OpenGL error: texture buffer data is not the right size."); + } + + glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); + glBufferSubData(GL_TEXTURE_BUFFER, 0, getSizeInBytes(), &data.front()); + glBindBuffer(GL_TEXTURE_BUFFER, 0); + + checkGLError(); +} + +void GLStorageTextureBuffer::resize(unsigned newLen) { + + // intentionally skipping the logic of GLTextureBuffer::resize here + TextureBuffer::resize(newLen); // NOLINT(bugprone-parent-virtual-call) + + glDeleteBuffers(1, &bufferHandle); + + glGenBuffers(1, &bufferHandle); + glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); + glBufferData(GL_TEXTURE_BUFFER, getSizeInBytes(), nullptr, GL_DYNAMIC_DRAW); + + glBindTexture(GL_TEXTURE_BUFFER, handle); + glTexBuffer(GL_TEXTURE_BUFFER, internalFormat(format), bufferHandle); + glBindBuffer(GL_TEXTURE_BUFFER, 0); + + checkGLError(); +} +void GLStorageTextureBuffer::resize(unsigned newX, unsigned newY) { exception("buffer textures only support 1 dimension"); } +void GLStorageTextureBuffer::resize(unsigned newX, unsigned newY, unsigned newZ) { exception("buffer textures only support 1 dimension"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } + +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector>& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector>& data) { exception("not implemented"); } +void GLStorageTextureBuffer::setData(const std::vector>& data) { exception("not implemented"); } + +void GLStorageTextureBuffer::setFilterMode(FilterMode newMode) { + // no op - gsampleBuffer does not have a filter mode +} + +void* GLStorageTextureBuffer::getNativeHandle() { + return GLTextureBuffer::getNativeHandle(); +} + +uint32_t GLStorageTextureBuffer::getNativeBufferID() { + return GLTextureBuffer::getNativeBufferID(); +} + +std::vector GLStorageTextureBuffer::getDataScalar() { + + std::vector outData; + outData.resize(getTotalSize()); + glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); + glGetBufferSubData(GL_TEXTURE_BUFFER, 0, getSizeInBytes(), &outData.front()); + glBindBuffer(GL_TEXTURE_BUFFER, 0); + + checkGLError(); + + return outData; +} +std::vector GLStorageTextureBuffer::getDataVector2() { + exception("not implemented"); + return {}; +} +std::vector GLStorageTextureBuffer::getDataVector3() { + exception("not implemented"); + return {}; +} + +GLenum GLStorageTextureBuffer::textureType() { + return GL_TEXTURE_BUFFER; +} + +GLStorageTextureBuffer::GLStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) : GLTextureBuffer{createUnintializedTextureBuffer(format, size1D)}{ + + if (sizeInBytes(format) != 4 && dimension(format) != 1) exception("Unsupported format specified. Format with 1 dimesnion and 4 bytes expected."); + + glGenBuffers(1, &bufferHandle); + glBindBuffer(GL_TEXTURE_BUFFER, bufferHandle); + glBufferData(GL_TEXTURE_BUFFER, getSizeInBytes(), data, GL_DYNAMIC_DRAW); + + glGenTextures(1, &handle); + glBindTexture(GL_TEXTURE_BUFFER, handle); + glTexBuffer(GL_TEXTURE_BUFFER, internalFormat(format), bufferHandle); + glBindBuffer(GL_TEXTURE_BUFFER, 0); + + checkGLError(); +} + // ============================================================= // ===================== Render buffer ========================= // ============================================================= @@ -1174,7 +1296,7 @@ void GLCompiledProgram::addUniqueAttribute(ShaderSpecAttribute newAttribute) { return; } } - attributes.push_back(GLShaderAttribute{newAttribute.name, newAttribute.type, newAttribute.arrayCount, -1, nullptr}); + attributes.push_back(GLShaderAttribute{newAttribute.name, newAttribute.type, newAttribute.arrayCount, newAttribute.attribDivisor, -1, nullptr}); } void GLCompiledProgram::addUniqueUniform(ShaderSpecUniform newUniform) { @@ -1299,11 +1421,11 @@ void GLShaderProgram::assignBufferToVAO(GLShaderAttribute& a) { reinterpret_cast(sizeof(float) * 1 * iArrInd)); break; case RenderDataType::Int: - glVertexAttribPointer(a.location + iArrInd, 1, GL_INT, GL_FALSE, sizeof(int) * 1 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 1, GL_INT, sizeof(int) * 1 * a.arrayCount, reinterpret_cast(sizeof(int) * 1 * iArrInd)); break; case RenderDataType::UInt: - glVertexAttribPointer(a.location + iArrInd, 1, GL_UNSIGNED_INT, GL_FALSE, sizeof(uint32_t) * 1 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 1, GL_UNSIGNED_INT, sizeof(uint32_t) * 1 * a.arrayCount, reinterpret_cast(sizeof(uint32_t) * 1 * iArrInd)); break; case RenderDataType::Vector2Float: @@ -1319,21 +1441,26 @@ void GLShaderProgram::assignBufferToVAO(GLShaderAttribute& a) { reinterpret_cast(sizeof(float) * 4 * iArrInd)); break; case RenderDataType::Vector2UInt: - glVertexAttribPointer(a.location + iArrInd, 2, GL_UNSIGNED_INT, GL_FALSE, sizeof(uint32_t) * 2 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 2, GL_UNSIGNED_INT, sizeof(uint32_t) * 2 * a.arrayCount, reinterpret_cast(sizeof(uint32_t) * 2 * iArrInd)); break; case RenderDataType::Vector3UInt: - glVertexAttribPointer(a.location + iArrInd, 3, GL_UNSIGNED_INT, GL_FALSE, sizeof(uint32_t) * 3 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 3, GL_UNSIGNED_INT, sizeof(uint32_t) * 3 * a.arrayCount, reinterpret_cast(sizeof(uint32_t) * 3 * iArrInd)); break; case RenderDataType::Vector4UInt: - glVertexAttribPointer(a.location + iArrInd, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(uint32_t) * 4 * a.arrayCount, + glVertexAttribIPointer(a.location + iArrInd, 4, GL_UNSIGNED_INT, sizeof(uint32_t) * 4 * a.arrayCount, reinterpret_cast(sizeof(uint32_t) * 4 * iArrInd)); break; default: throw std::invalid_argument("Unrecognized GLShaderAttribute type"); break; } + + if (a.attribDivisor > 0) { + glVertexAttribDivisor(a.location + iArrInd, a.attribDivisor); + } + } checkGLError(); @@ -2019,6 +2146,9 @@ void GLShaderProgram::validateData() { if (instanceCount == INVALID_IND_32) { throw std::invalid_argument("Must set instance count to use instanced drawing"); } + if (instanceVertexCount == INVALID_IND_32) { + throw std::invalid_argument("Must set instance vertex count to use instanced drawing"); + } } } @@ -2031,6 +2161,7 @@ void GLShaderProgram::setPrimitiveRestartIndex(unsigned int restartIndex_) { } void GLShaderProgram::setInstanceCount(uint32_t instanceCount_) { instanceCount = instanceCount_; } +void GLShaderProgram::setInstanceVertexCount(uint32_t instanceVertexCount_) { instanceVertexCount = instanceVertexCount_; } void GLShaderProgram::activateTextures() { for (GLShaderTexture& t : textures) { @@ -2092,10 +2223,10 @@ void GLShaderProgram::draw() { glDrawElements(GL_TRIANGLES, drawDataLength, GL_UNSIGNED_INT, 0); break; case DrawMode::TrianglesInstanced: - glDrawArraysInstanced(GL_TRIANGLES, 0, drawDataLength, instanceCount); + glDrawArraysInstanced(GL_TRIANGLES, 0, instanceVertexCount, instanceCount); break; case DrawMode::TriangleStripInstanced: - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, drawDataLength, instanceCount); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, instanceVertexCount, instanceCount); break; } @@ -2288,6 +2419,11 @@ std::shared_ptr GLEngine::generateTextureBuffer(TextureFormat for return std::shared_ptr(newT); } +std::shared_ptr GLEngine::generateStorageTextureBuffer(TextureFormat format, unsigned int size1D, void* data) { + GLStorageTextureBuffer* newT = new GLStorageTextureBuffer(format, size1D, data); + return std::shared_ptr(newT); +} + std::shared_ptr GLEngine::generateRenderBuffer(RenderBufferType type, unsigned int sizeX_, unsigned int sizeY_) { GLRenderBuffer* newR = new GLRenderBuffer(type, sizeX_, sizeY_);