Radium Engine  1.5.0
Mesh.cpp
1 #include <Engine/Data/Mesh.hpp>
2 
3 #include <numeric>
4 
5 #include <Core/Utils/Attribs.hpp>
6 #include <Core/Utils/Log.hpp>
7 #include <Engine/Data/ShaderProgram.hpp>
8 #include <Engine/OpenGL.hpp>
9 
10 #include <globjects/Buffer.h>
11 #include <globjects/VertexArray.h>
12 
13 namespace Ra {
14 namespace Engine {
15 namespace Data {
16 using namespace Ra::Core::Utils;
17 
18 // Dirty is initializes as false so that we do not create the vao while
19 // we have no data to send to the gpu.
20 AttribArrayDisplayable::AttribArrayDisplayable( const std::string& name,
21  MeshRenderMode renderMode ) :
22  Displayable( name ), m_renderMode { renderMode } {
23  CORE_ASSERT( m_renderMode == RM_POINTS || m_renderMode == RM_LINES ||
24  m_renderMode == RM_LINE_LOOP || m_renderMode == RM_LINE_STRIP ||
25  m_renderMode == RM_TRIANGLES || m_renderMode == RM_TRIANGLE_STRIP ||
26  m_renderMode == RM_TRIANGLE_FAN || m_renderMode == RM_LINES_ADJACENCY ||
27  m_renderMode == RM_LINE_STRIP_ADJACENCY,
28  "Unsupported render mode" );
29 
30  updatePickingRenderMode();
31 }
32 
33 size_t Mesh::getNumFaces() const {
35  switch ( getRenderMode() ) {
36  case MeshRenderMode::RM_TRIANGLE_STRIP:
37  [[fallthrough]];
38  case MeshRenderMode::RM_TRIANGLE_FAN:
39  return ( getCoreGeometry().getIndices().size() - 1 ) * 3 + 1;
40  case MeshRenderMode::RM_TRIANGLES:
41  return getCoreGeometry().getIndices().size();
42  default:
43  return size_t( 0 );
44  }
45 }
46 
47 void Mesh::loadGeometry( const Core::Vector3Array& vertices, const std::vector<uint>& indices ) {
48  // Do not remove this function to force everyone to use TriangleMesh.
49  // ... because we have some line meshes as well...
51  Core::Geometry::TriangleMesh mesh;
52 
53  auto nIdx = indices.size();
54 
55  if ( indices.empty() ) {
56  m_numElements = vertices.size();
57  setRenderMode( RM_POINTS );
58  }
59  else
60  m_numElements = nIdx;
61  mesh.setVertices( vertices );
62 
63  // Check that when loading a TriangleMesh we actually have triangles or lines.
64  CORE_ASSERT( m_renderMode != GL_TRIANGLES || nIdx % 3 == 0,
65  "There should be 3 indices per triangle " );
66  CORE_ASSERT( m_renderMode != GL_LINES || nIdx % 2 == 0, "There should be 2 indices per line" );
67  CORE_ASSERT( m_renderMode != GL_LINES_ADJACENCY || nIdx % 4 == 0,
68  "There should be 4 indices per line adjacency" );
70  for ( uint i = 0; i < indices.size(); i = i + 3 ) {
71  // We store all indices in order. This means that for lines we have
72  // (L00, L01, L10), (L11, L20, L21) etc. We fill the missing by wrapping around indices.
73  mindices.push_back( { indices[i], indices[( i + 1 ) % nIdx], indices[( i + 2 ) % nIdx] } );
74  }
75 
76  mesh.setIndices( std::move( mindices ) );
77  m_dataDirty.clear();
78  m_vbos.clear();
79 
81  loadGeometry( std::move( mesh ) );
82 }
83 
84 void AttribArrayDisplayable::updatePickingRenderMode() {
85  switch ( getRenderMode() ) {
86  case AttribArrayDisplayable::RM_POINTS: {
87  Displayable::m_pickingRenderMode = PKM_POINTS;
88  break;
89  }
90  case AttribArrayDisplayable::RM_LINES: // fall through
91  [[fallthrough]];
92  case AttribArrayDisplayable::RM_LINE_LOOP: // fall through
93  [[fallthrough]];
94  case AttribArrayDisplayable::RM_LINE_STRIP: {
95  Displayable::m_pickingRenderMode = PKM_LINES;
96  break;
97  }
98  case AttribArrayDisplayable::RM_LINES_ADJACENCY: // fall through
99  [[fallthrough]];
100  case AttribArrayDisplayable::RM_LINE_STRIP_ADJACENCY: {
101  Displayable::m_pickingRenderMode = PKM_LINE_ADJ;
102  break;
103  }
104  case AttribArrayDisplayable::RM_TRIANGLES:
105  [[fallthrough]];
106  case AttribArrayDisplayable::RM_TRIANGLE_STRIP:
107  [[fallthrough]];
108  case AttribArrayDisplayable::RM_TRIANGLE_FAN: {
109  Displayable::m_pickingRenderMode = PKM_TRI;
110  break;
111  }
112  default: {
113  Displayable::m_pickingRenderMode = NO_PICKING;
114  break;
115  }
116  }
117 }
118 
119 void AttribArrayDisplayable::setDirty( const std::string& name ) {
120  auto itr = m_handleToBuffer.find( name );
121  if ( itr == m_handleToBuffer.end() ) {
122  m_handleToBuffer[name] = m_dataDirty.size();
123  m_dataDirty.push_back( true );
124  m_vbos.emplace_back( nullptr );
125  }
126  else
127  m_dataDirty[itr->second] = true;
128 
129  m_isDirty = true;
130 }
131 
132 void AttribArrayDisplayable::setDirty( unsigned int index ) {
133  if ( index < m_dataDirty.size() ) {
134  m_dataDirty[index] = true;
135  m_isDirty = true;
136  }
137 }
138 
139 void AttribArrayDisplayable::setDirty( const Ra::Core::Geometry::MeshAttrib& type ) {
140  auto name = Core::Geometry::getAttribName( type );
141  auto itr = m_handleToBuffer.find( name );
142  if ( itr == m_handleToBuffer.end() ) {
143  m_handleToBuffer[name] = m_dataDirty.size();
144  m_dataDirty.push_back( true );
145  m_vbos.emplace_back( nullptr );
146  }
147  else
148  m_dataDirty[itr->second] = true;
149 
150  m_isDirty = true;
151 }
152 
153 Ra::Core::Utils::optional<gl::GLuint> AttribArrayDisplayable::getVaoHandle() {
154  if ( m_vao ) return m_vao->id();
155  return {};
156 }
157 Ra::Core::Utils::optional<gl::GLuint>
158 AttribArrayDisplayable::getVboHandle( const std::string& name ) {
159  auto idx = m_handleToBuffer.find( name );
160  if ( idx != m_handleToBuffer.end() && m_vbos[idx->second] ) return m_vbos[idx->second]->id();
161  return {};
162 }
163 
164 void PointCloud::render( const ShaderProgram* prog ) {
165  if ( m_vao ) {
166  autoVertexAttribPointer( prog );
167  m_vao->bind();
168  m_vao->drawArrays(
169  static_cast<GLenum>( m_renderMode ), 0, GLsizei( m_mesh.vertices().size() ) );
170  m_vao->unbind();
171  }
172 }
173 
174 void PointCloud::loadGeometry( Core::Geometry::PointCloud&& mesh ) {
175  loadGeometry_common( std::move( mesh ) );
176 }
177 
178 void PointCloud::updateGL_specific_impl() {
179  if ( !m_vao ) { m_vao = globjects::VertexArray::create(); }
180 }
181 
182 } // namespace Data
183 } // namespace Engine
184 } // namespace Ra
Definition: Cage.cpp:3