diff --git a/include/ACGL/Base/FileHelpers.hh b/include/ACGL/Base/FileHelpers.hh index e24b5a6e071f44845081f533da5eb9fb6f632891..d80270ce1e92b918fc74c32c570c6e9af130c5a1 100644 --- a/include/ACGL/Base/FileHelpers.hh +++ b/include/ACGL/Base/FileHelpers.hh @@ -48,7 +48,7 @@ namespace FileHelpers /* * Splits a string at the delim char. */ - //void splitString(const std::string &s, char delim, std::vector<std::string> &elems); + void splitString(const std::string &s, char delim, std::vector<std::string> &elems); /* diff --git a/include/ACGL/OpenGL/Objects/ArrayBuffer.hh b/include/ACGL/OpenGL/Objects/ArrayBuffer.hh index 5bfa2afa6d4d1d43983c6ac46fdfd7dee3999d4b..24b3f729a3bffb8c5a348871503e56c7eb9ef399 100644 --- a/include/ACGL/OpenGL/Objects/ArrayBuffer.hh +++ b/include/ACGL/OpenGL/Objects/ArrayBuffer.hh @@ -118,6 +118,9 @@ public: //! Returns the definitions of the attributes: inline const AttributeVec& getAttributes (void) const { return mAttributes; } + //! Returns one attribute: + inline Attribute getAttribute( uint_t i ) const { return mAttributes[i]; } + // ==================================================================================================== \/ // ============================================================================================ METHODS \/ // ==================================================================================================== \/ diff --git a/include/ACGL/OpenGL/Objects/LocationMappings.hh b/include/ACGL/OpenGL/Objects/LocationMappings.hh index e59948cec549e1ec8a585ada17f3121830042936..d8fc70bc3647f3ddb2f3f1ff7a3aa29e52d55440 100644 --- a/include/ACGL/OpenGL/Objects/LocationMappings.hh +++ b/include/ACGL/OpenGL/Objects/LocationMappings.hh @@ -77,6 +77,8 @@ public: //! Tells whether a mapping for a given name exists inline bool exists(const std::string& _name) const { return (getLocation(_name) != -1); } + void printMapping(); + // =================================================================================================== \/ // ============================================================================================ FIELDS \/ // =================================================================================================== \/ diff --git a/include/ACGL/OpenGL/Objects/VertexArrayObject.hh b/include/ACGL/OpenGL/Objects/VertexArrayObject.hh index f9f14a55fc90fedd9ff62497d71c14b708bf7259..78c38a387418aa7ebb075733e6ba0301cf702f66 100755 --- a/include/ACGL/OpenGL/Objects/VertexArrayObject.hh +++ b/include/ACGL/OpenGL/Objects/VertexArrayObject.hh @@ -54,7 +54,7 @@ public: { SharedArrayBuffer arrayBuffer; // the ArrayBuffer to use int32_t attributeID; // the attribute from that ArrayBuffer - GLint location; // a location the in-attribute from a shader is bound to + //GLint location; // a location the in-attribute from a shader is bound to // more Attribute properties can be looked up in the ArrayBuffer (like the name) }; @@ -62,7 +62,7 @@ public: // ============================================================================================ TYPEDEFS \/ // ===================================================================================================== \/ public: - typedef std::vector< Attribute > AttributeVec; + typedef std::vector< Attribute > AttributeVec; // position in the vector == attrib location // ========================================================================================================= \/ // ============================================================================================ CONSTRUCTORS \/ @@ -75,9 +75,14 @@ public: mMode(GL_TRIANGLES) { glGenVertexArrays(1, &mObjectName); + GLint maxAttributes; + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttributes); + if (openGLCriticalErrorOccured() ) { ACGL::Utils::error() << "could not generate vertex array object!" << std::endl; } + + mAttributes.resize( maxAttributes ); // reserve probably 16 slots, the size() can now be used to query the MAX_VERTEX_ATTRIBS } virtual ~VertexArrayObject(void) @@ -120,13 +125,6 @@ public: // ============================================================================================ METHODS \/ // ==================================================================================================== \/ public: - /** - * Will check if the VAO looks ok (e.g. there is at least one ArrayBuffer and all ArrayBuffers - * have the same number of elements). - * A failed test will output an error but won't have other consequences. - */ - bool isValid(void) const; - /** * Set the given ElementArrayBuffer, if a NULL pointer is given, an existing EAB will get unset. * Will restore the previously bound VAO (DSA style) @@ -140,21 +138,21 @@ public: * Will set the attribute _arrayBufferAttribute of ArrayBuffer _arrayBuffer to the given attribute location. * If that location was already used it will get overwritten. * The _attributeLocation has to be lower than GL_MAX_VERTEX_ATTRIBS - * An attribute location of -1 indicates that the attribute should remain unbound for now + * An attribute location of -1 indicates that the attribute should get the next free location */ inline void attachAttribute( const SharedArrayBuffer& _arrayBuffer, uint32_t _arrayBufferAttribute, GLint _attributeLocation = -1) { - Attribute newAttribute = { _arrayBuffer, _arrayBufferAttribute, _attributeLocation }; - attachAttribute( newAttribute ); + Attribute newAttribute = { _arrayBuffer, _arrayBufferAttribute }; + attachAttribute( newAttribute, _attributeLocation ); } /** * Will set the attribute named _arrayBufferAttributeName of ArrayBuffer _arrayBuffer to the given attribute location. * If that location was already used it will get overwritten. * The _attributeLocation has to be lower than GL_MAX_VERTEX_ATTRIBS - * An attribute location of -1 indicates that the attribute should remain unbound for now + * An attribute location of -1 indicates that the attribute should should get the next free location */ inline void attachAttribute( const SharedArrayBuffer& _arrayBuffer, const std::string& _arrayBufferAttributeName, @@ -165,19 +163,21 @@ public: _attributeLocation); } - void attachAttribute( const Attribute &_attribute ); + //! if the location was already in use, the new attribute will replace it, if a free loc should be used but no location is free, + //! nothing will get attached. + void attachAttribute( const Attribute &_attribute, GLint _location ); /** * Attaches all attributes defined by an ArrayBuffer - * The attributes are attached to the default location of -1, indicating they should remain unbound for now + * The attributes are attached to the next free location. * Afterwards, you might want to automatically wire up the attributes with a ShaderProgram, using setAttributeLocationsByShaderProgram */ void attachAllAttributes( const SharedArrayBuffer& _arrayBuffer ); /** - * Will detach the first found Attribute with the given attribute location. + * Will detach the Attribute with the given attribute location. */ - void detachAttribute( GLint _location ); + void detachAttribute( GLuint _location ); /** * Will detach the first found Attribute with the given name. @@ -190,11 +190,17 @@ public: */ void setAttributeLocations( ConstSharedLocationMappings _locationMappings ); + //! get a list of attribute locations and names that can be used to set up a ShaderProgram + SharedLocationMappings getAttributeLocations(); + private: - //! Sets the vertex attribute pointer for the current VAO according to the specified attribute data + //! Sets the vertex attribute pointer for the current VAO according to the specified attribute (index into mAttributes) //! Note: expects that this VAO is currently bound //! Note: will bind the ArrayBuffer referenced by _attribute.arrayBuffer - void setAttributePointer(const Attribute& _attribute); + void setAttributePointer( GLuint _index ); + + //! returns a free attribute location between 0 .. MAX_ATTRIB_LOCATIONS unless no location is free, in that case returns -1 + GLint getFreeAttributeLocation(); // ===================================================================================================== \/ // ============================================================================================ WRAPPERS \/ diff --git a/src/ACGL/Base/FileHelpers.cc b/src/ACGL/Base/FileHelpers.cc index 22b8f2f384285fc9340b4edb44f09b213f28045c..7b037de49a12666e5654286ffb6aa7018a4adecf 100644 --- a/src/ACGL/Base/FileHelpers.cc +++ b/src/ACGL/Base/FileHelpers.cc @@ -73,6 +73,8 @@ namespace FileHelpers return false; } + */ + // copied from stackoverflow void splitString(const std::string &s, char delim, std::vector<std::string> &elems) { @@ -87,7 +89,6 @@ namespace FileHelpers elems.push_back(item); } } - */ #ifndef PLATFORM_IOS std::string getDeviceDependentPathFor( const std::string &resource ) diff --git a/src/ACGL/OpenGL/Objects/LocationMappings.cc b/src/ACGL/OpenGL/Objects/LocationMappings.cc index 204e9be1fbc7feda09e6852e397cb3da79466066..49c1db092fa8d4f14ab89d5daaed61e94fbbce94 100644 --- a/src/ACGL/OpenGL/Objects/LocationMappings.cc +++ b/src/ACGL/OpenGL/Objects/LocationMappings.cc @@ -31,3 +31,12 @@ void LocationMappings::setLocation(const std::string& _name, GLuint _location) } mMappings[_name] = _location; } + + +void LocationMappings::printMapping() +{ + LocationMap::const_iterator end = mMappings.end(); + for (LocationMap::const_iterator it = mMappings.begin(); it != end; ++it) { + ACGL::Utils::debug() << "loc mapping: " << it->first << " - " << it->second << std::endl; + } +} diff --git a/src/ACGL/OpenGL/Objects/Sampler.cc b/src/ACGL/OpenGL/Objects/Sampler.cc index e149ab53395669c3df8ddd6768163ec0d1eaaa99..20cc9cfe111eaa9d20209707ec1966020c445537 100644 --- a/src/ACGL/OpenGL/Objects/Sampler.cc +++ b/src/ACGL/OpenGL/Objects/Sampler.cc @@ -5,6 +5,8 @@ #include <ACGL/OpenGL/Objects/Sampler.hh> +#if (ACGL_OPENGL_VERSION >= 33) + using namespace ACGL::OpenGL; Sampler::Sampler() @@ -46,3 +48,4 @@ void Sampler::setMaxAnisotropy( GLfloat _sampleCount ) } } +#endif // OpenGL >= 3.3 diff --git a/src/ACGL/OpenGL/Objects/VertexArrayObject.cc b/src/ACGL/OpenGL/Objects/VertexArrayObject.cc index 0bf45513a783c35c7b293c8f0df691f5affe9aad..2d953fae6b89d1811f28b1a282c72a41932d0513 100755 --- a/src/ACGL/OpenGL/Objects/VertexArrayObject.cc +++ b/src/ACGL/OpenGL/Objects/VertexArrayObject.cc @@ -7,6 +7,7 @@ #if (ACGL_OPENGL_VERSION >= 30) using namespace ACGL; +using namespace ACGL::Utils; using namespace ACGL::OpenGL; void VertexArrayObject::attachElementArrayBuffer( const SharedElementArrayBuffer& _elementArrayBuffer ) @@ -27,36 +28,67 @@ void VertexArrayObject::attachElementArrayBuffer( const SharedElementArrayBuffer restoreOldVAO(); } -void VertexArrayObject::attachAttribute( const Attribute &_attribute ) +void VertexArrayObject::attachAttribute( const Attribute &_attribute, GLint _location ) { - GLint maxAttributes; - glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttributes); // TODO: clever caching - - if(mAttributes.size() >= (uint32_t) maxAttributes) - { + if ( (GLuint)_location >= mAttributes.size()) { ACGL::Utils::error() << "can't attach attribute " << _attribute.arrayBuffer->getAttributes()[_attribute.attributeID].name - << " - maximum number of attributes reached: " << maxAttributes << std::endl; + << " - maximum number of attributes: " << mAttributes.size() << std::endl; return; + } else if (_location < 0) { + // find a free location: + _location = getFreeAttributeLocation(); + if (_location < 0) { + // no free location found + ACGL::Utils::error() << "can't attach attribute " << _attribute.arrayBuffer->getAttributes()[_attribute.attributeID].name + << " - maximum number of attributes reached ( " << mAttributes.size() << " )" << std::endl; + return; + } } - mAttributes.push_back( _attribute ); - + mAttributes[_location] = _attribute; storeOldVAOandBind(); - setAttributePointer( _attribute ); + setAttributePointer( _location ); restoreOldVAO(); } +GLint VertexArrayObject::getFreeAttributeLocation() +{ + GLint maxAttributes; + glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxAttributes); + + for (ArrayBuffer::AttributeVec::size_type i = 0; i < mAttributes.size(); ++i) + { + if ( !(mAttributes[i].arrayBuffer) ) { + // no shared pointer set, no attribute set! + return (GLint) i; + } + } + + return -1; +} + void VertexArrayObject::attachAllAttributes( const SharedArrayBuffer& _arrayBuffer ) { ArrayBuffer::AttributeVec attributes = _arrayBuffer->getAttributes(); for(ArrayBuffer::AttributeVec::size_type i = 0; i < attributes.size(); ++i) { - attachAttribute(_arrayBuffer, (GLint) i); + attachAttribute(_arrayBuffer, (GLint) i, getFreeAttributeLocation() ); } } -void VertexArrayObject::detachAttribute( GLint _location ) +void VertexArrayObject::detachAttribute( GLuint _location ) { + if (_location >= mAttributes.size()) { + ACGL::Utils::error() << "can't detach attribute with location " << _location << " - no such Attribute" << std::endl; + return; + } + + storeOldVAOandBind(); + mAttributes[_location].arrayBuffer = SharedArrayBuffer(); + glDisableVertexAttribArray( _location ); + restoreOldVAO(); + + /* for (AttributeVec::size_type i = 0; i < mAttributes.size(); ++i) { if (mAttributes[i].location == _location) @@ -69,6 +101,7 @@ void VertexArrayObject::detachAttribute( GLint _location ) } // if we got here, no Attribute of the given name exists ACGL::Utils::warning() << "can't detach attribute with location " << _location << " - no such Attribute" << std::endl; + */ } /** @@ -80,9 +113,10 @@ void VertexArrayObject::detachAttribute( const std::string &_name ) { if (mAttributes[i].arrayBuffer->getAttributes()[ mAttributes[i].attributeID ].name == _name) { + detachAttribute( i ); // the other pointer data is still set, but that isn't relevant if the attribute itself is deactivated - glDisableVertexArrayAttribEXT( mObjectName, mAttributes[i].location ); - mAttributes.erase( mAttributes.begin()+i ); + //glDisableVertexArrayAttribEXT( mObjectName, mAttributes[i].location ); + //mAttributes.erase( mAttributes.begin()+i ); return; } } @@ -90,108 +124,83 @@ void VertexArrayObject::detachAttribute( const std::string &_name ) ACGL::Utils::warning() << "can't detach attribute " << _name << " - no such Attribute" << std::endl; } -bool VertexArrayObject::isValid(void) const -{ - GLsizei elements = 0; - if (mAttributes.size() > 0) - { - elements = mAttributes[0].arrayBuffer->getElements(); - } else { - Utils::error() << "VertexArrayObject has no attributes attached" << std::endl; - return false; - } - if (mpElementArrayBuffer) +void VertexArrayObject::setAttributeLocations( ConstSharedLocationMappings _locationMappings ) +{ + AttributeVec oldAttributes = mAttributes; + for (AttributeVec::size_type i = 0; i < mAttributes.size(); ++i) { - elements = mpElementArrayBuffer->getElements(); + mAttributes[i].arrayBuffer = SharedArrayBuffer(); // set to NULL } + AttributeVec unmatchedAttributes; - for (AttributeVec::size_type i = 0; i < mAttributes.size(); ++i) + // if there is an old attribute, look up the name in the _locationMap, use the new location if the + // name is present (stored in the map), remove the attribute from the old map. + // after that, run over the unmatchedAttributes to store the remaining attributes on free slots in the map + for (AttributeVec::size_type i = 0; i < oldAttributes.size(); ++i) { - if (mAttributes[0].arrayBuffer->getElements() != elements) - { - Utils::error() << "VertexArrayObject validation failed: Attribute "<< i << " has different number of elements."<< std::endl; - return false; + if (oldAttributes[i].arrayBuffer) { + GLint location = _locationMappings->getLocation( oldAttributes[i].arrayBuffer->getAttribute( (int) oldAttributes[i].attributeID ).name ); + if ((location >= 0) && ((GLuint)location < oldAttributes.size())) { + mAttributes[location] = oldAttributes[i]; + //debug() << "moved loc " << oldAttributes[i].arrayBuffer->getAttribute( (int) oldAttributes[i].attributeID ).name + // << " from " << i << " to " << location << std::endl; + } else { + unmatchedAttributes.push_back( oldAttributes[i] ); + //debug() << "unmatched " << oldAttributes[i].arrayBuffer->getAttribute( (int) oldAttributes[i].attributeID ).name + // << " at " << i << std::endl; + } + + oldAttributes[i].arrayBuffer = SharedArrayBuffer(); // set to NULL } } + for (AttributeVec::size_type i = 0; i < unmatchedAttributes.size(); ++i) + { + GLint location = getFreeAttributeLocation(); + mAttributes[location] = unmatchedAttributes[i]; // the total attribute number hasn't changed so location must be valid + //debug() << "moved uloc " << unmatchedAttributes[i].arrayBuffer->getAttribute( (int) unmatchedAttributes[i].attributeID ).name + // << " to " << location << std::endl; + } - return true; -} + storeOldVAOandBind(); + // disable all attributes & set the new ones + for (GLuint i = 0; i < mAttributes.size(); ++i) { + glDisableVertexAttribArray( i ); + if (mAttributes[i].arrayBuffer) setAttributePointer( i ); + } + restoreOldVAO(); +} -void VertexArrayObject::setAttributeLocations( ConstSharedLocationMappings _locationMappings ) +SharedLocationMappings VertexArrayObject::getAttributeLocations() { - bool fullUpdateNeeded = false; - GLint maxAttributes; - glGetIntegerv( GL_MAX_VERTEX_ATTRIBS, &maxAttributes ); + SharedLocationMappings locationMap = SharedLocationMappings( new LocationMappings() ); for (AttributeVec::size_type i = 0; i < mAttributes.size(); ++i) { - std::string attributeName = mAttributes[i].arrayBuffer->getAttributes()[ mAttributes[i].attributeID ].name; - int_t location = _locationMappings->getLocation(attributeName); - - if(location == -1) - { - // TODO: fail silently? - ACGL::Utils::error() << "can't update VAO mapping: attribute " << attributeName << " not specified" << std::endl; - continue; // try to match as much as possible - } - if(location >= maxAttributes) - { - ACGL::Utils::error() << "can't update VAO mapping: location of attribute " << attributeName << " is too high (" - << location << ") GL_MAX_VERTEX_ATTRIBS is " << maxAttributes << std::endl; - continue; // try to match as much as possible - } - - if(mAttributes[i].location != location) - { - mAttributes[i].location = location; - fullUpdateNeeded = true; + if ( mAttributes[i].arrayBuffer ) { + //debug() << "aloc: " << mAttributes[i].arrayBuffer->getAttribute( (int) mAttributes[i].attributeID ).name << " " << i << std::endl; + locationMap->setLocation( mAttributes[i].arrayBuffer->getAttribute( (int) mAttributes[i].attributeID ).name, i ); } } - // why the full update? setting the new location right when a change is detected will get problamatic - // if two attributes exchange there position... - if (fullUpdateNeeded) - { - storeOldVAOandBind(); - - // disable all attributes - for (GLint i = 0; i < maxAttributes; ++i) - glDisableVertexAttribArray( i ); - - // set all attributes: - for (uint32_t i = 0; i < mAttributes.size(); ++i) - { - setAttributePointer(mAttributes[i]); - } - - restoreOldVAO(); - } + return locationMap; } - -void VertexArrayObject::setAttributePointer(const Attribute& _attribute) +void VertexArrayObject::setAttributePointer( GLuint _index ) { - if(_attribute.location == -1) - { - // An attribute location of -1 indicates that this attribute should remain unbound for now - return; - } - - SharedArrayBuffer arrayBuffer = _attribute.arrayBuffer; - arrayBuffer->bind(); + mAttributes[_index].arrayBuffer->bind(); - ArrayBuffer::Attribute arrayBufferAttribute = arrayBuffer->getAttributes()[_attribute.attributeID]; - glVertexAttribPointer(_attribute.location, + ArrayBuffer::Attribute arrayBufferAttribute = mAttributes[_index].arrayBuffer->getAttribute(mAttributes[_index].attributeID); + glVertexAttribPointer(_index, arrayBufferAttribute.size, arrayBufferAttribute.type, arrayBufferAttribute.normalized, - arrayBuffer->getStride(), + mAttributes[_index].arrayBuffer->getStride(), reinterpret_cast<GLvoid*>(arrayBufferAttribute.offset) ); - glEnableVertexAttribArray(_attribute.location); + glEnableVertexAttribArray(_index); }