//////////////////////////////////////////////////////////////////////////////// // Copyright (c) 2012, Computer Graphics Group RWTH Aachen University // // All rights reserved. // //////////////////////////////////////////////////////////////////////////////// #ifndef ACGL_OPENGL_OBJECTS_UNIFORM_BUFFER_HH #define ACGL_OPENGL_OBJECTS_UNIFORM_BUFFER_HH /** * A uniform buffer is an OpenGL buffer object bound to a uniform buffer location. * It can be used: * provide the same set of uniforms to different ShaderPrograms without setting the values multiple times * set multiple uniform variables at once by mapping the buffer into the CPU memory, memset all values and unmap it (quickest way to change a lot of uniforms). * quick switching between multiple sets of uniforms (e.g. material properties). * * To be used, uniforms must be organized in a uniform block, this block has to be bound * to the same location the uniform buffer gets bound to (quite similar to textures). * * If only advantage one is requested, the individual offsets along with the uniform names * can be saved in a uniform buffer to set the uniforms by setUniform() as it would be done * for normal uniforms in a ShaderProgram. * Otherwise the exact memory layout must be known, which can be queried by OpenGL, but which * is also well defined in the case of std140-blocks (see OpenGL spec). * * In contrast to ShaderPrograms, nothing has to be activated before setUniform can be called * here. */ #include #include #include #include #include #include #include #if (ACGL_OPENGL_VERSION >= 31) namespace ACGL{ namespace OpenGL{ class UniformBuffer : public Buffer { // ========================================================================================================= \/ // ============================================================================================ CONSTRUCTORS \/ // ========================================================================================================= \/ public: UniformBuffer() : Buffer(GL_UNIFORM_BUFFER) {} UniformBuffer( SharedBufferObject _pBuffer ) : Buffer(_pBuffer, GL_UNIFORM_BUFFER) {} // ==================================================================================================== \/ // ============================================================================================ GETTERS \/ // ==================================================================================================== \/ public: /** returns the byte offset of a uniform within the buffer * Needed to upload the new value of the uniform. * Initially the UniformBuffer does not know any locations as it is just unstructured memory with no * intrinsic meaning, so the locations have to be queried from the matching ShaderProgram and provided * to the UniformBuffer. This is optional, the application can also know the layout and upload the data * without storing/querying the mappings to/from the buffer. */ GLint getUniformOffset (const std::string& _nameInShader) const { if (!uniformNameToOffsetMap) return -1; return uniformNameToOffsetMap->getLocation(_nameInShader); } void setUniformOffsets (SharedLocationMappings _uniformNameToOffsetMap) { uniformNameToOffsetMap = _uniformNameToOffsetMap; } // ==================================================================================================== \/ // ============================================================================================ SETTERS \/ // ==================================================================================================== \/ public: //! reserve a number of bytes on the GPU for uniforms inline void reserveMemory(GLsizeiptr _size){ setData( _size, NULL, GL_STREAM_DRAW ); } //! uniform setters for scalar types: can only work if the offset-uniformname mapping was set before via setUniformOffsets() inline void setUniform (const std::string &_nameInShader, GLfloat _v) { setUniformScalar (_nameInShader, _v); } inline void setUniform (const std::string &_nameInShader, GLint _v) { setUniformScalar (_nameInShader, _v); } inline void setUniform (const std::string &_nameInShader, GLuint _v) { setUniformScalar (_nameInShader, _v); } inline void setUniform (const std::string &_nameInShader, GLboolean _v) { setUniformScalar(_nameInShader, _v); } inline void setUniform (const std::string &_nameInShader, GLdouble _v) { setUniformScalar (_nameInShader, _v); } //! uniform setters for glm types: can only work if the offset-uniformname mapping was set before via setUniformOffsets() template void setUniform (const std::string &_nameInShader, T _v) { GLint offset = getUniformOffset( _nameInShader ); if (offset == -1) { ACGL::Utils::error() << "UniformBuffer does not know uniform " << _nameInShader << std::endl; return; } setSubData( offset, sizeof(T), glm::value_ptr(_v) ); } // =================================================================================================== \/ // ============================================================================================ FIELDS \/ // =================================================================================================== \/ private: // template for scalar types: private as the setUniform() functions above map to this template void setUniformScalar (const std::string &_nameInShader, T _v) { GLint offset = getUniformOffset( _nameInShader ); if (offset == -1) { ACGL::Utils::error() << "UniformBuffer does not know uniform " << _nameInShader << std::endl; return; } setSubData( offset, sizeof(T), &_v ); } SharedLocationMappings uniformNameToOffsetMap; }; ACGL_SMARTPOINTER_TYPEDEFS(UniformBuffer) } // OpenGL } // ACGL #endif // OpenGL >= 3.1 #endif // ACGL_OPENGL_OBJECTS_UNIFORM_BUFFER_HH