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
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,
396 using base::IndexedGeometry;
399 typename base::CoreGeometry&& geom,
415 using base::IndexedGeometry;
416 size_t getNumFaces()
const override;
425 using base::loadGeometry;
426 [[deprecated]]
void loadGeometry(
const Core::Vector3Array& vertices,
441 using IndexType = Core::Vector3ui;
444 using base::IndexedGeometry;
445 inline size_t getNumFaces()
const override;
448 inline void updateGL_specific_impl()
override;
451 inline void triangulate();
460template <
typename CoreMeshType>
463 typename CoreMeshType::IndexContainerType indices;
467 const auto& [layerKeyType, layerBase] =
469 const auto& layer =
static_cast<
472 const auto& faces = layer.collection();
473 indices.
reserve( faces.size() );
482 indices.reserve( edges.size() );
484 edges.begin(), edges.end(),
std::back_inserter( indices ), []( Ra::Core::Vector2ui v ) {
485 return ( Ra::Core::Vector3ui { v( 0 ), v( 1 ), v( 1 ) } );
493 mesh.vertexAttribs().copyAllAttributes( data->getGeometry().vertexAttribs() );
499namespace RenderMeshType {
500template <
class CoreMeshT>
504struct getType<
Ra::Core::Geometry::LineMesh> {
509struct getType<
Ra::Core::Geometry::TriangleMesh> {
514struct getType<
Ra::Core::Geometry::QuadMesh> {
519struct getType<
Ra::Core::Geometry::PolyMesh> {
525template <
typename CoreMeshType>
526typename RenderMeshType::getType<CoreMeshType>::Type*
528 using MeshType =
typename RenderMeshType::getType<CoreMeshType>::Type;
530 auto mesh = createCoreMeshFromGeometryData<CoreMeshType>( data );
532 MeshType* ret =
new MeshType { name };
542 updatePickingRenderMode();
551void VaoIndices::setIndicesDirty() {
552 m_indicesDirty =
true;
562 auto handle = m_attribManager.addAttrib<T>( name );
563 m_attribManager.getAttrib( handle ).setData( data );
564 m_handleToBuffer[name] = m_dataDirty.size();
565 m_dataDirty.push_back(
true );
566 m_vbos.emplace_back(
nullptr );
572void IndexedAttribArrayDisplayable<I>::addAttrib(
574 const typename Ra::Core ::Utils::Attrib<T>::Container&& data ) {
575 auto handle = m_attribManager.addAttrib<T>( name );
576 m_attribManager.getAttrib( handle ).setData(
std::move( data ) );
577 m_handleToBuffer[name] = m_dataDirty.size();
578 m_dataDirty.push_back(
true );
579 m_vbos.emplace_back(
nullptr );
584void IndexedAttribArrayDisplayable<I>::updateGL() {
587 ON_ASSERT(
bool dirtyTest =
false;
588 for (
const auto& d : m_dataDirty ) { dirtyTest = dirtyTest || d; } );
589 CORE_ASSERT( dirtyTest == m_isDirty,
"Dirty flags inconsistency" );
592 m_indices = globjects::Buffer::create();
593 m_indicesDirty =
true;
595 if ( m_indicesDirty ) {
597 static_cast<gl::GLsizeiptr
>( m_cpu_indices.size() *
sizeof( IndexType ) ),
598 m_cpu_indices.data(),
600 m_indicesDirty =
false;
603 m_numElements = m_cpu_indices.size();
605 if ( !m_vao ) { m_vao = globjects::VertexArray::create(); }
607 m_vao->bindElementBuffer( m_indices.get() );
611 auto idx = m_handleToBuffer[b->getName()];
613 if ( m_dataDirty[idx] ) {
614 if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
615 m_vbos[idx]->setData( b->getBufferSize(), b->dataPtr(), GL_DYNAMIC_DRAW );
616 m_dataDirty[idx] =
false;
619 m_attribManager.for_each_attrib( func );
628 auto glprog = prog->getProgramObject();
629 gl::GLint attribCount = glprog->get( GL_ACTIVE_ATTRIBUTES );
631 for ( GLint idx = 0; idx < attribCount; ++idx ) {
632 const gl::GLsizei bufSize = 256;
633 gl::GLchar name[bufSize];
637 glprog->getActiveAttrib( idx, bufSize, &length, &size, &type, name );
638 auto loc = glprog->getAttributeLocation( name );
640 auto attribName = name;
641 auto attrib = m_attribManager.getAttribBase( attribName );
643 if ( attrib && attrib->getSize() > 0 ) {
644 m_vao->enable( loc );
645 auto binding = m_vao->binding( idx );
646 binding->setAttribute( loc );
647 CORE_ASSERT( m_vbos[m_handleToBuffer[attribName]].get(),
"vbo is nullptr" );
648#ifdef CORE_USE_DOUBLE
649 binding->setBuffer( m_vbos[m_handleToBuffer[attribName]].get(),
651 attrib->getNumberOfComponents() *
sizeof(
float ) );
655 m_vbos[m_handleToBuffer[attribName]].get(), 0, attrib->getStride() );
657 binding->setFormat( attrib->getNumberOfComponents(), GL_SCALAR );
659 else { m_vao->disable( loc ); }
666 autoVertexAttribPointer( prog );
668 m_vao->drawElements(
static_cast<GLenum
>( m_renderMode ),
669 GLsizei( m_numElements ),
678template <
typename CoreGeometry>
679CoreGeometryDisplayable<CoreGeometry>::CoreGeometryDisplayable(
const std::string& name,
680 MeshRenderMode renderMode ) :
681 base( name, renderMode ) {
682 setupCoreMeshObservers();
685template <
typename CoreGeometry>
691template <
typename CoreGeometry>
696template <
typename CoreGeometry>
698CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry()
const {
702template <
typename CoreGeometry>
704CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry() {
708template <
typename CoreGeometry>
709const CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry()
const {
713template <
typename CoreGeometry>
714CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry() {
718template <
typename CoreGeometry>
719void CoreGeometryDisplayable<CoreGeometry>::addToTranslationTable(
const std::string& name ) {
720 m_translationTable.insert( name, name );
723template <
typename CoreGeometry>
730 auto itr = m_handleToBuffer.find( name );
731 if ( itr == m_handleToBuffer.end() ) {
732 m_handleToBuffer[name] = m_dataDirty.size();
734 addToTranslationTable( name );
736 m_dataDirty.push_back(
true );
737 m_vbos.emplace_back(
nullptr );
739 auto idx = m_handleToBuffer[name];
740 attrib->attach( AttribObserver(
this, idx ) );
746template <
typename CoreGeometry>
749 auto glprog = prog->getProgramObject();
750 gl::GLint attribCount = glprog->get( GL_ACTIVE_ATTRIBUTES );
752 for ( GLint idx = 0; idx < attribCount; ++idx ) {
753 const gl::GLsizei bufSize = 256;
754 gl::GLchar name[bufSize];
758 glprog->getActiveAttrib( idx, bufSize, &length, &size, &type, name );
759 auto loc = glprog->getAttributeLocation( name );
761 auto attribNameOpt = m_translationTable.keyIfExists( name );
762 if ( attribNameOpt ) {
763 auto attribName = *attribNameOpt;
764 auto attrib = m_mesh.getAttribBase( attribName );
765 if ( attrib && attrib->getSize() > 0 ) {
766 m_vao->enable( loc );
767 auto binding = m_vao->binding( idx );
768 binding->setAttribute( loc );
769 CORE_ASSERT( m_vbos[m_handleToBuffer[attribName]].get(),
"vbo is nullptr" );
770#ifdef CORE_USE_DOUBLE
771 binding->setBuffer( m_vbos[m_handleToBuffer[attribName]].get(),
773 attrib->getNumberOfComponents() *
sizeof(
float ) );
777 m_vbos[m_handleToBuffer[attribName]].get(), 0, attrib->getStride() );
779 binding->setFormat( attrib->getNumberOfComponents(), GL_SCALAR );
781 else { m_vao->disable( loc ); }
783 else { m_vao->disable( loc ); }
790 setupCoreMeshObservers();
795void CoreGeometryDisplayable<T>::setupCoreMeshObservers() {
797 m_dataDirty.resize( m_mesh.vertexAttribs().getNumAttribs() );
798 m_vbos.resize( m_mesh.vertexAttribs().getNumAttribs() );
802 m_handleToBuffer[name] = idx;
803 m_dataDirty[idx] =
true;
806 addToTranslationTable( name );
808 b->
attach( AttribObserver(
this, idx ) );
813 m_mesh.vertexAttribs().attachMember(
819template <
typename CoreGeometry>
824 return m_mesh.addAttrib( name, data );
827template <
typename CoreGeometry>
829 return m_mesh.vertices().size();
832template <
typename CoreGeometry>
834 CORE_ASSERT(
false,
"must be specialized" );
837template <
typename CoreGeometry>
841 ON_ASSERT(
bool dirtyTest =
false;
842 for (
auto d : m_dataDirty ) { dirtyTest = dirtyTest || d; } );
843 CORE_ASSERT( dirtyTest == m_isDirty,
"Dirty flags inconsistency" );
844 CORE_ASSERT( !( m_mesh.vertices().empty() ),
"No vertex." );
846 updateGL_specific_impl();
847#ifdef CORE_USE_DOUBLE
850 auto idx = m_handleToBuffer[b->
getName()];
852 if ( m_dataDirty[idx] ) {
853 if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
858 auto data = std::make_unique<float[]>( size * eltSize );
859 const void* ptr = b->
dataPtr();
860 const char* cptr =
reinterpret_cast<const char*
>( ptr );
862 for (
size_t i = 0; i < size; i++ ) {
863 auto tptr =
reinterpret_cast<const Scalar*
>( cptr + i * stride );
864 for (
size_t j = 0; j < eltSize; ++j ) {
865 data[i * eltSize + j] = tptr[j];
869 m_vbos[idx]->setData(
870 size * eltSize *
sizeof(
float ), data.get(), GL_DYNAMIC_DRAW );
872 m_dataDirty[idx] =
false;
878 auto idx = m_handleToBuffer[b->
getName()];
880 if ( m_dataDirty[idx] ) {
881 if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
883 m_dataDirty[idx] =
false;
887 m_mesh.vertexAttribs().for_each_attrib( func );
890 for (
auto buffer : m_handleToBuffer ) {
893 if ( !m_mesh.hasAttrib( buffer.first ) && m_vbos[buffer.second] ) {
894 m_vbos[buffer.second].reset(
nullptr );
895 m_dataDirty[buffer.second] =
false;
904template <
typename CoreGeometry>
909 m_translationTable.replace( meshAttribName, shaderAttribName );
916 typename base::CoreGeometry&& geom,
917 typename base::MeshRenderMode renderMode ) :
918 base( name, renderMode ) {
925 base::loadGeometry_common(
std::move( mesh ) );
934 m_indices = globjects::Buffer::create();
935 m_indicesDirty =
true;
937 if ( m_indicesDirty ) {
941 base::m_mesh.getIndices().size() * base::CoreGeometry::IndexType::RowsAtCompileTime;
944 static_cast<gl::GLsizeiptr
>( base::m_mesh.getIndices().size() *
945 sizeof(
typename base::CoreGeometry::IndexType ) ),
946 base::m_mesh.getIndices().data(),
948 m_indicesDirty =
false;
950 if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
952 base::m_vao->bindElementBuffer( m_indices.get() );
953 base::m_vao->unbind();
961 base::autoVertexAttribPointer( prog );
963 base::m_vao->drawElements(
static_cast<GLenum
>( base::m_renderMode ),
964 GLsizei( m_numElements ),
968 base::m_vao->unbind();
977 typename base::CoreGeometry&& geom,
978 typename base::MeshRenderMode renderMode ) :
979 base( name, renderMode ) {
987 base::loadGeometry_common(
std::move( mesh ) );
988 CORE_ASSERT(
false,
"not implemented yet" );
997 CORE_ASSERT(
false,
"not implemented yet" );
1025template <
typename T>
1027 CORE_ASSERT(
false,
"not implemented yet" );
1048 typename base::CoreGeometry&& geom,
1049 typename base::MeshRenderMode renderMode ) :
1050 base( name, renderMode ) {
1054PointCloud::PointCloud(
const std::string& name,
typename base::MeshRenderMode renderMode ) :
1055 base( name, renderMode ) {}
1060 typename base::CoreGeometry&& geom,
1061 typename base::MeshRenderMode renderMode ) :
1062 base( name,
std::move( geom ), renderMode ) {}
1064LineMesh::LineMesh(
const std::string& name,
typename base::MeshRenderMode renderMode ) :
1065 base( name, renderMode ) {}
1069template <
typename T>
1070size_t GeneralMesh<T>::getNumFaces()
const {
1071 return this->getCoreGeometry().getIndices().size();
1074template <
typename T>
1076 if ( !this->m_indices ) {
1077 this->m_indices = globjects::Buffer::create();
1078 this->m_indicesDirty =
true;
1080 if ( this->m_indicesDirty ) {
1084 this->m_numElements = m_triangleIndices.size() * GeneralMesh::IndexType::RowsAtCompileTime;
1086 this->m_indices->setData(
static_cast<gl::GLsizeiptr
>( m_triangleIndices.size() *
1087 sizeof( GeneralMesh::IndexType ) ),
1088 m_triangleIndices.data(),
1090 this->m_indicesDirty =
false;
1092 if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
1093 base::m_vao->bind();
1094 base::m_vao->bindElementBuffer( this->m_indices.get() );
1095 base::m_vao->unbind();
1098template <
typename T>
1100 m_triangleIndices.clear();
1101 m_triangleIndices.reserve( this->m_mesh.getIndices().size() );
1102 for (
const auto& face : this->m_mesh.getIndices() ) {
1103 if ( face.size() == 3 ) { m_triangleIndices.push_back( face ); }
1106 int minus { int( face.size() ) - 1 };
1108 while ( plus + 1 < minus ) {
1109 if ( ( plus - minus ) % 2 ) {
1110 m_triangleIndices.emplace_back( face[plus], face[plus + 1], face[minus] );
1114 m_triangleIndices.emplace_back( face[minus], face[plus], face[minus - 1] );
1123inline void GeneralMesh<Core::Geometry::QuadMesh>::triangulate() {
1124 m_triangleIndices.clear();
1125 m_triangleIndices.reserve( 2 * this->m_mesh.getIndices().size() );
1127 for (
const auto& face : this->m_mesh.getIndices() ) {
1128 m_triangleIndices.emplace_back( face[0], face[1], face[2] );
1129 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.