3 #include <Core/Asset/GeometryData.hpp>
4 #include <Core/Containers/VectorArray.hpp>
5 #include <Core/Geometry/MeshPrimitives.hpp>
6 #include <Core/Geometry/StandardAttribNames.hpp>
7 #include <Core/Geometry/TriangleMesh.hpp>
8 #include <Core/Utils/BijectiveAssociation.hpp>
9 #include <Core/Utils/Color.hpp>
10 #include <Core/Utils/Log.hpp>
11 #include <Core/Utils/ObjectWithSemantic.hpp>
12 #include <Engine/Data/DisplayableObject.hpp>
13 #include <Engine/Data/ShaderProgram.hpp>
14 #include <Engine/RaEngine.hpp>
16 #include <globjects/Buffer.h>
17 #include <globjects/Program.h>
18 #include <globjects/VertexArray.h>
19 #include <globjects/VertexAttributeBinding.h>
31 using namespace Ra::Core::Utils;
35 class RA_ENGINE_API
Vao
38 std::unique_ptr<globjects::VertexArray> m_vao;
39 std::vector<std::unique_ptr<globjects::Buffer>> m_vbos;
40 std::vector<bool> m_dataDirty;
41 std::map<std::string, int> m_handleToBuffer;
60 RM_LINE_LOOP = 0x0002,
61 RM_LINE_STRIP = 0x0003,
62 RM_TRIANGLES = 0x0004,
63 RM_TRIANGLE_STRIP = 0x0005,
64 RM_TRIANGLE_FAN = 0x0006,
66 RM_QUAD_STRIP = 0x0008,
68 RM_LINES_ADJACENCY = 0x000A,
69 RM_LINE_STRIP_ADJACENCY = 0x000B,
70 RM_TRIANGLES_ADJACENCY = 0x000C,
71 RM_TRIANGLE_STRIP_ADJACENCY = 0x000D,
77 MeshRenderMode renderMode = RM_TRIANGLES );
86 inline void setRenderMode( MeshRenderMode mode );
88 inline MeshRenderMode getRenderMode()
const;
96 void setDirty(
const Core::Geometry::MeshAttrib& type );
99 void setDirty(
const std::string& name );
103 void setDirty(
unsigned int index );
121 Ra::Core::Utils::optional<gl::GLuint> getVboHandle(
const std::string& name );
126 Ra::Core::Utils::optional<gl::GLuint> getVaoHandle();
130 void updatePickingRenderMode();
136 m_displayable( displayable ), m_idx( idx ) {}
138 if ( m_idx <
int( m_displayable->m_dataDirty.size() ) ) {
139 m_displayable->m_dataDirty[m_idx] =
true;
140 m_displayable->m_isDirty =
true;
144 LOG( logDEBUG ) <<
"Invalid dirty bit notified on " << m_displayable->getName();
149 AttribArrayDisplayable* m_displayable;
154 std::unique_ptr<globjects::VertexArray> m_vao;
156 MeshRenderMode m_renderMode { MeshRenderMode::RM_TRIANGLES };
159 std::vector<std::unique_ptr<globjects::Buffer>> m_vbos;
160 std::vector<bool> m_dataDirty;
164 std::map<std::string, unsigned int> m_handleToBuffer;
169 bool m_isDirty {
false };
177 inline void setIndicesDirty();
193 std::unique_ptr<globjects::Buffer> m_indices {
nullptr };
194 bool m_indicesDirty {
true };
197 size_t m_numElements { 0 };
203 template <
typename I>
207 using IndexContainerType = Ra::Core::AlignedStdVector<IndexType>;
209 template <
typename T>
210 inline void addAttrib(
const std::string& name,
212 template <
typename T>
213 inline void addAttrib(
const std::string& name,
214 const typename Ra::Core ::Utils::Attrib<T>::Container&& data );
215 inline void updateGL()
override;
221 inline void autoVertexAttribPointer(
const ShaderProgram* prog );
222 IndexContainerType m_cpu_indices;
227 template <
typename T>
232 using CoreGeometry = T;
249 inline const CoreGeometry& getCoreGeometry()
const;
250 inline CoreGeometry& getCoreGeometry();
254 template <
typename A>
257 inline size_t getNumVertices()
const override;
284 const std::string& shaderAttribName );
287 virtual void updateGL_specific_impl() {}
289 void loadGeometry_common( CoreGeometry&& mesh );
290 void setupCoreMeshObservers();
300 void addToTranslationTable(
const std::string& name );
315 using base::CoreGeometryDisplayable;
317 const std::string& name,
318 typename base::CoreGeometry&& geom,
326 void loadGeometry( Core::Geometry::PointCloud&& mesh )
override;
329 void updateGL_specific_impl()
override;
333 template <
typename T>
340 const std::string& name,
341 typename base::CoreGeometry&& geom,
354 template <
typename T>
361 const std::string& name,
362 typename base::CoreGeometry&& geom,
366 void loadGeometry( T&& mesh )
override;
369 void updateGL_specific_impl()
override;
372 using LayerSemantic = Core::Utils::ObjectWithSemantic::SemanticName;
373 using LayerKeyType = std::pair<LayerSemanticCollection, std::string>;
375 using EntryType = std::pair<bool, VaoIndices*>;
376 struct RA_CORE_API KeyHash {
377 std::size_t operator()(
const LayerKeyType& k )
const {
379 std::ostringstream stream;
381 k.first.begin(), k.first.end(), std::ostream_iterator<std::string>( stream,
"" ) );
382 std::string result = stream.str();
383 std::sort( result.begin(), result.end() );
386 return std::hash<std::string> {}( result ) ^
387 ( std::hash<std::string> {}( k.second ) << 1 );
390 std::unordered_map<LayerKeyType, EntryType, KeyHash> m_indices;
399 using base::IndexedGeometry;
401 const std::string& name,
402 typename base::CoreGeometry&& geom,
405 const std::string& name,
418 using base::IndexedGeometry;
419 size_t getNumFaces()
const override;
428 using base::loadGeometry;
429 [[deprecated]]
void loadGeometry(
const Core::Vector3Array& vertices,
430 const std::vector<uint>& indices );
440 template <
typename T>
444 using IndexType = Core::Vector3ui;
447 using base::IndexedGeometry;
448 inline size_t getNumFaces()
const override;
451 inline void updateGL_specific_impl()
override;
454 inline void triangulate();
455 Core::AlignedStdVector<IndexType> m_triangleIndices;
463 template <
typename CoreMeshType>
466 typename CoreMeshType::IndexContainerType indices;
470 const auto& [layerKeyType, layerBase] =
472 const auto& layer =
static_cast<
475 const auto& faces = layer.collection();
476 indices.reserve( faces.size() );
477 std::copy( faces.begin(), faces.end(), std::back_inserter( indices ) );
485 indices.reserve( edges.size() );
487 edges.begin(), edges.end(), std::back_inserter( indices ), []( Ra::Core::Vector2ui v ) {
488 return ( Ra::Core::Vector3ui { v( 0 ), v( 1 ), v( 1 ) } );
493 mesh.setIndices( std::move( indices ) );
502 namespace RenderMeshType {
503 template <
class CoreMeshT>
507 struct getType<
Ra::Core::Geometry::LineMesh> {
512 struct getType<
Ra::Core::Geometry::TriangleMesh> {
517 struct getType<
Ra::Core::Geometry::QuadMesh> {
522 struct getType<
Ra::Core::Geometry::PolyMesh> {
528 template <
typename CoreMeshType>
529 typename RenderMeshType::getType<CoreMeshType>::Type*
531 using MeshType =
typename RenderMeshType::getType<CoreMeshType>::Type;
533 auto mesh = createCoreMeshFromGeometryData<CoreMeshType>( data );
535 MeshType* ret =
new MeshType { name };
536 ret->loadGeometry( std::move( mesh ) );
555 m_indicesDirty =
true;
560 template <
typename I>
561 template <
typename T>
563 const std::string& name,
565 auto handle = m_attribManager.addAttrib<T>( name );
566 m_attribManager.getAttrib( handle ).setData( data );
567 m_handleToBuffer[name] = m_dataDirty.size();
568 m_dataDirty.push_back(
true );
569 m_vbos.emplace_back(
nullptr );
573 template <
typename I>
574 template <
typename T>
575 void IndexedAttribArrayDisplayable<I>::addAttrib(
576 const std::string& name,
577 const typename Ra::Core ::Utils::Attrib<T>::Container&& data ) {
578 auto handle = m_attribManager.addAttrib<T>( name );
579 m_attribManager.getAttrib( handle ).setData( std::move( data ) );
580 m_handleToBuffer[name] = m_dataDirty.size();
581 m_dataDirty.push_back(
true );
582 m_vbos.emplace_back(
nullptr );
586 template <
typename I>
587 void IndexedAttribArrayDisplayable<I>::updateGL() {
590 ON_ASSERT(
bool dirtyTest =
false;
for (
const auto& d
591 : m_dataDirty ) { dirtyTest = dirtyTest || d; } );
592 CORE_ASSERT( dirtyTest == m_isDirty,
"Dirty flags inconsistency" );
595 m_indices = globjects::Buffer::create();
596 m_indicesDirty =
true;
598 if ( m_indicesDirty ) {
600 static_cast<gl::GLsizeiptr
>( m_cpu_indices.size() *
sizeof( IndexType ) ),
601 m_cpu_indices.data(),
603 m_indicesDirty =
false;
606 m_numElements = m_cpu_indices.size();
608 if ( !m_vao ) { m_vao = globjects::VertexArray::create(); }
610 m_vao->bindElementBuffer( m_indices.get() );
614 auto idx = m_handleToBuffer[b->getName()];
616 if ( m_dataDirty[idx] ) {
617 if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
618 m_vbos[idx]->setData( b->getBufferSize(), b->dataPtr(), GL_DYNAMIC_DRAW );
619 m_dataDirty[idx] =
false;
622 m_attribManager.for_each_attrib( func );
628 template <
typename I>
631 auto glprog = prog->getProgramObject();
632 gl::GLint attribCount = glprog->get( GL_ACTIVE_ATTRIBUTES );
634 for ( GLint idx = 0; idx < attribCount; ++idx ) {
635 const gl::GLsizei bufSize = 256;
636 gl::GLchar name[bufSize];
640 glprog->getActiveAttrib( idx, bufSize, &length, &size, &type, name );
641 auto loc = glprog->getAttributeLocation( name );
643 auto attribName = name;
644 auto attrib = m_attribManager.getAttribBase( attribName );
646 if ( attrib && attrib->getSize() > 0 ) {
647 m_vao->enable( loc );
648 auto binding = m_vao->binding( idx );
649 binding->setAttribute( loc );
650 CORE_ASSERT( m_vbos[m_handleToBuffer[attribName]].get(),
"vbo is nullptr" );
651 #ifdef CORE_USE_DOUBLE
652 binding->setBuffer( m_vbos[m_handleToBuffer[attribName]].get(),
654 attrib->getNumberOfComponents() *
sizeof(
float ) );
658 m_vbos[m_handleToBuffer[attribName]].get(), 0, attrib->getStride() );
660 binding->setFormat( attrib->getNumberOfComponents(), GL_SCALAR );
662 else { m_vao->disable( loc ); }
666 template <
typename I>
669 autoVertexAttribPointer( prog );
671 m_vao->drawElements(
static_cast<GLenum
>( m_renderMode ),
672 GLsizei( m_numElements ),
681 template <
typename CoreGeometry>
682 CoreGeometryDisplayable<CoreGeometry>::CoreGeometryDisplayable(
const std::string& name,
683 MeshRenderMode renderMode ) :
684 base( name, renderMode ) {
685 setupCoreMeshObservers();
688 template <
typename CoreGeometry>
694 template <
typename CoreGeometry>
699 template <
typename CoreGeometry>
701 CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry()
const {
705 template <
typename CoreGeometry>
707 CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry() {
711 template <
typename CoreGeometry>
712 const CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry()
const {
716 template <
typename CoreGeometry>
717 CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry() {
721 template <
typename CoreGeometry>
722 void CoreGeometryDisplayable<CoreGeometry>::addToTranslationTable(
const std::string& name ) {
723 m_translationTable.insert( name, name );
726 template <
typename CoreGeometry>
729 auto attrib = m_mesh.getAttribBase( name );
733 auto itr = m_handleToBuffer.find( name );
734 if ( itr == m_handleToBuffer.end() ) {
735 m_handleToBuffer[name] = m_dataDirty.size();
737 addToTranslationTable( name );
739 m_dataDirty.push_back(
true );
740 m_vbos.emplace_back(
nullptr );
742 auto idx = m_handleToBuffer[name];
743 attrib->attach( AttribObserver(
this, idx ) );
749 template <
typename CoreGeometry>
752 auto glprog = prog->getProgramObject();
753 gl::GLint attribCount = glprog->get( GL_ACTIVE_ATTRIBUTES );
755 for ( GLint idx = 0; idx < attribCount; ++idx ) {
756 const gl::GLsizei bufSize = 256;
757 gl::GLchar name[bufSize];
761 glprog->getActiveAttrib( idx, bufSize, &length, &size, &type, name );
762 auto loc = glprog->getAttributeLocation( name );
764 auto attribNameOpt = m_translationTable.keyIfExists( name );
765 if ( attribNameOpt ) {
766 auto attribName = *attribNameOpt;
767 auto attrib = m_mesh.getAttribBase( attribName );
768 if ( attrib && attrib->getSize() > 0 ) {
769 m_vao->enable( loc );
770 auto binding = m_vao->binding( idx );
771 binding->setAttribute( loc );
772 CORE_ASSERT( m_vbos[m_handleToBuffer[attribName]].get(),
"vbo is nullptr" );
773 #ifdef CORE_USE_DOUBLE
774 binding->setBuffer( m_vbos[m_handleToBuffer[attribName]].get(),
776 attrib->getNumberOfComponents() *
sizeof(
float ) );
780 m_vbos[m_handleToBuffer[attribName]].get(), 0, attrib->getStride() );
782 binding->setFormat( attrib->getNumberOfComponents(), GL_SCALAR );
784 else { m_vao->disable( loc ); }
786 else { m_vao->disable( loc ); }
790 template <
typename T>
792 m_mesh = std::move( mesh );
793 setupCoreMeshObservers();
796 template <
typename T>
798 void CoreGeometryDisplayable<T>::setupCoreMeshObservers() {
800 m_dataDirty.resize( m_mesh.vertexAttribs().getNumAttribs() );
801 m_vbos.resize( m_mesh.vertexAttribs().getNumAttribs() );
805 m_handleToBuffer[name] = idx;
806 m_dataDirty[idx] =
true;
809 addToTranslationTable( name );
811 b->
attach( AttribObserver(
this, idx ) );
816 m_mesh.vertexAttribs().attachMember(
822 template <
typename CoreGeometry>
823 template <
typename A>
827 return m_mesh.addAttrib( name, data );
830 template <
typename CoreGeometry>
832 return m_mesh.vertices().size();
835 template <
typename CoreGeometry>
837 CORE_ASSERT(
false,
"must be specialized" );
840 template <
typename CoreGeometry>
844 ON_ASSERT(
bool dirtyTest =
false;
for (
auto d
845 : m_dataDirty ) { dirtyTest = dirtyTest || d; } );
846 CORE_ASSERT( dirtyTest == m_isDirty,
"Dirty flags inconsistency" );
847 CORE_ASSERT( !( m_mesh.vertices().empty() ),
"No vertex." );
849 updateGL_specific_impl();
850 #ifdef CORE_USE_DOUBLE
853 auto idx = m_handleToBuffer[b->
getName()];
855 if ( m_dataDirty[idx] ) {
856 if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
861 auto data = std::make_unique<float[]>( size * eltSize );
862 const void* ptr = b->
dataPtr();
863 const char* cptr =
reinterpret_cast<const char*
>( ptr );
865 for (
size_t i = 0; i < size; i++ ) {
866 auto tptr =
reinterpret_cast<const Scalar*
>( cptr + i * stride );
867 for (
size_t j = 0; j < eltSize; ++j ) {
868 data[i * eltSize + j] = tptr[j];
872 m_vbos[idx]->setData(
873 size * eltSize *
sizeof(
float ), data.get(), GL_DYNAMIC_DRAW );
875 m_dataDirty[idx] =
false;
881 auto idx = m_handleToBuffer[b->
getName()];
883 if ( m_dataDirty[idx] ) {
884 if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
886 m_dataDirty[idx] =
false;
890 m_mesh.vertexAttribs().for_each_attrib( func );
893 for (
auto buffer : m_handleToBuffer ) {
896 if ( !m_mesh.hasAttrib( buffer.first ) && m_vbos[buffer.second] ) {
897 m_vbos[buffer.second].reset(
nullptr );
898 m_dataDirty[buffer.second] =
false;
907 template <
typename CoreGeometry>
909 const std::string& meshAttribName,
910 const std::string& shaderAttribName ) {
912 m_translationTable.replace( meshAttribName, shaderAttribName );
917 template <
typename T>
919 typename base::CoreGeometry&& geom,
920 typename base::MeshRenderMode renderMode ) :
921 base( name, renderMode ) {
925 template <
typename T>
928 base::loadGeometry_common( std::move( mesh ) );
934 template <
typename T>
937 m_indices = globjects::Buffer::create();
938 m_indicesDirty =
true;
940 if ( m_indicesDirty ) {
944 base::m_mesh.getIndices().size() * base::CoreGeometry::IndexType::RowsAtCompileTime;
947 static_cast<gl::GLsizeiptr
>( base::m_mesh.getIndices().size() *
948 sizeof(
typename base::CoreGeometry::IndexType ) ),
949 base::m_mesh.getIndices().data(),
951 m_indicesDirty =
false;
953 if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
955 base::m_vao->bindElementBuffer( m_indices.get() );
956 base::m_vao->unbind();
959 template <
typename T>
964 base::autoVertexAttribPointer( prog );
966 base::m_vao->drawElements(
static_cast<GLenum
>( base::m_renderMode ),
967 GLsizei( m_numElements ),
971 base::m_vao->unbind();
978 template <
typename T>
980 typename base::CoreGeometry&& geom,
981 typename base::MeshRenderMode renderMode ) :
982 base( name, renderMode ) {
986 template <
typename T>
990 base::loadGeometry_common( std::move( mesh ) );
991 CORE_ASSERT(
false,
"not implemented yet" );
998 template <
typename T>
1000 CORE_ASSERT(
false,
"not implemented yet" );
1028 template <
typename T>
1030 CORE_ASSERT(
false,
"not implemented yet" );
1050 PointCloud::PointCloud(
const std::string& name,
1051 typename base::CoreGeometry&& geom,
1052 typename base::MeshRenderMode renderMode ) :
1053 base( name, renderMode ) {
1057 PointCloud::PointCloud(
const std::string& name,
typename base::MeshRenderMode renderMode ) :
1058 base( name, renderMode ) {}
1062 LineMesh::LineMesh(
const std::string& name,
1063 typename base::CoreGeometry&& geom,
1064 typename base::MeshRenderMode renderMode ) :
1065 base( name, std::move( geom ), renderMode ) {}
1067 LineMesh::LineMesh(
const std::string& name,
typename base::MeshRenderMode renderMode ) :
1068 base( name, renderMode ) {}
1072 template <
typename T>
1073 size_t GeneralMesh<T>::getNumFaces()
const {
1074 return this->getCoreGeometry().getIndices().size();
1077 template <
typename T>
1079 if ( !this->m_indices ) {
1080 this->m_indices = globjects::Buffer::create();
1081 this->m_indicesDirty =
true;
1083 if ( this->m_indicesDirty ) {
1087 this->m_numElements = m_triangleIndices.size() * GeneralMesh::IndexType::RowsAtCompileTime;
1089 this->m_indices->setData(
static_cast<gl::GLsizeiptr
>( m_triangleIndices.size() *
1090 sizeof( GeneralMesh::IndexType ) ),
1091 m_triangleIndices.data(),
1093 this->m_indicesDirty =
false;
1095 if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
1096 base::m_vao->bind();
1097 base::m_vao->bindElementBuffer( this->m_indices.get() );
1098 base::m_vao->unbind();
1101 template <
typename T>
1103 m_triangleIndices.clear();
1104 m_triangleIndices.reserve( this->m_mesh.getIndices().size() );
1105 for (
const auto& face : this->m_mesh.getIndices() ) {
1106 if ( face.size() == 3 ) { m_triangleIndices.push_back( face ); }
1109 int minus { int( face.size() ) - 1 };
1111 while ( plus + 1 < minus ) {
1112 if ( ( plus - minus ) % 2 ) {
1113 m_triangleIndices.emplace_back( face[plus], face[plus + 1], face[minus] );
1117 m_triangleIndices.emplace_back( face[minus], face[plus], face[minus - 1] );
1126 inline void GeneralMesh<Core::Geometry::QuadMesh>::triangulate() {
1127 m_triangleIndices.clear();
1128 m_triangleIndices.reserve( 2 * this->m_mesh.getIndices().size() );
1130 for (
const auto& face : this->m_mesh.getIndices() ) {
1131 m_triangleIndices.emplace_back( face[0], face[1], face[2] );
1132 m_triangleIndices.emplace_back( face[0], face[2], face[3] );
bool isLineMesh() const
Return true if the object is a Line Mesh.
Geometry::MultiIndexedGeometry & getGeometry()
Read/write access to the multiIndexedGeometry;.
This class represents vertex + attributes per vertex. Toplogy is handled in MultiIndexedGeometry subc...
Utils::AttribManager & vertexAttribs()
std::pair< LayerKeyType, const GeometryIndexLayerBase & > getFirstLayerOccurrence(const LayerSemanticCollection &semantics) const
Read-only access to a layer.
std::string getName() const
Return the attribute's name.
An attrib handle basically store an Index and a name.
The AttribManager provides attributes management by handles.
virtual int getStride() const =0
virtual size_t getSize() const =0
virtual size_t getNumberOfComponents() const =0
virtual size_t getBufferSize() const =0
virtual const void * dataPtr() const =0
std::set< SemanticName > SemanticNameCollection
Store in set to allow for logarithmic search.
int attach(Observer observer)
void updateGL() override=0
MeshRenderMode getRenderMode() const
Get the render mode.
void updatePickingRenderMode()
Update the picking render mode according to the object render mode.
void setRenderMode(MeshRenderMode mode)
Set the render mode.
Template class to manage the Displayable aspect of a Core Geomertry, such as TriangleMesh.
void updateGL() override
Update (i.e. send to GPU) the buffers marked as dirty.
void addAttribObserver(const std::string &name)
void autoVertexAttribPointer(const ShaderProgram *prog)
assume m_vao is bound.
void setAttribNameCorrespondance(const std::string &meshAttribName, const std::string &shaderAttribName)
virtual void loadGeometry(CoreGeometry &&mesh)
Ra::Core::Utils::AttribHandle< A > addAttrib(const std::string &name, const typename Core::VectorArray< A > &data)
Helper function that calls Ra::Core::CoreGeometry::addAttrib()
const Core::Geometry::AbstractGeometry & getAbstractGeometry() const override
const std::string & getName() const
Returns the name of the mesh.
void updateGL_specific_impl() override
void autoVertexAttribPointer(const ShaderProgram *prog)
assume m_vao is bound.
An engine mesh owning CoreGeometry, with indices.
void loadGeometry(T &&mesh) override
void updateGL_specific_impl() override
void render(const ShaderProgram *prog) override
LineMesh, own a Core::Geometry::LineMesh.
Mesh, own a Core::Geometry::TriangleMesh.
void updateGL_specific_impl() override
void render(const ShaderProgram *prog) override
void loadGeometry(T &&mesh) override
A PointCloud without indices.
IndicesObserver(VaoIndices *displayable)
not tested
void operator()()
not tested
Concept class to ensure consistent naming of VaoIndices accross derived classes.
void setIndicesDirty()
Tag the indices as dirty, asking for a update to gpu.
Index layer for line mesh.