Radium Engine  1.5.0
Mesh.hpp
1 #pragma once
2 
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>
15 
16 #include <globjects/Buffer.h>
17 #include <globjects/Program.h>
18 #include <globjects/VertexArray.h>
19 #include <globjects/VertexAttributeBinding.h>
20 
21 #include <array>
22 #include <iterator>
23 #include <map>
24 #include <vector>
25 
26 namespace Ra {
27 namespace Engine {
28 namespace Data {
29 class ShaderProgram;
30 
31 using namespace Ra::Core::Utils;
32 
35 class RA_ENGINE_API Vao
36 {
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;
42 };
43 
51 class RA_ENGINE_API AttribArrayDisplayable : public Displayable
52 {
53  public:
57  enum MeshRenderMode : uint {
58  RM_POINTS = 0x0000,
59  RM_LINES = 0x0001, // decimal value: 1
60  RM_LINE_LOOP = 0x0002, // decimal value: 2
61  RM_LINE_STRIP = 0x0003, // decimal value: 3
62  RM_TRIANGLES = 0x0004, // decimal value: 4
63  RM_TRIANGLE_STRIP = 0x0005, // decimal value: 5
64  RM_TRIANGLE_FAN = 0x0006, // decimal value: 6
65  RM_QUADS = 0x0007, // decimal value: 7
66  RM_QUAD_STRIP = 0x0008, // decimal value: 8
67  RM_POLYGON = 0x0009, // decimal value: 9
68  RM_LINES_ADJACENCY = 0x000A, // decimal value: 10
69  RM_LINE_STRIP_ADJACENCY = 0x000B, // decimal value: 11
70  RM_TRIANGLES_ADJACENCY = 0x000C, // decimal value: 12
71  RM_TRIANGLE_STRIP_ADJACENCY = 0x000D, // decimal value: 13
72  RM_PATCHES = 0x000E, // decimal value: 14
73  };
74 
75  public:
76  explicit AttribArrayDisplayable( const std::string& name,
77  MeshRenderMode renderMode = RM_TRIANGLES );
78  AttribArrayDisplayable( const AttribArrayDisplayable& rhs ) = delete;
79  void operator=( const AttribArrayDisplayable& rhs ) = delete;
80 
82 
84 
86  inline void setRenderMode( MeshRenderMode mode );
88  inline MeshRenderMode getRenderMode() const;
89 
93 
96  void setDirty( const Core::Geometry::MeshAttrib& type );
97 
99  void setDirty( const std::string& name );
100 
103  void setDirty( unsigned int index );
105 
108  void updateGL() override = 0;
109 
113  virtual const Core::Geometry::AttribArrayGeometry& getAttribArrayGeometry() const = 0;
114  virtual Core::Geometry::AttribArrayGeometry& getAttribArrayGeometry() = 0;
116 
121  Ra::Core::Utils::optional<gl::GLuint> getVboHandle( const std::string& name );
122 
126  Ra::Core::Utils::optional<gl::GLuint> getVaoHandle();
127 
128  protected:
130  void updatePickingRenderMode();
131 
132  class AttribObserver
133  {
134  public:
135  explicit AttribObserver( AttribArrayDisplayable* displayable, int idx ) :
136  m_displayable( displayable ), m_idx( idx ) {}
137  void operator()() {
138  if ( m_idx < int( m_displayable->m_dataDirty.size() ) ) {
139  m_displayable->m_dataDirty[m_idx] = true;
140  m_displayable->m_isDirty = true;
141  }
142  else {
144  LOG( logDEBUG ) << "Invalid dirty bit notified on " << m_displayable->getName();
145  }
146  }
147 
148  private:
149  AttribArrayDisplayable* m_displayable;
150  int m_idx;
151  };
152 
153  protected:
154  std::unique_ptr<globjects::VertexArray> m_vao;
155 
156  MeshRenderMode m_renderMode { MeshRenderMode::RM_TRIANGLES };
157 
158  // m_vbos and m_dataDirty have the same size and are indexed thru m_handleToBuffer[attribName]
159  std::vector<std::unique_ptr<globjects::Buffer>> m_vbos;
160  std::vector<bool> m_dataDirty;
161 
162  // Geometry attrib name (std::string) to buffer id (int)
163  // buffer id are indices in m_vbos and m_dataDirty
164  std::map<std::string, unsigned int> m_handleToBuffer;
165 
169  bool m_isDirty { false };
170 };
171 
173 class RA_ENGINE_API VaoIndices
174 {
175  public:
177  inline void setIndicesDirty();
178 
181  {
182  public:
184  explicit IndicesObserver( VaoIndices* displayable ) : m_displayable { displayable } {}
186  void operator()() { m_displayable->m_indicesDirty = true; }
187 
188  private:
189  VaoIndices* m_displayable;
190  };
191 
192  protected:
193  std::unique_ptr<globjects::Buffer> m_indices { nullptr };
194  bool m_indicesDirty { true };
197  size_t m_numElements { 0 };
198 };
199 
203 template <typename I>
205 {
206  using IndexType = I;
207  using IndexContainerType = Ra::Core::AlignedStdVector<IndexType>;
208 
209  template <typename T>
210  inline void addAttrib( const std::string& name,
211  const typename Ra::Core::Utils::Attrib<T>::Container& data );
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;
216 
217  inline void render( const ShaderProgram* prog ) override;
218 
219  protected:
221  inline void autoVertexAttribPointer( const ShaderProgram* prog );
222  IndexContainerType m_cpu_indices;
223  AttribManager m_attribManager;
224 };
225 
227 template <typename T>
229 {
230  public:
232  using CoreGeometry = T;
233 
234  explicit CoreGeometryDisplayable( const std::string& name,
235  MeshRenderMode renderMode = RM_TRIANGLES );
236 
237  // no need to detach observer in dtor since CoreGeometry is owned by this, and CoreGeometry dtor
238  // will detachAll observers.
239 
244  inline Core::Geometry::AbstractGeometry& getAbstractGeometry() override;
245 
246  inline const Core::Geometry::AttribArrayGeometry& getAttribArrayGeometry() const override;
247  inline Core::Geometry::AttribArrayGeometry& getAttribArrayGeometry() override;
248 
249  inline const CoreGeometry& getCoreGeometry() const;
250  inline CoreGeometry& getCoreGeometry();
252 
254  template <typename A>
255  inline Ra::Core::Utils::AttribHandle<A> addAttrib( const std::string& name,
256  const typename Core::VectorArray<A>& data );
257  inline size_t getNumVertices() const override;
258 
268  virtual void loadGeometry( CoreGeometry&& mesh );
269 
271  void updateGL() override;
272 
283  void setAttribNameCorrespondance( const std::string& meshAttribName,
284  const std::string& shaderAttribName );
285 
286  protected:
287  virtual void updateGL_specific_impl() {}
288 
289  void loadGeometry_common( CoreGeometry&& mesh );
290  void setupCoreMeshObservers();
291 
294 
298  void addAttribObserver( const std::string& name );
299 
300  void addToTranslationTable( const std::string& name );
301 
305 
306  CoreGeometry m_mesh;
307 };
308 
310 class RA_ENGINE_API PointCloud : public CoreGeometryDisplayable<Core::Geometry::PointCloud>
311 {
313 
314  public:
315  using base::CoreGeometryDisplayable;
316  inline explicit PointCloud(
317  const std::string& name,
318  typename base::CoreGeometry&& geom,
319  typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_POINTS );
320 
321  inline explicit PointCloud( const std::string& name, MeshRenderMode renderMode = RM_POINTS );
322 
324  void render( const ShaderProgram* prog ) override;
325 
326  void loadGeometry( Core::Geometry::PointCloud&& mesh ) override;
327 
328  protected:
329  void updateGL_specific_impl() override;
330 };
331 
333 template <typename T>
335 {
336  public:
339  explicit IndexedGeometry(
340  const std::string& name,
341  typename base::CoreGeometry&& geom,
342  typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_TRIANGLES );
343 
344  void render( const ShaderProgram* prog ) override;
345 
346  void loadGeometry( T&& mesh ) override;
347 
348  protected:
349  void updateGL_specific_impl() override;
350 };
351 
354 template <typename T>
356 {
357  public:
360  explicit MultiIndexedGeometry(
361  const std::string& name,
362  typename base::CoreGeometry&& geom,
363  typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_TRIANGLES );
364  void render( const ShaderProgram* prog ) override;
365 
366  void loadGeometry( T&& mesh ) override;
367 
368  protected:
369  void updateGL_specific_impl() override;
370 
371  using LayerSemanticCollection = Core::Utils::ObjectWithSemantic::SemanticNameCollection;
372  using LayerSemantic = Core::Utils::ObjectWithSemantic::SemanticName;
373  using LayerKeyType = std::pair<LayerSemanticCollection, std::string>;
374 
375  using EntryType = std::pair<bool, VaoIndices*>;
376  struct RA_CORE_API KeyHash {
377  std::size_t operator()( const LayerKeyType& k ) const {
378  // Mix semantic collection into a single identifier string
379  std::ostringstream stream;
380  std::copy(
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() );
384 
385  // Combine with layer name hash
386  return std::hash<std::string> {}( result ) ^
387  ( std::hash<std::string> {}( k.second ) << 1 );
388  }
389  };
390  std::unordered_map<LayerKeyType, EntryType, KeyHash> m_indices;
391 };
392 
394 class RA_ENGINE_API LineMesh : public IndexedGeometry<Core::Geometry::LineMesh>
395 {
397 
398  public:
399  using base::IndexedGeometry;
400  inline explicit LineMesh(
401  const std::string& name,
402  typename base::CoreGeometry&& geom,
403  typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_LINES );
404  inline explicit LineMesh(
405  const std::string& name,
406  typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_LINES );
407 
408  protected:
409  private:
410 };
411 
413 class RA_ENGINE_API Mesh : public IndexedGeometry<Core::Geometry::TriangleMesh>
414 {
416 
417  public:
418  using base::IndexedGeometry;
419  size_t getNumFaces() const override;
420 
428  using base::loadGeometry;
429  [[deprecated]] void loadGeometry( const Core::Vector3Array& vertices,
430  const std::vector<uint>& indices );
431 
432  protected:
433  private:
434 };
435 
440 template <typename T>
441 class RA_ENGINE_API GeneralMesh : public IndexedGeometry<T>
442 {
443  using base = IndexedGeometry<T>;
444  using IndexType = Core::Vector3ui;
445 
446  public:
447  using base::IndexedGeometry;
448  inline size_t getNumFaces() const override;
449 
450  protected:
451  inline void updateGL_specific_impl() override;
452 
453  private:
454  inline void triangulate();
455  Core::AlignedStdVector<IndexType> m_triangleIndices;
456 };
457 
460 
463 template <typename CoreMeshType>
464 CoreMeshType createCoreMeshFromGeometryData( const Ra::Core::Asset::GeometryData* data ) {
465  CoreMeshType mesh;
466  typename CoreMeshType::IndexContainerType indices;
467 
468  if ( !data->isLineMesh() ) {
469  auto& geo = data->getGeometry();
470  const auto& [layerKeyType, layerBase] =
471  geo.getFirstLayerOccurrence( mesh.getLayerKey().first );
472  const auto& layer = static_cast<
474  layerBase );
475  const auto& faces = layer.collection();
476  indices.reserve( faces.size() );
477  std::copy( faces.begin(), faces.end(), std::back_inserter( indices ) );
478  }
479 #if 0
480  // TODO manage line meshes in a "usual" way, i.e. as an indexed geometry with specific
481  // rendering properties (i.e. shader, as it is the case for point clouds)
482  // Create a degenerated triangle to handle edges case.
483  else {
484  const auto& edges = ... access the LineIndexLayer
485  indices.reserve( edges.size() );
486  std::transform(
487  edges.begin(), edges.end(), std::back_inserter( indices ), []( Ra::Core::Vector2ui v ) {
488  return ( Ra::Core::Vector3ui { v( 0 ), v( 1 ), v( 1 ) } );
489  } );
490  }
491 #endif
492 
493  mesh.setIndices( std::move( indices ) );
494 
495  // This copy only "usual" attributes. See Core::Geometry::AttribManager::copyAllAttributes
496  mesh.vertexAttribs().copyAllAttributes( data->getGeometry().vertexAttribs() );
497 
498  return mesh;
499 }
500 
502 namespace RenderMeshType {
503 template <class CoreMeshT>
504 struct getType {};
505 
506 template <>
507 struct getType<Ra::Core::Geometry::LineMesh> {
508  using Type = Ra::Engine::Data::LineMesh;
509 };
510 
511 template <>
512 struct getType<Ra::Core::Geometry::TriangleMesh> {
513  using Type = Ra::Engine::Data::Mesh;
514 };
515 
516 template <>
517 struct getType<Ra::Core::Geometry::QuadMesh> {
518  using Type = Ra::Engine::Data::QuadMesh;
519 };
520 
521 template <>
522 struct getType<Ra::Core::Geometry::PolyMesh> {
523  using Type = Ra::Engine::Data::PolyMesh;
524 };
525 } // namespace RenderMeshType
526 
528 template <typename CoreMeshType>
529 typename RenderMeshType::getType<CoreMeshType>::Type*
530 createMeshFromGeometryData( const std::string& name, const Ra::Core::Asset::GeometryData* data ) {
531  using MeshType = typename RenderMeshType::getType<CoreMeshType>::Type;
532 
533  auto mesh = createCoreMeshFromGeometryData<CoreMeshType>( data );
534 
535  MeshType* ret = new MeshType { name };
536  ret->loadGeometry( std::move( mesh ) );
537 
538  return ret;
539 }
540 
542 
544  m_renderMode = mode;
546 }
547 
549  return m_renderMode;
550 }
551 
553 
555  m_indicesDirty = true;
556 }
557 
559 
560 template <typename I>
561 template <typename T>
563  const std::string& name,
564  const typename Ra::Core::Utils::Attrib<T>::Container& data ) {
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 );
570  m_isDirty = true;
571 }
572 
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 );
583  m_isDirty = true;
584 }
585 
586 template <typename I>
587 void IndexedAttribArrayDisplayable<I>::updateGL() {
588  if ( m_isDirty ) {
589  // Check that our dirty bits are consistent.
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" );
593 
594  if ( !m_indices ) {
595  m_indices = globjects::Buffer::create();
596  m_indicesDirty = true;
597  }
598  if ( m_indicesDirty ) {
599  m_indices->setData(
600  static_cast<gl::GLsizeiptr>( m_cpu_indices.size() * sizeof( IndexType ) ),
601  m_cpu_indices.data(),
602  GL_STATIC_DRAW );
603  m_indicesDirty = false;
604  }
605 
606  m_numElements = m_cpu_indices.size();
607 
608  if ( !m_vao ) { m_vao = globjects::VertexArray::create(); }
609  m_vao->bind();
610  m_vao->bindElementBuffer( m_indices.get() );
611  m_vao->unbind();
612 
613  auto func = [this]( Ra::Core::Utils::AttribBase* b ) {
614  auto idx = m_handleToBuffer[b->getName()];
615 
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;
620  }
621  };
622  m_attribManager.for_each_attrib( func );
623  GL_CHECK_ERROR;
624  m_isDirty = false;
625  }
626 }
627 
628 template <typename I>
630 
631  auto glprog = prog->getProgramObject();
632  gl::GLint attribCount = glprog->get( GL_ACTIVE_ATTRIBUTES );
633 
634  for ( GLint idx = 0; idx < attribCount; ++idx ) {
635  const gl::GLsizei bufSize = 256;
636  gl::GLchar name[bufSize];
637  gl::GLsizei length;
638  gl::GLint size;
639  gl::GLenum type;
640  glprog->getActiveAttrib( idx, bufSize, &length, &size, &type, name );
641  auto loc = glprog->getAttributeLocation( name );
642 
643  auto attribName = name; // m_translationTableShaderToMesh[name];
644  auto attrib = m_attribManager.getAttribBase( attribName );
645 
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(),
653  0,
654  attrib->getNumberOfComponents() * sizeof( float ) );
655 #else
656 
657  binding->setBuffer(
658  m_vbos[m_handleToBuffer[attribName]].get(), 0, attrib->getStride() );
659 #endif
660  binding->setFormat( attrib->getNumberOfComponents(), GL_SCALAR );
661  }
662  else { m_vao->disable( loc ); }
663  }
664 }
665 
666 template <typename I>
668  if ( m_vao ) {
669  autoVertexAttribPointer( prog );
670  m_vao->bind();
671  m_vao->drawElements( static_cast<GLenum>( m_renderMode ),
672  GLsizei( m_numElements ),
673  GL_UNSIGNED_INT,
674  nullptr );
675  m_vao->unbind();
676  }
677 }
678 
680 
681 template <typename CoreGeometry>
682 CoreGeometryDisplayable<CoreGeometry>::CoreGeometryDisplayable( const std::string& name,
683  MeshRenderMode renderMode ) :
684  base( name, renderMode ) {
685  setupCoreMeshObservers();
686 }
687 
688 template <typename CoreGeometry>
691  return m_mesh;
692 }
693 
694 template <typename CoreGeometry>
696  return m_mesh;
697 }
698 
699 template <typename CoreGeometry>
701 CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry() const {
702  return m_mesh;
703 }
704 
705 template <typename CoreGeometry>
707 CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry() {
708  return m_mesh;
709 }
710 
711 template <typename CoreGeometry>
712 const CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry() const {
713  return m_mesh;
714 }
715 
716 template <typename CoreGeometry>
717 CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry() {
718  return m_mesh;
719 }
720 
721 template <typename CoreGeometry>
722 void CoreGeometryDisplayable<CoreGeometry>::addToTranslationTable( const std::string& name ) {
723  m_translationTable.insert( name, name );
724 }
725 
726 template <typename CoreGeometry>
728  // this observer is called each time an attrib is added or removed from m_mesh
729  auto attrib = m_mesh.getAttribBase( name );
730  // if attrib not nullptr, then it's an attrib add, so attach an observer to it
731 
732  if ( attrib ) {
733  auto itr = m_handleToBuffer.find( name );
734  if ( itr == m_handleToBuffer.end() ) {
735  m_handleToBuffer[name] = m_dataDirty.size();
736 
737  addToTranslationTable( name );
738 
739  m_dataDirty.push_back( true );
740  m_vbos.emplace_back( nullptr );
741  }
742  auto idx = m_handleToBuffer[name];
743  attrib->attach( AttribObserver( this, idx ) );
744  }
745  // else it's an attrib remove, do nothing, cleanup will be done in updateGL()
746  else {}
747 }
748 
749 template <typename CoreGeometry>
751 
752  auto glprog = prog->getProgramObject();
753  gl::GLint attribCount = glprog->get( GL_ACTIVE_ATTRIBUTES );
754 
755  for ( GLint idx = 0; idx < attribCount; ++idx ) {
756  const gl::GLsizei bufSize = 256;
757  gl::GLchar name[bufSize];
758  gl::GLsizei length;
759  gl::GLint size;
760  gl::GLenum type;
761  glprog->getActiveAttrib( idx, bufSize, &length, &size, &type, name );
762  auto loc = glprog->getAttributeLocation( name );
763 
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(),
775  0,
776  attrib->getNumberOfComponents() * sizeof( float ) );
777 #else
778 
779  binding->setBuffer(
780  m_vbos[m_handleToBuffer[attribName]].get(), 0, attrib->getStride() );
781 #endif
782  binding->setFormat( attrib->getNumberOfComponents(), GL_SCALAR );
783  }
784  else { m_vao->disable( loc ); }
785  }
786  else { m_vao->disable( loc ); }
787  }
788 }
789 
790 template <typename T>
792  m_mesh = std::move( mesh );
793  setupCoreMeshObservers();
794 }
795 
796 template <typename T>
797 
798 void CoreGeometryDisplayable<T>::setupCoreMeshObservers() {
799  int idx = 0;
800  m_dataDirty.resize( m_mesh.vertexAttribs().getNumAttribs() );
801  m_vbos.resize( m_mesh.vertexAttribs().getNumAttribs() );
802  // here capture ref to idx to propagate idx incrementation
803  m_mesh.vertexAttribs().for_each_attrib( [&idx, this]( Ra::Core::Utils::AttribBase* b ) {
804  auto name = b->getName();
805  m_handleToBuffer[name] = idx;
806  m_dataDirty[idx] = true;
807 
808  // create a identity translation if name is not already translated.
809  addToTranslationTable( name );
810 
811  b->attach( AttribObserver( this, idx ) );
812  ++idx;
813  } );
814 
815  // add an observer on attrib manipulation.
816  m_mesh.vertexAttribs().attachMember(
818  m_isDirty = true;
819 }
820 
822 template <typename CoreGeometry>
823 template <typename A>
826  const typename Core::VectorArray<A>& data ) {
827  return m_mesh.addAttrib( name, data );
828 }
829 
830 template <typename CoreGeometry>
832  return m_mesh.vertices().size();
833 }
834 
835 template <typename CoreGeometry>
837  CORE_ASSERT( false, "must be specialized" );
838 }
839 
840 template <typename CoreGeometry>
842  if ( m_isDirty ) {
843  // Check that our dirty bits are consistent.
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." );
848 
849  updateGL_specific_impl();
850 #ifdef CORE_USE_DOUBLE
851  // need convserion
852  auto func = [this]( Ra::Core::Utils::AttribBase* b ) {
853  auto idx = m_handleToBuffer[b->getName()];
854 
855  if ( m_dataDirty[idx] ) {
856  if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
857 
858  auto stride = b->getStride();
859  auto eltSize = b->getNumberOfComponents();
860  auto size = b->getSize();
861  auto data = std::make_unique<float[]>( size * eltSize );
862  const void* ptr = b->dataPtr();
863  const char* cptr = reinterpret_cast<const char*>( ptr );
864 
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];
869  }
870  }
871 
872  m_vbos[idx]->setData(
873  size * eltSize * sizeof( float ), data.get(), GL_DYNAMIC_DRAW );
874 
875  m_dataDirty[idx] = false;
876  }
877  };
878 
879 #else
880  auto func = [this]( Ra::Core::Utils::AttribBase* b ) {
881  auto idx = m_handleToBuffer[b->getName()];
882 
883  if ( m_dataDirty[idx] ) {
884  if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
885  m_vbos[idx]->setData( b->getBufferSize(), b->dataPtr(), GL_DYNAMIC_DRAW );
886  m_dataDirty[idx] = false;
887  }
888  };
889 #endif
890  m_mesh.vertexAttribs().for_each_attrib( func );
891 
892  // cleanup removed attrib
893  for ( auto buffer : m_handleToBuffer ) {
894  // do not remove name from handleToBuffer to keep index ...
895  // we could also update handleToBuffer, m_vbos, m_dataDirty
896  if ( !m_mesh.hasAttrib( buffer.first ) && m_vbos[buffer.second] ) {
897  m_vbos[buffer.second].reset( nullptr );
898  m_dataDirty[buffer.second] = false;
899  }
900  }
901 
902  GL_CHECK_ERROR;
903  m_isDirty = false;
904  }
905 }
906 
907 template <typename CoreGeometry>
909  const std::string& meshAttribName,
910  const std::string& shaderAttribName ) {
911 
912  m_translationTable.replace( meshAttribName, shaderAttribName );
913 }
914 
916 
917 template <typename T>
918 IndexedGeometry<T>::IndexedGeometry( const std::string& name,
919  typename base::CoreGeometry&& geom,
920  typename base::MeshRenderMode renderMode ) :
921  base( name, renderMode ) {
922  loadGeometry( std::move( geom ) );
923 }
924 
925 template <typename T>
927  setIndicesDirty();
928  base::loadGeometry_common( std::move( mesh ) );
929 
930  // indices
931  base::m_mesh.attach( IndicesObserver( this ) );
932 }
933 
934 template <typename T>
936  if ( !m_indices ) {
937  m_indices = globjects::Buffer::create();
938  m_indicesDirty = true;
939  }
940  if ( m_indicesDirty ) {
942  // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW );
943  m_numElements =
944  base::m_mesh.getIndices().size() * base::CoreGeometry::IndexType::RowsAtCompileTime;
945 
946  m_indices->setData(
947  static_cast<gl::GLsizeiptr>( base::m_mesh.getIndices().size() *
948  sizeof( typename base::CoreGeometry::IndexType ) ),
949  base::m_mesh.getIndices().data(),
950  GL_STATIC_DRAW );
951  m_indicesDirty = false;
952  }
953  if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
954  base::m_vao->bind();
955  base::m_vao->bindElementBuffer( m_indices.get() );
956  base::m_vao->unbind();
957 }
958 
959 template <typename T>
961  if ( base::m_vao ) {
962  GL_CHECK_ERROR;
963  base::m_vao->bind();
964  base::autoVertexAttribPointer( prog );
965  GL_CHECK_ERROR;
966  base::m_vao->drawElements( static_cast<GLenum>( base::m_renderMode ),
967  GLsizei( m_numElements ),
968  GL_UNSIGNED_INT,
969  nullptr );
970  GL_CHECK_ERROR;
971  base::m_vao->unbind();
972  GL_CHECK_ERROR;
973  }
974 }
975 
977 
978 template <typename T>
979 MultiIndexedGeometry<T>::MultiIndexedGeometry( const std::string& name,
980  typename base::CoreGeometry&& geom,
981  typename base::MeshRenderMode renderMode ) :
982  base( name, renderMode ) {
983  loadGeometry( std::move( geom ) );
984 }
985 
986 template <typename T>
988  m_indices.clear();
989 
990  base::loadGeometry_common( std::move( mesh ) );
991  CORE_ASSERT( false, "not implemented yet" );
992 
994  // indices
995  // base::m_mesh.attach( IndicesObserver( this ) );
996 }
997 
998 template <typename T>
1000  CORE_ASSERT( false, "not implemented yet" );
1001  // if ( !m_indices )
1002  // {
1003  // m_indices = globjects::Buffer::create();
1004  // m_indicesDirty = true;
1005  // }
1006  // if ( m_indicesDirty )
1007  // {
1008  // /// this one do not work since m_indices is not a std::vector
1009  // // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW );
1010  // m_numElements =
1011  // base::m_mesh.getIndices().size() *
1012  // base::CoreGeometry::IndexType::RowsAtCompileTime;
1013  //
1014  // m_indices->setData(
1015  // static_cast<gl::GLsizeiptr>( base::m_mesh.getIndices().size() *
1016  // sizeof( typename base::CoreGeometry::IndexType ) ),
1017  // base::m_mesh.getIndices().data(),
1018  // GL_STATIC_DRAW );
1019  // m_indicesDirty = false;
1020  // }
1021  // if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
1022  // base::m_vao->bind();
1023  // base::m_vao->bindElementBuffer( m_indices.get() );
1024  // base::m_vao->unbind();
1026 }
1027 
1028 template <typename T>
1030  CORE_ASSERT( false, "not implemented yet" );
1031  // if ( base::m_vao )
1032  // {
1033  // GL_CHECK_ERROR;
1034  // base::m_vao->bind();
1035  // base::autoVertexAttribPointer( prog );
1036  // GL_CHECK_ERROR;
1037  // base::m_vao->drawElements( static_cast<GLenum>( base::m_renderMode ),
1038  // GLsizei( m_numElements ),
1039  // GL_UNSIGNED_INT,
1040  // nullptr );
1041  // GL_CHECK_ERROR;
1042  // base::m_vao->unbind();
1043  // GL_CHECK_ERROR;
1044  // }
1046 }
1047 
1049 
1050 PointCloud::PointCloud( const std::string& name,
1051  typename base::CoreGeometry&& geom,
1052  typename base::MeshRenderMode renderMode ) :
1053  base( name, renderMode ) {
1054  loadGeometry( std::move( geom ) );
1055 }
1056 
1057 PointCloud::PointCloud( const std::string& name, typename base::MeshRenderMode renderMode ) :
1058  base( name, renderMode ) {}
1059 
1061 
1062 LineMesh::LineMesh( const std::string& name,
1063  typename base::CoreGeometry&& geom,
1064  typename base::MeshRenderMode renderMode ) :
1065  base( name, std::move( geom ), renderMode ) {}
1066 
1067 LineMesh::LineMesh( const std::string& name, typename base::MeshRenderMode renderMode ) :
1068  base( name, renderMode ) {}
1069 
1071 
1072 template <typename T>
1073 size_t GeneralMesh<T>::getNumFaces() const {
1074  return this->getCoreGeometry().getIndices().size();
1075 }
1076 
1077 template <typename T>
1079  if ( !this->m_indices ) {
1080  this->m_indices = globjects::Buffer::create();
1081  this->m_indicesDirty = true;
1082  }
1083  if ( this->m_indicesDirty ) {
1084  triangulate();
1086  // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW );
1087  this->m_numElements = m_triangleIndices.size() * GeneralMesh::IndexType::RowsAtCompileTime;
1088 
1089  this->m_indices->setData( static_cast<gl::GLsizeiptr>( m_triangleIndices.size() *
1090  sizeof( GeneralMesh::IndexType ) ),
1091  m_triangleIndices.data(),
1092  GL_STATIC_DRAW );
1093  this->m_indicesDirty = false;
1094  }
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();
1099 }
1100 
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 ); }
1107  else {
1109  int minus { int( face.size() ) - 1 };
1110  int plus { 0 };
1111  while ( plus + 1 < minus ) {
1112  if ( ( plus - minus ) % 2 ) {
1113  m_triangleIndices.emplace_back( face[plus], face[plus + 1], face[minus] );
1114  ++plus;
1115  }
1116  else {
1117  m_triangleIndices.emplace_back( face[minus], face[plus], face[minus - 1] );
1118  --minus;
1119  }
1120  }
1121  }
1122  }
1123 }
1124 
1125 template <>
1126 inline void GeneralMesh<Core::Geometry::QuadMesh>::triangulate() {
1127  m_triangleIndices.clear();
1128  m_triangleIndices.reserve( 2 * this->m_mesh.getIndices().size() );
1129  // assume quads are convex
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] );
1133  }
1134 }
1135 
1136 } // namespace Data
1137 } // namespace Engine
1138 } // namespace Ra
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.
Definition: Attribs.hpp:449
An attrib handle basically store an Index and a name.
Definition: Attribs.hpp:146
The AttribManager provides attributes management by handles.
Definition: Attribs.hpp:204
virtual const void * dataPtr() const =0
std::set< SemanticName > SemanticNameCollection
Store in set to allow for logarithmic search.
int attach(Observer observer)
Definition: Observable.hpp:54
MeshRenderMode getRenderMode() const
Get the render mode.
Definition: Mesh.hpp:548
void updatePickingRenderMode()
Update the picking render mode according to the object render mode.
Definition: Mesh.cpp:84
void setRenderMode(MeshRenderMode mode)
Set the render mode.
Definition: Mesh.hpp:543
Template class to manage the Displayable aspect of a Core Geomertry, such as TriangleMesh.
Definition: Mesh.hpp:229
void updateGL() override
Update (i.e. send to GPU) the buffers marked as dirty.
Definition: Mesh.hpp:841
void addAttribObserver(const std::string &name)
Definition: Mesh.hpp:727
void autoVertexAttribPointer(const ShaderProgram *prog)
assume m_vao is bound.
Definition: Mesh.hpp:750
void setAttribNameCorrespondance(const std::string &meshAttribName, const std::string &shaderAttribName)
Definition: Mesh.hpp:908
virtual void loadGeometry(CoreGeometry &&mesh)
Definition: Mesh.hpp:836
Ra::Core::Utils::AttribHandle< A > addAttrib(const std::string &name, const typename Core::VectorArray< A > &data)
Helper function that calls Ra::Core::CoreGeometry::addAttrib()
Definition: Mesh.hpp:825
const Core::Geometry::AbstractGeometry & getAbstractGeometry() const override
Definition: Mesh.hpp:690
const std::string & getName() const
Returns the name of the mesh.
void updateGL_specific_impl() override
Definition: Mesh.hpp:1078
void autoVertexAttribPointer(const ShaderProgram *prog)
assume m_vao is bound.
Definition: Mesh.hpp:629
An engine mesh owning CoreGeometry, with indices.
Definition: Mesh.hpp:335
void loadGeometry(T &&mesh) override
Definition: Mesh.hpp:926
void updateGL_specific_impl() override
Definition: Mesh.hpp:935
void render(const ShaderProgram *prog) override
Definition: Mesh.hpp:960
LineMesh, own a Core::Geometry::LineMesh.
Definition: Mesh.hpp:395
Mesh, own a Core::Geometry::TriangleMesh.
Definition: Mesh.hpp:414
void updateGL_specific_impl() override
Definition: Mesh.hpp:999
void render(const ShaderProgram *prog) override
Definition: Mesh.hpp:1029
void loadGeometry(T &&mesh) override
Definition: Mesh.hpp:987
A PointCloud without indices.
Definition: Mesh.hpp:311
IndicesObserver(VaoIndices *displayable)
not tested
Definition: Mesh.hpp:184
Concept class to ensure consistent naming of VaoIndices accross derived classes.
Definition: Mesh.hpp:174
void setIndicesDirty()
Tag the indices as dirty, asking for a update to gpu.
Definition: Mesh.hpp:554
Definition: Cage.cpp:3
Index layer for line mesh.