From 5a16cbe86a9fa2bcf6e418b8102cb2b3e1411e2b Mon Sep 17 00:00:00 2001 From: Nicolas Mellado Date: Mon, 19 Jul 2021 13:00:11 +0200 Subject: [PATCH] [engine] Prepare API of GeometryDisplayable --- src/Engine/Data/Mesh.cpp | 178 ++++++++++++++++++++++++++++++++++++++- src/Engine/Data/Mesh.hpp | 110 +++++++++++++++--------- src/Engine/Data/Mesh.inl | 72 ---------------- 3 files changed, 246 insertions(+), 114 deletions(-) diff --git a/src/Engine/Data/Mesh.cpp b/src/Engine/Data/Mesh.cpp index 03c21ad563f..f891aa00277 100644 --- a/src/Engine/Data/Mesh.cpp +++ b/src/Engine/Data/Mesh.cpp @@ -19,7 +19,7 @@ using namespace Ra::Core::Utils; // we have no data to send to the gpu. AttribArrayDisplayable::AttribArrayDisplayable( const std::string& name, MeshRenderMode renderMode ) : - Displayable( name ), m_renderMode {renderMode} { + Displayable( name ), m_renderMode { renderMode } { CORE_ASSERT( m_renderMode == RM_POINTS || m_renderMode == RM_LINES || m_renderMode == RM_LINE_LOOP || m_renderMode == RM_LINE_STRIP || m_renderMode == RM_TRIANGLES || m_renderMode == RM_TRIANGLE_STRIP || @@ -73,7 +73,7 @@ void Mesh::loadGeometry( const Core::Vector3Array& vertices, const std::vectorgetName(); + m_handleToBuffer[name] = idx; + m_dataDirty[idx] = true; + + // create a identity translation if name is not already translated. + addToTranslationTable( name ); + + b->attach( AttribObserver( this, idx ) ); + ++idx; + } ); + + // add an observer on attrib manipulation. + m_geom.vertexAttribs().attachMember( this, &GeometryDisplayable::addAttribObserver ); + m_isDirty = true; +} + +void GeometryDisplayable::addToTranslationTable( const std::string& name ) { + auto it = m_translationTableMeshToShader.find( name ); + if ( it == m_translationTableMeshToShader.end() ) + { + m_translationTableMeshToShader[name] = name; + m_translationTableShaderToMesh[name] = name; + } +} + +void GeometryDisplayable::addAttribObserver( const std::string& name ) { + // this observer is called each time an attrib is added or removed from m_mesh + auto attrib = m_geom.getAttribBase( name ); + // if attrib not nullptr, then it's an attrib add, so attach an observer to it + + if ( attrib ) + { + auto itr = m_handleToBuffer.find( name ); + if ( itr == m_handleToBuffer.end() ) + { + m_handleToBuffer[name] = m_dataDirty.size(); + + addToTranslationTable( name ); + + m_dataDirty.push_back( true ); + m_vbos.emplace_back( nullptr ); + } + auto idx = m_handleToBuffer[name]; + attrib->attach( AttribObserver( this, idx ) ); + } + // else it's an attrib remove, do nothing, cleanup will be done in updateGL() + else + {} +} + +void GeometryDisplayable::setAttribNameCorrespondence( const std::string& meshAttribName, + const std::string& shaderAttribName ) { + + // clean previously set translation + + auto it1 = std::find_if( m_translationTableShaderToMesh.begin(), + m_translationTableShaderToMesh.end(), + [&meshAttribName]( const TranslationTable::value_type& p ) { + return p.second == meshAttribName; + } ); + + if ( it1 != m_translationTableShaderToMesh.end() ) m_translationTableShaderToMesh.erase( it1 ); + + auto it2 = std::find_if( m_translationTableMeshToShader.begin(), + m_translationTableMeshToShader.end(), + [&shaderAttribName]( const TranslationTable::value_type& p ) { + return p.second == shaderAttribName; + } ); + + if ( it2 != m_translationTableMeshToShader.end() ) m_translationTableMeshToShader.erase( it2 ); + + m_translationTableShaderToMesh[shaderAttribName] = meshAttribName; + m_translationTableMeshToShader[meshAttribName] = shaderAttribName; +} + +bool GeometryDisplayable::addRenderLayer( LayerKeyType key ) { + if ( !m_geom.containsLayer( key ) ) return false; + auto it = m_geomLayers.find( key ); + if ( it == m_geomLayers.end() ) return false; + + VaoIndices* vao = new VaoIndices; + auto& geomLayer = m_geom.getLayerWithLock( key ); + int observerId = geomLayer.attach( VaoIndices::IndicesObserver( vao ) ); + m_geom.unlockLayer( key ); + + m_geomLayers[key] = { observerId, vao }; + + return false; +} +bool GeometryDisplayable::removeRenderLayer( LayerKeyType key ) { + auto it = m_geomLayers.find( key ); + if ( it == m_geomLayers.end() ) return false; + + // the layer might have already been deleted + if ( m_geom.containsLayer( key ) ) + { + auto& geomLayer = m_geom.getLayerWithLock( key ); + geomLayer.detach( it->second.first ); + m_geom.unlockLayer( key ); + } + delete ( it->second.second ); + m_geomLayers.erase( it ); + + return true; +} + +void GeometryDisplayable::updateGL_specific_impl() { + CORE_ASSERT( false, "not implemented yet" ); + // if ( !m_indices ) + // { + // m_indices = globjects::Buffer::create(); + // m_indicesDirty = true; + // } + // if ( m_indicesDirty ) + // { + // /// this one do not work since m_indices is not a std::vector + // // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW ); + // m_numElements = + // base::m_mesh.getIndices().size() * + // base::CoreGeometry::IndexType::RowsAtCompileTime; + // + // m_indices->setData( + // static_cast( base::m_mesh.getIndices().size() * + // sizeof( typename base::CoreGeometry::IndexType ) ), + // base::m_mesh.getIndices().data(), + // GL_STATIC_DRAW ); + // m_indicesDirty = false; + // } + // if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); } + // base::m_vao->bind(); + // base::m_vao->bindElementBuffer( m_indices.get() ); + // base::m_vao->unbind(); + /// \todo implement ! +} + +void GeometryDisplayable::render( const ShaderProgram* ) { + CORE_ASSERT( false, "not implemented yet" ); + // if ( base::m_vao ) + // { + // GL_CHECK_ERROR; + // base::m_vao->bind(); + // base::autoVertexAttribPointer( prog ); + // GL_CHECK_ERROR; + // base::m_vao->drawElements( static_cast( base::m_renderMode ), + // GLsizei( m_numElements ), + // GL_UNSIGNED_INT, + // nullptr ); + // GL_CHECK_ERROR; + // base::m_vao->unbind(); + // GL_CHECK_ERROR; + // } + /// \todo implement ! +} void PointCloud::render( const ShaderProgram* prog ) { if ( m_vao ) diff --git a/src/Engine/Data/Mesh.hpp b/src/Engine/Data/Mesh.hpp index 9375bf784d2..26c477f25fd 100644 --- a/src/Engine/Data/Mesh.hpp +++ b/src/Engine/Data/Mesh.hpp @@ -162,7 +162,7 @@ class RA_ENGINE_API AttribArrayDisplayable : public Displayable protected: std::unique_ptr m_vao; - MeshRenderMode m_renderMode {MeshRenderMode::RM_TRIANGLES}; + MeshRenderMode m_renderMode { MeshRenderMode::RM_TRIANGLES }; // m_vbos and m_dataDirty have the same size and are indexed thru m_handleToBuffer[attribName] std::vector> m_vbos; @@ -174,7 +174,7 @@ class RA_ENGINE_API AttribArrayDisplayable : public Displayable /// General dirty bit of the mesh. Must be equivalent of the "or" of the other dirty flags. /// an empty mesh is not dirty - bool m_isDirty {false}; + bool m_isDirty { false }; }; /// Concept class to ensure consistent naming of VaoIndices accross derived classes. @@ -189,20 +189,20 @@ class RA_ENGINE_API VaoIndices { public: /// not tested - explicit IndicesObserver( VaoIndices* displayable ) : m_displayable {displayable} {} + explicit IndicesObserver( VaoIndices* displayable ) : m_displayable { displayable } {} /// not tested void operator()() { m_displayable->m_indicesDirty = true; } private: - VaoIndices* m_displayable; + VaoIndices* m_displayable { nullptr }; }; protected: - std::unique_ptr m_indices {nullptr}; - bool m_indicesDirty {true}; + std::unique_ptr m_indices { nullptr }; + bool m_indicesDirty { true }; /// number of elements to draw (i.e number of indices to use) /// automatically set by updateGL(), not meaningfull if m_indicesDirty. - size_t m_numElements {0}; + size_t m_numElements { 0 }; }; /// This class handles an attrib array displayable on gpu only, without core @@ -358,44 +358,76 @@ class IndexedGeometry : public CoreGeometryDisplayable, public VaoIndices }; /// An engine mesh owning a MultiIndexedCoreGeometry, with multiple indices layer. -/// \todo Work in progress. -template -class MultiIndexedGeometry : public CoreGeometryDisplayable +class GeometryDisplayable : public AttribArrayDisplayable { public: - using base = CoreGeometryDisplayable; - using CoreGeometryDisplayable::CoreGeometryDisplayable; - explicit MultiIndexedGeometry( + using base = AttribArrayDisplayable; + + using LayerSemanticCollection = + typename Core::Geometry::MultiIndexedGeometry::LayerSemanticCollection; + using LayerSemantic = typename Core::Geometry::MultiIndexedGeometry::LayerSemantic; + using LayerKeyType = typename Core::Geometry::MultiIndexedGeometry::LayerKeyType; + using LayerKeyHash = Core::Geometry::MultiIndexedGeometry::LayerKeyHash; + + explicit GeometryDisplayable( const std::string& name, - typename base::CoreGeometry&& geom, + typename Core::Geometry::MultiIndexedGeometry&& geom, typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_TRIANGLES ); + virtual inline ~GeometryDisplayable(); void render( const ShaderProgram* prog ) override; - void loadGeometry( T&& mesh ) override; + inline Core::Geometry::MultiIndexedGeometry& getGeometry() { return m_geom; } + inline const Core::Geometry::MultiIndexedGeometry& getGeometry() const { return m_geom; } + + /// Bind meshAttribName to shaderAttribName. + /// meshAttribName is a vertex attrib added to the underlying CoreGeometry + /// shaderAttribName is the name of the input paramter of the shader. + /// By default the same name is used, but this mecanism allows to override + /// this behavior. + /// Only one shaderAttribName can be bound to a meshAttribName and the other + /// way round. + /// \param meshAttribName: name of the attribute on the CoreGeometry side + /// \param shaderAttribName: name of the input vertex attribute on the + /// shader side. + void setAttribNameCorrespondence( const std::string& meshAttribName, + const std::string& shaderAttribName ); + + void loadGeometry( Core::Geometry::MultiIndexedGeometry&& mesh ); + inline void loadGeometry( Core::Geometry::MultiIndexedGeometry&& mesh, LayerKeyType key ) { + loadGeometry( std::move( mesh ) ); + addRenderLayer( key ); + } + template + inline void loadGeometry( Core::Geometry::MultiIndexedGeometry&& mesh, + const RangeOfLayerKeys& r ) { + loadGeometry( std::move( mesh ) ); + for ( const auto& k : r ) + addRenderLayer( k ); + } + bool addRenderLayer( LayerKeyType key ); + bool removeRenderLayer( LayerKeyType key ); protected: - void updateGL_specific_impl() override; + void updateGL_specific_impl(); + void setupCoreMeshObservers(); - using LayerSemanticCollection = Core::Utils::ObjectWithSemantic::SemanticNameCollection; - using LayerSemantic = Core::Utils::ObjectWithSemantic::SemanticName; - using LayerKeyType = std::pair; - - using EntryType = std::pair; - struct RA_CORE_API KeyHash { - std::size_t operator()( const LayerKeyType& k ) const { - // Mix semantic collection into a single identifier string - std::ostringstream stream; - std::copy( - k.first.begin(), k.first.end(), std::ostream_iterator( stream, "" ) ); - std::string result = stream.str(); - std::sort( result.begin(), result.end() ); - - // Combine with layer name hash - return std::hash {}( result ) ^ - ( std::hash {}( k.second ) << 1 ); - } - }; - std::unordered_map m_indices; + /// m_mesh Observer method, called whenever an attrib is added or removed from + /// m_mesh. + /// it adds an observer to the new attrib. + void addAttribObserver( const std::string& name ); + + void addToTranslationTable( const std::string& name ); + + // + using LayerEntryType = std::pair; // std::pair; + + using TranslationTable = std::map; + TranslationTable m_translationTableMeshToShader; + TranslationTable m_translationTableShaderToMesh; + + private: + Core::Geometry::MultiIndexedGeometry m_geom; + std::unordered_map m_geomLayers; }; /// LineMesh, own a Core::Geometry::LineMesh @@ -507,9 +539,7 @@ CoreMeshType createCoreMeshFromGeometryData( const Ra::Core::Asset::GeometryData } if ( data->hasColors() ) - { - mesh.addAttrib( Data::Mesh::getAttribName( Data::Mesh::VERTEX_COLOR ), data->getColors() ); - } + { mesh.addAttrib( Data::Mesh::getAttribName( Data::Mesh::VERTEX_COLOR ), data->getColors() ); } // add custom attribs // only attributs not handled before are handled by data->getAttribManager() @@ -553,7 +583,7 @@ createMeshFromGeometryData( const std::string& name, const Ra::Core::Asset::Geom CoreMeshType mesh = createCoreMeshFromGeometryData( data ); - MeshType* ret = new MeshType {name}; + MeshType* ret = new MeshType { name }; ret->loadGeometry( std::move( mesh ) ); return ret; diff --git a/src/Engine/Data/Mesh.inl b/src/Engine/Data/Mesh.inl index 41b6cfe4eb7..a07e963415f 100644 --- a/src/Engine/Data/Mesh.inl +++ b/src/Engine/Data/Mesh.inl @@ -503,78 +503,6 @@ void IndexedGeometry::render( const ShaderProgram* prog ) { } } -//////////////// MultiIndexedGeometry /////////////////////////////// - -template -MultiIndexedGeometry::MultiIndexedGeometry( const std::string& name, - typename base::CoreGeometry&& geom, - typename base::MeshRenderMode renderMode ) : - base( name, renderMode ) { - loadGeometry( std::move( geom ) ); -} - -template -void MultiIndexedGeometry::loadGeometry( T&& mesh ) { - m_indices.clear(); - - base::loadGeometry_common( std::move( mesh ) ); - CORE_ASSERT( false, "not implemented yet" ); - - /// \todo HERE - // indices - // base::m_mesh.attach( IndicesObserver( this ) ); -} - -template -void MultiIndexedGeometry::updateGL_specific_impl() { - CORE_ASSERT( false, "not implemented yet" ); - // if ( !m_indices ) - // { - // m_indices = globjects::Buffer::create(); - // m_indicesDirty = true; - // } - // if ( m_indicesDirty ) - // { - // /// this one do not work since m_indices is not a std::vector - // // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW ); - // m_numElements = - // base::m_mesh.getIndices().size() * - // base::CoreGeometry::IndexType::RowsAtCompileTime; - // - // m_indices->setData( - // static_cast( base::m_mesh.getIndices().size() * - // sizeof( typename base::CoreGeometry::IndexType ) ), - // base::m_mesh.getIndices().data(), - // GL_STATIC_DRAW ); - // m_indicesDirty = false; - // } - // if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); } - // base::m_vao->bind(); - // base::m_vao->bindElementBuffer( m_indices.get() ); - // base::m_vao->unbind(); - /// \todo implement ! -} - -template -void MultiIndexedGeometry::render( const ShaderProgram* ) { - CORE_ASSERT( false, "not implemented yet" ); - // if ( base::m_vao ) - // { - // GL_CHECK_ERROR; - // base::m_vao->bind(); - // base::autoVertexAttribPointer( prog ); - // GL_CHECK_ERROR; - // base::m_vao->drawElements( static_cast( base::m_renderMode ), - // GLsizei( m_numElements ), - // GL_UNSIGNED_INT, - // nullptr ); - // GL_CHECK_ERROR; - // base::m_vao->unbind(); - // GL_CHECK_ERROR; - // } - /// \todo implement ! -} - ///////// PointCloud ////////// PointCloud::PointCloud( const std::string& name,