diff --git a/include/ACGL/OpenGL/Objects/FrameBufferObject.hh b/include/ACGL/OpenGL/Objects/FrameBufferObject.hh index 1085e78e153b9bac622134dc096324f73644f983..09656c6b408f9080e10870008f2457e9c8b66d9b 100644 --- a/include/ACGL/OpenGL/Objects/FrameBufferObject.hh +++ b/include/ACGL/OpenGL/Objects/FrameBufferObject.hh @@ -30,7 +30,7 @@ #include <ACGL/OpenGL/Tools.hh> #include <ACGL/OpenGL/Objects/RenderBuffer.hh> #include <ACGL/OpenGL/Objects/Texture.hh> -#include <ACGL/OpenGL/Objects/ShaderProgram.hh> +//#include <ACGL/OpenGL/Objects/ShaderProgram.hh> #include <ACGL/OpenGL/Objects/LocationMappings.hh> #include <vector> @@ -43,12 +43,6 @@ class FrameBufferObject { ACGL_NOT_COPYABLE(FrameBufferObject) - // =================================================================================================== \/ - // ============================================================================================ STATIC \/ - // =================================================================================================== \/ -private: - static GLuint msBuffers[8]; - // ==================================================================================================== \/ // ============================================================================================ STRUCTS \/ // ==================================================================================================== \/ @@ -56,10 +50,10 @@ public: //! An attachment can be a texture or a render buffer struct Attachment { - std::string name; - ConstSharedTexture texture; - ConstSharedRenderBuffer renderBuffer; - int_t fragDataLocation; // the frag data location that maps to this attachment + std::string name; // user defined name that matches the fragment shader out + ConstSharedTexture texture; // attached color texture, or: + ConstSharedRenderBuffer renderBuffer; // attached renderbuffer - only this or the texture should be set! + GLuint location; // the frag data location that maps to this attachment }; // ===================================================================================================== \/ @@ -74,10 +68,7 @@ public: public: FrameBufferObject(void) : mObjectName(0), - mDrawBuffers(0), mColorAttachments(), - mColorAttachmentIndices(), - mFragDataLocationIndices(), mDepthAttachment() { glGenFramebuffers(1, &mObjectName); @@ -86,9 +77,10 @@ public: ACGL::Utils::error() << "could not generate FrameBufferObject!" << std::endl; return; } - mDepthAttachment.name = ""; - mDepthAttachment.texture = ConstSharedTexture(); + mDepthAttachment.texture = ConstSharedTexture(); mDepthAttachment.renderBuffer = ConstSharedRenderBuffer(); + mDepthAttachment.name = ""; // not useful here + mDepthAttachment.location = -1; // not useful here } virtual ~FrameBufferObject(void) @@ -140,56 +132,36 @@ public: openGLRareError(); }*/ + //! let OpenGL validate the completeness bool isFrameBufferObjectComplete() const; - inline bool attachColorRenderBuffer(const std::string _name, const ConstSharedRenderBuffer& _renderBuffer) + /* + * Attach another RenderBuffer as a render target. If the name already exists the old target will get replaced. + */ + inline bool attachColorRenderBuffer(const std::string &_name, const ConstSharedRenderBuffer& _renderBuffer) { - bind(); - glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mDrawBuffers, GL_RENDERBUFFER, _renderBuffer->getObjectName() ); - if (openGLCommonErrorOccured()) - { - Utils::error() << "Attaching of render buffer to the FBO failed" << std::endl; - return false; - } - - Attachment attachment = {_name, SharedTexture(), _renderBuffer}; - mColorAttachments.push_back(attachment); - mColorAttachmentIndices[_name] = mDrawBuffers; - mFragDataLocationIndices[mDrawBuffers] = mDrawBuffers; - mDrawBuffers++; - return true; + return attachColorAttachment( (Attachment){_name, SharedTexture(), _renderBuffer, mColorAttachments.size()} ); } - inline bool attachColorTexture(const std::string _name, const ConstSharedTexture& _texture) + inline bool attachColorTexture(const std::string &_name, const ConstSharedTexture& _texture) { - bind(); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mDrawBuffers, _texture->getTarget(), _texture->getObjectName(), 0 ); - if (openGLCommonErrorOccured()) - { - Utils::error() << "Attaching of texture to the FBO failed" << std::endl; - return false; - } - - Attachment attachment = {_name, _texture, SharedRenderBuffer()}; - mColorAttachments.push_back(attachment); - mColorAttachmentIndices[_name] = mDrawBuffers; - mFragDataLocationIndices[mDrawBuffers] = mDrawBuffers; - mDrawBuffers++; - return true; + return attachColorAttachment( (Attachment){_name, _texture, SharedRenderBuffer(), mColorAttachments.size()} ); } - inline bool setColorRenderBuffer(const std::string _name, const ConstSharedRenderBuffer& _renderBuffer) + inline bool attachColorRenderBuffer(const std::string &_name, const ConstSharedRenderBuffer& _renderBuffer, GLuint _location ) { - glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mColorAttachmentIndices[_name], GL_RENDERBUFFER, _renderBuffer->getObjectName() ); - return true; + return attachColorAttachment( (Attachment){_name, SharedTexture(), _renderBuffer, _location} ); } - inline bool setColorTexture(const std::string _name, const ConstSharedTexture& _texture) + inline bool attachColorTexture(const std::string &_name, const ConstSharedTexture& _texture, GLuint _location ) { - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + mColorAttachmentIndices[_name], _texture->getTarget(), _texture->getObjectName(), 0 ); - return true; + return attachColorAttachment( (Attachment){_name, _texture, SharedRenderBuffer(), _location} ); } + bool attachColorAttachment( const Attachment &_attachment ); + + void remapAttachments(); + inline bool setDepthRenderBuffer(const ConstSharedRenderBuffer& _renderBuffer) { glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, _renderBuffer->getObjectName() ); @@ -226,30 +198,20 @@ public: // =========================================================================================== METHODS \/ // =================================================================================================== \/ public: - - //! updates the attachment locations of this FBO so they match the locations of fragment shader output - //! variables of the same names in _shaderPorgram - void setAttachmentsByShaderProgram(ConstSharedShaderProgram _shaderProgram); - //! sets the attachment locations of this FBO where they match the names specified in _locationMappings void setAttachmentLocations(ConstSharedLocationMappings _locationMappings); -protected: - //! maps the frag data locations specified in mFragDataLocationIndices to the respective color attachments - void updateDrawBuffers(); + //! get a list of attachment locations and names that can be used to set up a ShaderProgram + SharedLocationMappings getAttachmentLocations(); // =================================================================================================== \/ // ============================================================================================ FIELDS \/ // =================================================================================================== \/ protected: GLuint mObjectName; - GLsizei mDrawBuffers; AttachmentVec mColorAttachments; - - std::map<std::string, int> mColorAttachmentIndices; // maps color attachment names to attachment indices (GL_COLOR_ATTACHMENT0 + i) - std::map<int, int> mFragDataLocationIndices; // maps fragment data locations to attachment indices (GL_COLOR_ATTACHMENT0 + i) - - Attachment mDepthAttachment; // depth and stencil are combined + Attachment mDepthAttachment; // depth and stencil are combined + GLuint mBufferMappings[8]; // maps from mColorAttachment.loction (shader outs) to FBO locations (order of mColorAttachments) }; ACGL_SHARED_TYPEDEF(FrameBufferObject) diff --git a/include/ACGL/OpenGL/Objects/ShaderProgram.hh b/include/ACGL/OpenGL/Objects/ShaderProgram.hh index e1dd512fea3bcd4651416c8f84b642247f3c6079..8ed1dcb6ae9fbd85aa5f613304ad39b03810842b 100644 --- a/include/ACGL/OpenGL/Objects/ShaderProgram.hh +++ b/include/ACGL/OpenGL/Objects/ShaderProgram.hh @@ -99,39 +99,51 @@ public: // ============================================================================================ WRAPPERS \/ // ===================================================================================================== \/ public: - inline GLint getUniformLocation (const std::string& _nameInShader) const { return glGetUniformLocation (mObjectName, _nameInShader.c_str()); } - inline GLint getAttributeLocation (const std::string& _nameInShader) const { return glGetAttribLocation (mObjectName, _nameInShader.c_str()); } - inline void bindAttributeLocation (const std::string& _nameInShader, GLuint _location) const { glBindAttribLocation (mObjectName, _location, _nameInShader.c_str()); } - -#if (ACGL_OPENGL_VERSION >= 30) - inline GLint getFragmentDataLocation (const std::string& _nameInShader) const { return glGetFragDataLocation(mObjectName, _nameInShader.c_str()); } - inline void bindFragmentDataLocation (const std::string& _nameInShader, GLuint _location) const { glBindFragDataLocation (mObjectName, _location, _nameInShader.c_str()); } -#endif // OpenGL >= 3.0 - + //! use, or activate it for rendering, also needed to set uniforms: inline void use(void) const { glUseProgram(mObjectName); } + //! attach a single shader, don't forget to relink! inline void attachShader(const ConstSharedShader& _shader) { mShaders.push_back(_shader); glAttachShader( mObjectName, _shader->getObjectName() ); } + //! link the program, has to be redone after changing input or output locations: bool link (void) const; // ===================================================================================================== \/ - // ============================================================================================= METHODS \/ + // =========================================================================================== LOCATIONS \/ // ===================================================================================================== \/ -public: - // Matches the attribute locations of this ShaderProgram to the names of the ArrayBuffer attributes currently attached to _vao - //void setAttributeLocationsByVAO( ConstSharedVertexArrayObject _vao ); - // Matches the fragment data locations of this ShaderProgram to the names of the color attachments of _fbo - //void setFragmentDataLocationsByFBO( ConstSharedFrameBufferObject _fbo ); + + //////////// uniform locations: + inline GLint getUniformLocation (const std::string& _nameInShader) const { return glGetUniformLocation (mObjectName, _nameInShader.c_str()); } + + //////////// attribute locations: + inline GLint getAttributeLocation (const std::string& _nameInShader) const { return glGetAttribLocation (mObjectName, _nameInShader.c_str()); } + inline void bindAttributeLocation (const std::string& _nameInShader, GLuint _location) const { glBindAttribLocation (mObjectName, _location, _nameInShader.c_str()); } //! Sets the attribute locations of this ShaderProgram according to the mappings specified in void setAttributeLocations( ConstSharedLocationMappings _locationMappings ); + //! Get all attribute names with there locations: + SharedLocationMappings getAttributeLocations(); + + //////////// fragdata locations: +#if (ACGL_OPENGL_VERSION >= 30) + inline GLint getFragmentDataLocation (const std::string& _nameInShader) const { return glGetFragDataLocation(mObjectName, _nameInShader.c_str()); } + inline void bindFragmentDataLocation (const std::string& _nameInShader, GLuint _location) const { glBindFragDataLocation (mObjectName, _location, _nameInShader.c_str()); } //! Sets the fragment data locations of this ShaderProgram according to the mappings specified in void setFragmentDataLocations( ConstSharedLocationMappings _locationMappings ); + //! Get all fragdata names with there locations: + SharedLocationMappings getFragmentDataLocations(); +#endif // OpenGL >= 3.0 + + + // Matches the attribute locations of this ShaderProgram to the names of the ArrayBuffer attributes currently attached to _vao + //void setAttributeLocationsByVAO( ConstSharedVertexArrayObject _vao ); + // Matches the fragment data locations of this ShaderProgram to the names of the color attachments of _fbo + //void setFragmentDataLocationsByFBO( ConstSharedFrameBufferObject _fbo ); // ===================================================================================================== \/ // ============================================================================================ UNIFORMS \/ diff --git a/src/ACGL/OpenGL/Objects/FrameBufferObject.cc b/src/ACGL/OpenGL/Objects/FrameBufferObject.cc index 46697c28cb83971196e977286b45a499a935fe7d..84ad31b5d6724f39626368ce823195c515e5869c 100644 --- a/src/ACGL/OpenGL/Objects/FrameBufferObject.cc +++ b/src/ACGL/OpenGL/Objects/FrameBufferObject.cc @@ -8,21 +8,6 @@ using namespace ACGL; using namespace ACGL::OpenGL; -/* - * We can't use the constants GL_COLOR_ATTACHMENT1 to GL_COLOR_ATTACHMENT7 here - * because OpenGL ES does not know these yet. - */ - GLuint FrameBufferObject::msBuffers[8] = { - GL_COLOR_ATTACHMENT0, - GL_COLOR_ATTACHMENT0+1, - GL_COLOR_ATTACHMENT0+2, - GL_COLOR_ATTACHMENT0+3, - GL_COLOR_ATTACHMENT0+4, - GL_COLOR_ATTACHMENT0+5, - GL_COLOR_ATTACHMENT0+6, - GL_COLOR_ATTACHMENT0+7}; - - int_t FrameBufferObject::getColorAttachmentIndexByName(const std::string& _name) const { for(AttachmentVec::size_type i = 0; i < mColorAttachments.size(); i++) @@ -96,132 +81,103 @@ void FrameBufferObject::validate(void) const Utils::error() << "FrameBufferObject validation failed: No color attachments."<< std::endl; } -void FrameBufferObject::setAttachmentsByShaderProgram(ConstSharedShaderProgram _shaderProgram) +bool FrameBufferObject::attachColorAttachment( const Attachment &_attachment ) { - // TODO: deprecate + int realLocation = -1; - bool needsUpdate = false; + for (unsigned int i = 0; i < mColorAttachments.size(); ++i) { + if (mColorAttachments[i].name == _attachment.name) { + // replace this attachment + mColorAttachments[i] = _attachment; + realLocation = i; + } + } + if (realLocation == -1) { + // it's a new attachment + realLocation = mColorAttachments.size(); + mColorAttachments.push_back(_attachment); + } - for(AttachmentVec::size_type i = 0; i < mColorAttachments.size(); i++) + // attach it to the OpenGL object: + bind(); + openGLCriticalErrorOccured(); + if (_attachment.renderBuffer) { + // it's a renderBuffer + glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + realLocation, GL_RENDERBUFFER, _attachment.renderBuffer->getObjectName() ); + } else { + // it's a texture + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + realLocation, _attachment.texture->getTarget(), _attachment.texture->getObjectName(), 0 ); + Utils::debug() << "glFramebufferTexture2D( " << _attachment.name << " to " << realLocation <<" )" << std::endl; + } + if (openGLCommonErrorOccured()) { - GLint fragDataLocation = _shaderProgram->getFragmentDataLocation(mColorAttachments[i].name); + Utils::error() << "Attaching of render target to the FBO failed" << std::endl; + return false; + } - if(fragDataLocation != -1 // does a fragment data location by that name exist in the ShaderProgram? - && fragDataLocation != mColorAttachmentIndices[mColorAttachments[i].name]) // does it match the index of the color attachment? - { - mColorAttachmentIndices[mColorAttachments[i].name] = fragDataLocation; + remapAttachments(); + return true; +} - needsUpdate = true; - } - } +void FrameBufferObject::remapAttachments() +{ + // max color attachments: 8, TODO + const int maxColorBuffers = 8; + GLenum bufferMappings[maxColorBuffers]; + unsigned int attachments = std::min( maxColorBuffers, (int) mColorAttachments.size() ); - if(needsUpdate) - { - bind(); + for (unsigned int i = 0; i < maxColorBuffers; ++i) { + bufferMappings[i] = GL_NONE; + } + for (unsigned int i = 0; i < attachments; ++i) { + bufferMappings[ mColorAttachments[i].location ] = GL_COLOR_ATTACHMENT0 + i; + } - for(AttachmentVec::size_type i = 0; i < mColorAttachments.size(); i++) - { - if(mColorAttachments[i].texture) - glFramebufferTexture2D( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0 + mColorAttachmentIndices[mColorAttachments[i].name], - mColorAttachments[i].texture->getTarget(), - mColorAttachments[i].texture->getObjectName(), - 0 - ); - if(mColorAttachments[i].renderBuffer) - glFramebufferRenderbuffer( - GL_FRAMEBUFFER, - GL_COLOR_ATTACHMENT0 + mColorAttachmentIndices[mColorAttachments[i].name], - GL_RENDERBUFFER, - mColorAttachments[i].renderBuffer->getObjectName() - ); + // debug: + Utils::message() << "remapAttachments: " << std::endl; + for (unsigned int i = 0; i < maxColorBuffers; ++i) { + if (bufferMappings[i] == GL_NONE) { + Utils::debug() << "bufferMappings["<<i<<"] GL_NONE" << std::endl; + } else { + Utils::debug() << "bufferMappings["<<i<<"] "<< bufferMappings[i]-GL_COLOR_ATTACHMENT0 << std::endl; } } + // end debug + - openGLRareError(); + bind(); // glDrawBuffers will get part of the FBO state! + glDrawBuffers( maxColorBuffers, bufferMappings ); } + void FrameBufferObject::setAttachmentLocations(ConstSharedLocationMappings _locationMappings) { bool needsUpdate = false; - // First, erase all existing frag data location mappings that coincide with names specified in _locationMappings for(AttachmentVec::size_type i = 0; i < mColorAttachments.size(); i++) { int_t location = _locationMappings->getLocation(mColorAttachments[i].name); - if(location != -1) // is a mapping by that name specified? + if (location != -1) // is a mapping by that name specified? { - // remove previous frag data location pointing to this color attachment - mFragDataLocationIndices.erase(i); - //ACGL::Utils::debug() << "Dropping attachment for " << mColorAttachments[i].name << " (index " << i << ")" << std::endl; - + mColorAttachments[i].location = location; needsUpdate = true; } } - // Then, wire up the new mappings - for(AttachmentVec::size_type i = 0; i < mColorAttachments.size(); i++) - { - int_t location = _locationMappings->getLocation(mColorAttachments[i].name); - - //ACGL::Utils::debug() << "Color attachment " << mColorAttachments[i].name << " (index " << i << ") should be mapped to frag data location " << location; - //ACGL::Utils::debug() << ". Currently mapped to: " << mFragDataLocationIndices[location] << std::endl; - - if(location != -1) // is a mapping by that name specified? - { - //ACGL::Utils::debug() << "Attaching frag data location " << location << " to color attachment " << i << std::endl; - mFragDataLocationIndices[location] = i; - } - } - - if(needsUpdate) - { - updateDrawBuffers(); - } + if(needsUpdate) remapAttachments(); } -void FrameBufferObject::updateDrawBuffers() -{ - // No fragment data mappings set up? -> Nothing to do - if(mFragDataLocationIndices.size() == 0) - { - return; - } - // The (temporary) buffer mapping table must be large enough to contain all mapped frag data locations - GLint maxDrawBuffers; glGetIntegerv(GL_MAX_DRAW_BUFFERS, &maxDrawBuffers); // TODO: clever caching? - GLsizei numBuffers = std::min(mFragDataLocationIndices.rbegin()->first + 1, maxDrawBuffers); +SharedLocationMappings FrameBufferObject::getAttachmentLocations() +{ + SharedLocationMappings locationMap = SharedLocationMappings( new LocationMappings() ); - GLenum* buffers = new GLenum[numBuffers]; - for(GLsizei i = 0; i < numBuffers; ++i) + for (AttachmentVec::size_type i = 0; i < mColorAttachments.size(); i++) { - // frag data mapping for this index exists? - if(mFragDataLocationIndices.count(i) > 0) - { - // map the frag data location to the given color attachment - buffers[i] = GL_COLOR_ATTACHMENT0 + mFragDataLocationIndices[i]; - //ACGL::Utils::debug() << "mFragDataLocationIndices[" << i << "] = " << mFragDataLocationIndices[i] << std::endl; - } - else - { - buffers[i] = GL_NONE; - } + locationMap->setLocation( mColorAttachments[i].name, mColorAttachments[i].location ); + //ACGL::Utils::debug() << "locationMap->setLocation( "<<mColorAttachments[i].name<<", "<<mColorAttachments[i].location<<" );"<<std::endl; } - // TODO: remove debug output -// ACGL::Utils::debug() << "Uploading mapping:"; -// for(int i = 0; i < numBuffers; ++i) { -// ACGL::Utils::debug() << " " << buffers[i]; -// } -// ACGL::Utils::debug() << std::endl; - - // upload the new mapping - bind(); - glDrawBuffers(numBuffers, buffers); - - delete[] buffers; - - openGLRareError(); + return locationMap; } diff --git a/src/ACGL/OpenGL/Objects/ShaderProgram.cc b/src/ACGL/OpenGL/Objects/ShaderProgram.cc index 02e39ee0f2a2cd123ed6705e7722da896860b286..744a6a746036638223acec1729401dd06d2c4a99 100644 --- a/src/ACGL/OpenGL/Objects/ShaderProgram.cc +++ b/src/ACGL/OpenGL/Objects/ShaderProgram.cc @@ -94,10 +94,13 @@ void ShaderProgram::setFragmentDataLocations(ConstSharedLocationMappings _locati // find out whether a fragment data location with a matching name exists in this shader GLint fragmentDataLocation = getFragmentDataLocation((*it).first); + //ACGL::Utils::debug() << "test ("<<(*it).first<<", "<<(*it).second<<"); loc:"<<fragmentDataLocation<<std::endl; + if ( fragmentDataLocation != -1 // fragment data location with that name exists? && ((GLuint) fragmentDataLocation) != (*it).second) // fragment data location with that name not already bound correctly? { bindFragmentDataLocation((*it).first, (*it).second); + ACGL::Utils::debug() << "bindFragmentDataLocation("<<(*it).first<<", "<<(*it).second<<");"<<std::endl; needsRelink = true; } } @@ -110,6 +113,47 @@ void ShaderProgram::setFragmentDataLocations(ConstSharedLocationMappings _locati } } +SharedLocationMappings ShaderProgram::getAttributeLocations() +{ + SharedLocationMappings locationMap = SharedLocationMappings( new LocationMappings() ); + + // query the number of _active_ attributes: + GLint attributeCount; + glGetProgramiv( mObjectName, GL_ACTIVE_ATTRIBUTES, &attributeCount ); + if (attributeCount == 0) return locationMap; + + // reserve a string long enought for the longest name: + GLint longestAttributeName; + glGetProgramiv( mObjectName, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &longestAttributeName ); + char *name = new char[longestAttributeName+1]; + + // get the name and location of each active attribute: + for (int i = 0; i < attributeCount; ++i) { + GLenum type; + GLint size; + GLsizei length; + glGetActiveAttrib( mObjectName, i, longestAttributeName, &length, &size, &type, name ); + name[ length+1 ] = 0; // null terminate + + GLint attribLocation = glGetAttribLocation( mObjectName, name ); + + //ACGL::Utils::debug() << "found attrib " << name << " at " << attribLocation << std::endl; + + locationMap->setLocation( std::string(name), (GLuint) attribLocation ); + } + + delete name; + return locationMap; +} + +SharedLocationMappings ShaderProgram::getFragmentDataLocations() +{ + SharedLocationMappings locationMap = SharedLocationMappings( new LocationMappings() ); + + ACGL::Utils::error() << " ShaderProgram::getFragmentDataLocations is not implemented -> missing OpenGL API" << std::endl; + + return locationMap; +} /*