Radium Engine  1.5.20
Loading...
Searching...
No Matches
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
26namespace Ra {
27namespace Engine {
28namespace Data {
29class ShaderProgram;
30
31using namespace Ra::Core::Utils;
32
35class RA_ENGINE_API Vao
36{
40 std::vector<bool> m_dataDirty;
41 std::map<std::string, int> m_handleToBuffer;
42};
43
51class 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 );
79 void operator=( const AttribArrayDisplayable& rhs ) = delete;
80
82
83 using Displayable::getName;
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:
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]
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
165
169 bool m_isDirty { false };
170};
171
173class 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
203template <typename I>
205{
206 using IndexType = I;
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
227template <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
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>
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
310class 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
333template <typename T>
335{
336 public:
338 using CoreGeometryDisplayable<T>::CoreGeometryDisplayable;
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
354template <typename T>
356{
357 public:
359 using CoreGeometryDisplayable<T>::CoreGeometryDisplayable;
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
374
376 struct RA_CORE_API KeyHash { std::size_t operator()( const LayerKeyType& k ) const {
377 // Mix semantic collection into a single identifier string
378 std::ostringstream stream;
379 std::copy( k.first.begin(), k.first.end(), std::ostream_iterator<std::string>( stream, "" ) );
380 std::string result = stream.str();
381 std::sort( result.begin(), result.end() );
382
383 // Combine with layer name hash
384 return std::hash<std::string> {}( result ) ^ ( std::hash<std::string> {}( k.second ) << 1 );
385}
386}; // namespace Data
388}; // namespace Engine
389
391class RA_ENGINE_API LineMesh : public IndexedGeometry<Core::Geometry::LineMesh>
392{
394
395 public:
396 using base::IndexedGeometry;
397 inline explicit LineMesh(
398 const std::string& name,
399 typename base::CoreGeometry&& geom,
400 typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_LINES );
401 inline explicit LineMesh(
402 const std::string& name,
403 typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_LINES );
404
405 protected:
406 private:
407};
408
410class RA_ENGINE_API Mesh : public IndexedGeometry<Core::Geometry::TriangleMesh>
411{
413
414 public:
415 using base::IndexedGeometry;
416 size_t getNumFaces() const override;
417
425 using base::loadGeometry;
426 [[deprecated]] void loadGeometry( const Core::Vector3Array& vertices,
427 const std::vector<uint>& indices );
428
429 protected:
430 private:
431};
432
437template <typename T>
438class RA_ENGINE_API GeneralMesh : public IndexedGeometry<T>
439{
440 using base = IndexedGeometry<T>;
441 using IndexType = Core::Vector3ui;
442
443 public:
444 using base::IndexedGeometry;
445 inline size_t getNumFaces() const override;
446
447 protected:
448 inline void updateGL_specific_impl() override;
449
450 private:
451 inline void triangulate();
452 Core::AlignedStdVector<IndexType> m_triangleIndices;
453};
454
457
460template <typename CoreMeshType>
462 CoreMeshType mesh;
463 typename CoreMeshType::IndexContainerType indices;
464
465 if ( !data->isLineMesh() ) {
466 auto& geo = data->getGeometry();
467 const auto& [layerKeyType, layerBase] =
468 geo.getFirstLayerOccurrence( mesh.getLayerKey().first );
469 const auto& layer = static_cast<
471 layerBase );
472 const auto& faces = layer.collection();
473 indices.reserve( faces.size() );
474 std::copy( faces.begin(), faces.end(), std::back_inserter( indices ) );
475 }
476#if 0
477 // TODO manage line meshes in a "usual" way, i.e. as an indexed geometry with specific
478 // rendering properties (i.e. shader, as it is the case for point clouds)
479 // Create a degenerated triangle to handle edges case.
480 else {
481 const auto& edges = ... access the LineIndexLayer
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 ) } );
486 } );
487 }
488#endif
489
490 mesh.setIndices( std::move( indices ) );
491
492 // This copy only "usual" attributes. See Core::Geometry::AttribManager::copyAllAttributes
493 mesh.vertexAttribs().copyAllAttributes( data->getGeometry().vertexAttribs() );
494
495 return mesh;
496}
497
499namespace RenderMeshType {
500template <class CoreMeshT>
501struct getType {};
502
503template <>
504struct getType<Ra::Core::Geometry::LineMesh> {
505 using Type = Ra::Engine::Data::LineMesh;
506};
507
508template <>
509struct getType<Ra::Core::Geometry::TriangleMesh> {
510 using Type = Ra::Engine::Data::Mesh;
511};
512
513template <>
514struct getType<Ra::Core::Geometry::QuadMesh> {
515 using Type = Ra::Engine::Data::QuadMesh;
516};
517
518template <>
519struct getType<Ra::Core::Geometry::PolyMesh> {
520 using Type = Ra::Engine::Data::PolyMesh;
521};
522} // namespace RenderMeshType
523
525template <typename CoreMeshType>
526typename RenderMeshType::getType<CoreMeshType>::Type*
528 using MeshType = typename RenderMeshType::getType<CoreMeshType>::Type;
529
530 auto mesh = createCoreMeshFromGeometryData<CoreMeshType>( data );
531
532 MeshType* ret = new MeshType { name };
533 ret->loadGeometry( std::move( mesh ) );
534
535 return ret;
536}
537
539
540void AttribArrayDisplayable::setRenderMode( MeshRenderMode mode ) {
541 m_renderMode = mode;
542 updatePickingRenderMode();
543}
544
545AttribArrayDisplayable::MeshRenderMode AttribArrayDisplayable::getRenderMode() const {
546 return m_renderMode;
547}
548
550
551void VaoIndices::setIndicesDirty() {
552 m_indicesDirty = true;
553}
554
556
557template <typename I>
558template <typename T>
560 const std::string& name,
561 const typename Ra::Core::Utils::Attrib<T>::Container& data ) {
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 );
567 m_isDirty = true;
568}
569
570template <typename I>
571template <typename T>
572void IndexedAttribArrayDisplayable<I>::addAttrib(
573 const std::string& name,
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 );
580 m_isDirty = true;
581}
582
583template <typename I>
584void IndexedAttribArrayDisplayable<I>::updateGL() {
585 if ( m_isDirty ) {
586 // Check that our dirty bits are consistent.
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" );
590
591 if ( !m_indices ) {
592 m_indices = globjects::Buffer::create();
593 m_indicesDirty = true;
594 }
595 if ( m_indicesDirty ) {
596 m_indices->setData(
597 static_cast<gl::GLsizeiptr>( m_cpu_indices.size() * sizeof( IndexType ) ),
598 m_cpu_indices.data(),
599 GL_STATIC_DRAW );
600 m_indicesDirty = false;
601 }
602
603 m_numElements = m_cpu_indices.size();
604
605 if ( !m_vao ) { m_vao = globjects::VertexArray::create(); }
606 m_vao->bind();
607 m_vao->bindElementBuffer( m_indices.get() );
608 m_vao->unbind();
609
610 auto func = [this]( Ra::Core::Utils::AttribBase* b ) {
611 auto idx = m_handleToBuffer[b->getName()];
612
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;
617 }
618 };
619 m_attribManager.for_each_attrib( func );
620 GL_CHECK_ERROR;
621 m_isDirty = false;
622 }
623}
624
625template <typename I>
627
628 auto glprog = prog->getProgramObject();
629 gl::GLint attribCount = glprog->get( GL_ACTIVE_ATTRIBUTES );
630
631 for ( GLint idx = 0; idx < attribCount; ++idx ) {
632 const gl::GLsizei bufSize = 256;
633 gl::GLchar name[bufSize];
634 gl::GLsizei length;
635 gl::GLint size;
636 gl::GLenum type;
637 glprog->getActiveAttrib( idx, bufSize, &length, &size, &type, name );
638 auto loc = glprog->getAttributeLocation( name );
639
640 auto attribName = name; // m_translationTableShaderToMesh[name];
641 auto attrib = m_attribManager.getAttribBase( attribName );
642
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(),
650 0,
651 attrib->getNumberOfComponents() * sizeof( float ) );
652#else
653
654 binding->setBuffer(
655 m_vbos[m_handleToBuffer[attribName]].get(), 0, attrib->getStride() );
656#endif
657 binding->setFormat( attrib->getNumberOfComponents(), GL_SCALAR );
658 }
659 else { m_vao->disable( loc ); }
660 }
661}
662
663template <typename I>
665 if ( m_vao ) {
666 autoVertexAttribPointer( prog );
667 m_vao->bind();
668 m_vao->drawElements( static_cast<GLenum>( m_renderMode ),
669 GLsizei( m_numElements ),
670 GL_UNSIGNED_INT,
671 nullptr );
672 m_vao->unbind();
673 }
674}
675
677
678template <typename CoreGeometry>
679CoreGeometryDisplayable<CoreGeometry>::CoreGeometryDisplayable( const std::string& name,
680 MeshRenderMode renderMode ) :
681 base( name, renderMode ) {
682 setupCoreMeshObservers();
683}
684
685template <typename CoreGeometry>
690
691template <typename CoreGeometry>
693 return m_mesh;
694}
695
696template <typename CoreGeometry>
698CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry() const {
699 return m_mesh;
700}
701
702template <typename CoreGeometry>
704CoreGeometryDisplayable<CoreGeometry>::getAttribArrayGeometry() {
705 return m_mesh;
706}
707
708template <typename CoreGeometry>
709const CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry() const {
710 return m_mesh;
711}
712
713template <typename CoreGeometry>
714CoreGeometry& CoreGeometryDisplayable<CoreGeometry>::getCoreGeometry() {
715 return m_mesh;
716}
717
718template <typename CoreGeometry>
719void CoreGeometryDisplayable<CoreGeometry>::addToTranslationTable( const std::string& name ) {
720 m_translationTable.insert( name, name );
721}
722
723template <typename CoreGeometry>
725 // this observer is called each time an attrib is added or removed from m_mesh
726 auto attrib = m_mesh.getAttribBase( name );
727 // if attrib not nullptr, then it's an attrib add, so attach an observer to it
728
729 if ( attrib ) {
730 auto itr = m_handleToBuffer.find( name );
731 if ( itr == m_handleToBuffer.end() ) {
732 m_handleToBuffer[name] = m_dataDirty.size();
733
734 addToTranslationTable( name );
735
736 m_dataDirty.push_back( true );
737 m_vbos.emplace_back( nullptr );
738 }
739 auto idx = m_handleToBuffer[name];
740 attrib->attach( AttribObserver( this, idx ) );
741 }
742 // else it's an attrib remove, do nothing, cleanup will be done in updateGL()
743 else {}
744}
745
746template <typename CoreGeometry>
748
749 auto glprog = prog->getProgramObject();
750 gl::GLint attribCount = glprog->get( GL_ACTIVE_ATTRIBUTES );
751
752 for ( GLint idx = 0; idx < attribCount; ++idx ) {
753 const gl::GLsizei bufSize = 256;
754 gl::GLchar name[bufSize];
755 gl::GLsizei length;
756 gl::GLint size;
757 gl::GLenum type;
758 glprog->getActiveAttrib( idx, bufSize, &length, &size, &type, name );
759 auto loc = glprog->getAttributeLocation( name );
760
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(),
772 0,
773 attrib->getNumberOfComponents() * sizeof( float ) );
774#else
775
776 binding->setBuffer(
777 m_vbos[m_handleToBuffer[attribName]].get(), 0, attrib->getStride() );
778#endif
779 binding->setFormat( attrib->getNumberOfComponents(), GL_SCALAR );
780 }
781 else { m_vao->disable( loc ); }
782 }
783 else { m_vao->disable( loc ); }
784 }
785}
786
787template <typename T>
789 m_mesh = std::move( mesh );
790 setupCoreMeshObservers();
791}
792
793template <typename T>
794
795void CoreGeometryDisplayable<T>::setupCoreMeshObservers() {
796 int idx = 0;
797 m_dataDirty.resize( m_mesh.vertexAttribs().getNumAttribs() );
798 m_vbos.resize( m_mesh.vertexAttribs().getNumAttribs() );
799 // here capture ref to idx to propagate idx incrementation
800 m_mesh.vertexAttribs().for_each_attrib( [&idx, this]( Ra::Core::Utils::AttribBase* b ) {
801 auto name = b->getName();
802 m_handleToBuffer[name] = idx;
803 m_dataDirty[idx] = true;
804
805 // create a identity translation if name is not already translated.
806 addToTranslationTable( name );
807
808 b->attach( AttribObserver( this, idx ) );
809 ++idx;
810 } );
811
812 // add an observer on attrib manipulation.
813 m_mesh.vertexAttribs().attachMember(
815 m_isDirty = true;
816}
817
819template <typename CoreGeometry>
820template <typename A>
823 const typename Core::VectorArray<A>& data ) {
824 return m_mesh.addAttrib( name, data );
825}
826
827template <typename CoreGeometry>
829 return m_mesh.vertices().size();
830}
831
832template <typename CoreGeometry>
834 CORE_ASSERT( false, "must be specialized" );
835}
836
837template <typename CoreGeometry>
839 if ( m_isDirty ) {
840 // Check that our dirty bits are consistent.
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." );
845
846 updateGL_specific_impl();
847#ifdef CORE_USE_DOUBLE
848 // need convserion
849 auto func = [this]( Ra::Core::Utils::AttribBase* b ) {
850 auto idx = m_handleToBuffer[b->getName()];
851
852 if ( m_dataDirty[idx] ) {
853 if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
854
855 auto stride = b->getStride();
856 auto eltSize = b->getNumberOfComponents();
857 auto size = b->getSize();
858 auto data = std::make_unique<float[]>( size * eltSize );
859 const void* ptr = b->dataPtr();
860 const char* cptr = reinterpret_cast<const char*>( ptr );
861
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];
866 }
867 }
868
869 m_vbos[idx]->setData(
870 size * eltSize * sizeof( float ), data.get(), GL_DYNAMIC_DRAW );
871
872 m_dataDirty[idx] = false;
873 }
874 };
875
876#else
877 auto func = [this]( Ra::Core::Utils::AttribBase* b ) {
878 auto idx = m_handleToBuffer[b->getName()];
879
880 if ( m_dataDirty[idx] ) {
881 if ( !m_vbos[idx] ) { m_vbos[idx] = globjects::Buffer::create(); }
882 m_vbos[idx]->setData( b->getBufferSize(), b->dataPtr(), GL_DYNAMIC_DRAW );
883 m_dataDirty[idx] = false;
884 }
885 };
886#endif
887 m_mesh.vertexAttribs().for_each_attrib( func );
888
889 // cleanup removed attrib
890 for ( auto buffer : m_handleToBuffer ) {
891 // do not remove name from handleToBuffer to keep index ...
892 // we could also update handleToBuffer, m_vbos, m_dataDirty
893 if ( !m_mesh.hasAttrib( buffer.first ) && m_vbos[buffer.second] ) {
894 m_vbos[buffer.second].reset( nullptr );
895 m_dataDirty[buffer.second] = false;
896 }
897 }
898
899 GL_CHECK_ERROR;
900 m_isDirty = false;
901 }
902}
903
904template <typename CoreGeometry>
906 const std::string& meshAttribName,
907 const std::string& shaderAttribName ) {
908
909 m_translationTable.replace( meshAttribName, shaderAttribName );
910}
911
913
914template <typename T>
916 typename base::CoreGeometry&& geom,
917 typename base::MeshRenderMode renderMode ) :
918 base( name, renderMode ) {
919 loadGeometry( std::move( geom ) );
920}
921
922template <typename T>
924 setIndicesDirty();
925 base::loadGeometry_common( std::move( mesh ) );
926
927 // indices
928 base::m_mesh.attach( IndicesObserver( this ) );
929}
930
931template <typename T>
933 if ( !m_indices ) {
934 m_indices = globjects::Buffer::create();
935 m_indicesDirty = true;
936 }
937 if ( m_indicesDirty ) {
939 // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW );
940 m_numElements =
941 base::m_mesh.getIndices().size() * base::CoreGeometry::IndexType::RowsAtCompileTime;
942
943 m_indices->setData(
944 static_cast<gl::GLsizeiptr>( base::m_mesh.getIndices().size() *
945 sizeof( typename base::CoreGeometry::IndexType ) ),
946 base::m_mesh.getIndices().data(),
947 GL_STATIC_DRAW );
948 m_indicesDirty = false;
949 }
950 if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
951 base::m_vao->bind();
952 base::m_vao->bindElementBuffer( m_indices.get() );
953 base::m_vao->unbind();
954}
955
956template <typename T>
958 if ( base::m_vao ) {
959 GL_CHECK_ERROR;
960 base::m_vao->bind();
961 base::autoVertexAttribPointer( prog );
962 GL_CHECK_ERROR;
963 base::m_vao->drawElements( static_cast<GLenum>( base::m_renderMode ),
964 GLsizei( m_numElements ),
965 GL_UNSIGNED_INT,
966 nullptr );
967 GL_CHECK_ERROR;
968 base::m_vao->unbind();
969 GL_CHECK_ERROR;
970 }
971}
972
974
975template <typename T>
977 typename base::CoreGeometry&& geom,
978 typename base::MeshRenderMode renderMode ) :
979 base( name, renderMode ) {
980 loadGeometry( std::move( geom ) );
981}
982
983template <typename T>
985 m_indices.clear();
986
987 base::loadGeometry_common( std::move( mesh ) );
988 CORE_ASSERT( false, "not implemented yet" );
989
991 // indices
992 // base::m_mesh.attach( IndicesObserver( this ) );
993}
994
995template <typename T>
997 CORE_ASSERT( false, "not implemented yet" );
998 // if ( !m_indices )
999 // {
1000 // m_indices = globjects::Buffer::create();
1001 // m_indicesDirty = true;
1002 // }
1003 // if ( m_indicesDirty )
1004 // {
1005 // /// this one do not work since m_indices is not a std::vector
1006 // // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW );
1007 // m_numElements =
1008 // base::m_mesh.getIndices().size() *
1009 // base::CoreGeometry::IndexType::RowsAtCompileTime;
1010 //
1011 // m_indices->setData(
1012 // static_cast<gl::GLsizeiptr>( base::m_mesh.getIndices().size() *
1013 // sizeof( typename base::CoreGeometry::IndexType ) ),
1014 // base::m_mesh.getIndices().data(),
1015 // GL_STATIC_DRAW );
1016 // m_indicesDirty = false;
1017 // }
1018 // if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
1019 // base::m_vao->bind();
1020 // base::m_vao->bindElementBuffer( m_indices.get() );
1021 // base::m_vao->unbind();
1023}
1024
1025template <typename T>
1027 CORE_ASSERT( false, "not implemented yet" );
1028 // if ( base::m_vao )
1029 // {
1030 // GL_CHECK_ERROR;
1031 // base::m_vao->bind();
1032 // base::autoVertexAttribPointer( prog );
1033 // GL_CHECK_ERROR;
1034 // base::m_vao->drawElements( static_cast<GLenum>( base::m_renderMode ),
1035 // GLsizei( m_numElements ),
1036 // GL_UNSIGNED_INT,
1037 // nullptr );
1038 // GL_CHECK_ERROR;
1039 // base::m_vao->unbind();
1040 // GL_CHECK_ERROR;
1041 // }
1043}
1044
1046
1047PointCloud::PointCloud( const std::string& name,
1048 typename base::CoreGeometry&& geom,
1049 typename base::MeshRenderMode renderMode ) :
1050 base( name, renderMode ) {
1051 loadGeometry( std::move( geom ) );
1052}
1053
1054PointCloud::PointCloud( const std::string& name, typename base::MeshRenderMode renderMode ) :
1055 base( name, renderMode ) {}
1056
1058
1059LineMesh::LineMesh( const std::string& name,
1060 typename base::CoreGeometry&& geom,
1061 typename base::MeshRenderMode renderMode ) :
1062 base( name, std::move( geom ), renderMode ) {}
1063
1064LineMesh::LineMesh( const std::string& name, typename base::MeshRenderMode renderMode ) :
1065 base( name, renderMode ) {}
1066
1068
1069template <typename T>
1070size_t GeneralMesh<T>::getNumFaces() const {
1071 return this->getCoreGeometry().getIndices().size();
1072}
1073
1074template <typename T>
1076 if ( !this->m_indices ) {
1077 this->m_indices = globjects::Buffer::create();
1078 this->m_indicesDirty = true;
1079 }
1080 if ( this->m_indicesDirty ) {
1081 triangulate();
1083 // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW );
1084 this->m_numElements = m_triangleIndices.size() * GeneralMesh::IndexType::RowsAtCompileTime;
1085
1086 this->m_indices->setData( static_cast<gl::GLsizeiptr>( m_triangleIndices.size() *
1087 sizeof( GeneralMesh::IndexType ) ),
1088 m_triangleIndices.data(),
1089 GL_STATIC_DRAW );
1090 this->m_indicesDirty = false;
1091 }
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();
1096}
1097
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 ); }
1104 else {
1106 int minus { int( face.size() ) - 1 };
1107 int plus { 0 };
1108 while ( plus + 1 < minus ) {
1109 if ( ( plus - minus ) % 2 ) {
1110 m_triangleIndices.emplace_back( face[plus], face[plus + 1], face[minus] );
1111 ++plus;
1112 }
1113 else {
1114 m_triangleIndices.emplace_back( face[minus], face[plus], face[minus - 1] );
1115 --minus;
1116 }
1117 }
1118 }
1119 }
1120}
1121
1122template <>
1123inline void GeneralMesh<Core::Geometry::QuadMesh>::triangulate() {
1124 m_triangleIndices.clear();
1125 m_triangleIndices.reserve( 2 * this->m_mesh.getIndices().size() );
1126 // assume quads are convex
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] );
1130 }
1131}
1132
1133} // namespace Ra
1134} // namespace Engine
1135} // namespace Ra
T back_inserter(T... args)
T begin(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.
Definition Attribs.hpp:448
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
Bijective association between two sets {keys} and {values} having the same cardinality....
virtual const void * dataPtr() const =0
std::set< SemanticName > SemanticNameCollection
Store in set to allow for logarithmic search.
int attach(Observer observer)
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:838
BijectiveAssociation< std::string, std::string > m_translationTable
Definition Mesh.hpp:304
void addAttribObserver(const std::string &name)
Definition Mesh.hpp:724
void autoVertexAttribPointer(const ShaderProgram *prog)
assume m_vao is bound.
Definition Mesh.hpp:747
void setAttribNameCorrespondance(const std::string &meshAttribName, const std::string &shaderAttribName)
Definition Mesh.hpp:905
virtual void loadGeometry(CoreGeometry &&mesh)
Definition Mesh.hpp:833
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:822
const Core::Geometry::AbstractGeometry & getAbstractGeometry() const override
Definition Mesh.hpp:687
void updateGL_specific_impl() override
Definition Mesh.hpp:1075
void autoVertexAttribPointer(const ShaderProgram *prog)
assume m_vao is bound.
Definition Mesh.hpp:626
An engine mesh owning CoreGeometry, with indices.
Definition Mesh.hpp:335
void loadGeometry(T &&mesh) override
Definition Mesh.hpp:923
void updateGL_specific_impl() override
Definition Mesh.hpp:932
void render(const ShaderProgram *prog) override
Definition Mesh.hpp:957
LineMesh, own a Core::Geometry::LineMesh.
Definition Mesh.hpp:392
Mesh, own a Core::Geometry::TriangleMesh.
Definition Mesh.hpp:411
void render(const ShaderProgram *prog) override
Definition Mesh.hpp:1026
void loadGeometry(T &&mesh) override
Definition Mesh.hpp:984
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
T copy(T... args)
T end(T... args)
T move(T... args)
CoreMeshType createCoreMeshFromGeometryData(const Ra::Core::Asset::GeometryData *data)
Definition Mesh.hpp:461
RenderMeshType::getType< CoreMeshType >::Type * createMeshFromGeometryData(const std::string &name, const Ra::Core::Asset::GeometryData *data)
create Mesh, PolyMesh Engine::Data::*Mesh * from GeometryData
Definition Mesh.hpp:527
hepler function to manage enum as underlying types in VariableSet
Definition Cage.cpp:3
STL namespace.
T reserve(T... args)
T sort(T... args)
T str(T... args)
T transform(T... args)