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>
31using namespace Ra::Core::Utils;
35class RA_ENGINE_API
Vao
35class RA_ENGINE_API
Vao {
…};
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 );
83 using Displayable::getName;
86 inline void setRenderMode( MeshRenderMode mode );
88 inline MeshRenderMode getRenderMode()
const;
96 void setDirty(
const Core::Geometry::MeshAttrib& type );
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;
156 MeshRenderMode m_renderMode { MeshRenderMode::RM_TRIANGLES };
169 bool m_isDirty {
false };
177 inline void setIndicesDirty();
194 bool m_indicesDirty {
true };
197 size_t m_numElements { 0 };
209 template <
typename T>
212 template <
typename T>
214 const typename Ra::Core ::Utils::Attrib<T>::Container&& data );
215 inline void updateGL()
override;
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;
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;
318 typename base::CoreGeometry&& geom,
326 void loadGeometry( Core::Geometry::PointCloud&& mesh )
override;
329 void updateGL_specific_impl()
override;
341 typename base::CoreGeometry&& geom,
362 typename base::CoreGeometry&& geom,
376 struct RA_CORE_API KeyHash {
399 using base::IndexedGeometry;
402 typename base::CoreGeometry&& geom,
418 using base::IndexedGeometry;
419 size_t getNumFaces()
const override;
428 using base::loadGeometry;
429 [[deprecated]]
void loadGeometry(
const Core::Vector3Array& vertices,
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();
463template <
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() );
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 ) } );
496 mesh.vertexAttribs().copyAllAttributes( data->getGeometry().vertexAttribs() );
502namespace RenderMeshType {
503template <
class CoreMeshT>
507struct getType<
Ra::Core::Geometry::LineMesh> {
512struct getType<
Ra::Core::Geometry::TriangleMesh> {
517struct getType<
Ra::Core::Geometry::QuadMesh> {
522struct getType<
Ra::Core::Geometry::PolyMesh> {
502namespace RenderMeshType {
…}
528template <
typename CoreMeshType>
529typename RenderMeshType::getType<CoreMeshType>::Type*
531 using MeshType =
typename RenderMeshType::getType<CoreMeshType>::Type;
533 auto mesh = createCoreMeshFromGeometryData<CoreMeshType>( data );
535 MeshType* ret =
new MeshType { name };
545 updatePickingRenderMode();
554void VaoIndices::setIndicesDirty() {
555 m_indicesDirty =
true;
554void VaoIndices::setIndicesDirty() {
…}
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 );
575void IndexedAttribArrayDisplayable<I>::addAttrib(
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 );
587void IndexedAttribArrayDisplayable<I>::updateGL() {
590 ON_ASSERT(
bool dirtyTest =
false;
591 for (
const auto& d : 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 );
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 ); }
669 autoVertexAttribPointer( prog );
671 m_vao->drawElements(
static_cast<GLenum
>( m_renderMode ),
672 GLsizei( m_numElements ),
681template <
typename CoreGeometry>
682CoreGeometryDisplayable<CoreGeometry>::CoreGeometryDisplayable(
const std::string& name,
683 MeshRenderMode renderMode ) :
684 base( name, renderMode ) {
685 setupCoreMeshObservers();
688template <
typename CoreGeometry>
694template <
typename CoreGeometry>
699template <
typename CoreGeometry>
701CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry()
const {
705template <
typename CoreGeometry>
707CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry() {
711template <
typename CoreGeometry>
712const CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry()
const {
716template <
typename CoreGeometry>
717CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry() {
721template <
typename CoreGeometry>
722void CoreGeometryDisplayable<CoreGeometry>::addToTranslationTable(
const std::string& name ) {
723 m_translationTable.insert( name, name );
726template <
typename CoreGeometry>
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 ) );
749template <
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 ); }
793 setupCoreMeshObservers();
798void 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(
822template <
typename CoreGeometry>
827 return m_mesh.addAttrib( name, data );
830template <
typename CoreGeometry>
832 return m_mesh.vertices().size();
835template <
typename CoreGeometry>
837 CORE_ASSERT(
false,
"must be specialized" );
840template <
typename CoreGeometry>
844 ON_ASSERT(
bool dirtyTest =
false;
845 for (
auto d : 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;
907template <
typename CoreGeometry>
912 m_translationTable.replace( meshAttribName, shaderAttribName );
919 typename base::CoreGeometry&& geom,
920 typename base::MeshRenderMode renderMode ) :
921 base( name, renderMode ) {
928 base::loadGeometry_common(
std::move( mesh ) );
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();
964 base::autoVertexAttribPointer( prog );
966 base::m_vao->drawElements(
static_cast<GLenum
>( base::m_renderMode ),
967 GLsizei( m_numElements ),
971 base::m_vao->unbind();
980 typename base::CoreGeometry&& geom,
981 typename base::MeshRenderMode renderMode ) :
982 base( name, renderMode ) {
990 base::loadGeometry_common(
std::move( mesh ) );
991 CORE_ASSERT(
false,
"not implemented yet" );
1000 CORE_ASSERT(
false,
"not implemented yet" );
1028template <
typename T>
1030 CORE_ASSERT(
false,
"not implemented yet" );
1051 typename base::CoreGeometry&& geom,
1052 typename base::MeshRenderMode renderMode ) :
1053 base( name, renderMode ) {
1057PointCloud::PointCloud(
const std::string& name,
typename base::MeshRenderMode renderMode ) :
1058 base( name, renderMode ) {}
1063 typename base::CoreGeometry&& geom,
1064 typename base::MeshRenderMode renderMode ) :
1065 base( name,
std::move( geom ), renderMode ) {}
1067LineMesh::LineMesh(
const std::string& name,
typename base::MeshRenderMode renderMode ) :
1068 base( name, renderMode ) {}
1072template <
typename T>
1073size_t GeneralMesh<T>::getNumFaces()
const {
1074 return this->getCoreGeometry().getIndices().size();
1077template <
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();
1101template <
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] );
1126inline 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] );
T back_inserter(T... args)
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::AttribBase * getAttribBase(const std::string &name)
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.
Bijective association between two sets {keys} and {values} having the same cardinality....
virtual const void * dataPtr() const =0
virtual int getStride() const =0
virtual size_t getSize() const =0
virtual size_t getNumberOfComponents() const =0
virtual size_t getBufferSize() const =0
std::set< SemanticName > SemanticNameCollection
Store in set to allow for logarithmic search.
int attach(Observer observer)
void updateGL() override=0
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.
BijectiveAssociation< std::string, std::string > m_translationTable
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
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.
CoreMeshType createCoreMeshFromGeometryData(const Ra::Core::Asset::GeometryData *data)
RenderMeshType::getType< CoreMeshType >::Type * createMeshFromGeometryData(const std::string &name, const Ra::Core::Asset::GeometryData *data)
create Mesh, PolyMesh Engine::Data::*Mesh * from GeometryData
hepler function to manage enum as underlying types in VariableSet
Index layer for line mesh.