Skip to content

Commit 5a16cbe

Browse files
committed
[engine] Prepare API of GeometryDisplayable
1 parent 4af8f8e commit 5a16cbe

3 files changed

Lines changed: 246 additions & 114 deletions

File tree

src/Engine/Data/Mesh.cpp

Lines changed: 176 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ using namespace Ra::Core::Utils;
1919
// we have no data to send to the gpu.
2020
AttribArrayDisplayable::AttribArrayDisplayable( const std::string& name,
2121
MeshRenderMode renderMode ) :
22-
Displayable( name ), m_renderMode {renderMode} {
22+
Displayable( name ), m_renderMode { renderMode } {
2323
CORE_ASSERT( m_renderMode == RM_POINTS || m_renderMode == RM_LINES ||
2424
m_renderMode == RM_LINE_LOOP || m_renderMode == RM_LINE_STRIP ||
2525
m_renderMode == RM_TRIANGLES || m_renderMode == RM_TRIANGLE_STRIP ||
@@ -73,7 +73,7 @@ void Mesh::loadGeometry( const Core::Vector3Array& vertices, const std::vector<u
7373
{
7474
// We store all indices in order. This means that for lines we have
7575
// (L00, L01, L10), (L11, L20, L21) etc. We fill the missing by wrapping around indices.
76-
mindices.push_back( {indices[i], indices[( i + 1 ) % nIdx], indices[( i + 2 ) % nIdx]} );
76+
mindices.push_back( { indices[i], indices[( i + 1 ) % nIdx], indices[( i + 2 ) % nIdx] } );
7777
}
7878

7979
mesh.setIndices( std::move( mindices ) );
@@ -156,6 +156,180 @@ void AttribArrayDisplayable::setDirty( const AttribArrayDisplayable::MeshData& t
156156

157157
m_isDirty = true;
158158
}
159+
//////////////// MultiIndexedGeometry ///////////////////////////////
160+
161+
GeometryDisplayable::GeometryDisplayable( const std::string& name,
162+
typename Core::Geometry::MultiIndexedGeometry&& geom,
163+
typename base::MeshRenderMode renderMode ) :
164+
base( name, renderMode ), m_geom( std::move( geom ) ) {}
165+
166+
GeometryDisplayable::~GeometryDisplayable() {}
167+
168+
void GeometryDisplayable::loadGeometry( Core::Geometry::MultiIndexedGeometry&& mesh ) {
169+
m_geomLayers.clear();
170+
m_geom = std::move( mesh );
171+
setupCoreMeshObservers();
172+
}
173+
174+
void GeometryDisplayable::setupCoreMeshObservers() {
175+
int idx = 0;
176+
m_dataDirty.resize( m_geom.vertexAttribs().getNumAttribs() );
177+
m_vbos.resize( m_geom.vertexAttribs().getNumAttribs() );
178+
// here capture ref to idx to propagate idx incrementation
179+
m_geom.vertexAttribs().for_each_attrib( [&idx, this]( Ra::Core::Utils::AttribBase* b ) {
180+
auto name = b->getName();
181+
m_handleToBuffer[name] = idx;
182+
m_dataDirty[idx] = true;
183+
184+
// create a identity translation if name is not already translated.
185+
addToTranslationTable( name );
186+
187+
b->attach( AttribObserver( this, idx ) );
188+
++idx;
189+
} );
190+
191+
// add an observer on attrib manipulation.
192+
m_geom.vertexAttribs().attachMember( this, &GeometryDisplayable::addAttribObserver );
193+
m_isDirty = true;
194+
}
195+
196+
void GeometryDisplayable::addToTranslationTable( const std::string& name ) {
197+
auto it = m_translationTableMeshToShader.find( name );
198+
if ( it == m_translationTableMeshToShader.end() )
199+
{
200+
m_translationTableMeshToShader[name] = name;
201+
m_translationTableShaderToMesh[name] = name;
202+
}
203+
}
204+
205+
void GeometryDisplayable::addAttribObserver( const std::string& name ) {
206+
// this observer is called each time an attrib is added or removed from m_mesh
207+
auto attrib = m_geom.getAttribBase( name );
208+
// if attrib not nullptr, then it's an attrib add, so attach an observer to it
209+
210+
if ( attrib )
211+
{
212+
auto itr = m_handleToBuffer.find( name );
213+
if ( itr == m_handleToBuffer.end() )
214+
{
215+
m_handleToBuffer[name] = m_dataDirty.size();
216+
217+
addToTranslationTable( name );
218+
219+
m_dataDirty.push_back( true );
220+
m_vbos.emplace_back( nullptr );
221+
}
222+
auto idx = m_handleToBuffer[name];
223+
attrib->attach( AttribObserver( this, idx ) );
224+
}
225+
// else it's an attrib remove, do nothing, cleanup will be done in updateGL()
226+
else
227+
{}
228+
}
229+
230+
void GeometryDisplayable::setAttribNameCorrespondence( const std::string& meshAttribName,
231+
const std::string& shaderAttribName ) {
232+
233+
// clean previously set translation
234+
235+
auto it1 = std::find_if( m_translationTableShaderToMesh.begin(),
236+
m_translationTableShaderToMesh.end(),
237+
[&meshAttribName]( const TranslationTable::value_type& p ) {
238+
return p.second == meshAttribName;
239+
} );
240+
241+
if ( it1 != m_translationTableShaderToMesh.end() ) m_translationTableShaderToMesh.erase( it1 );
242+
243+
auto it2 = std::find_if( m_translationTableMeshToShader.begin(),
244+
m_translationTableMeshToShader.end(),
245+
[&shaderAttribName]( const TranslationTable::value_type& p ) {
246+
return p.second == shaderAttribName;
247+
} );
248+
249+
if ( it2 != m_translationTableMeshToShader.end() ) m_translationTableMeshToShader.erase( it2 );
250+
251+
m_translationTableShaderToMesh[shaderAttribName] = meshAttribName;
252+
m_translationTableMeshToShader[meshAttribName] = shaderAttribName;
253+
}
254+
255+
bool GeometryDisplayable::addRenderLayer( LayerKeyType key ) {
256+
if ( !m_geom.containsLayer( key ) ) return false;
257+
auto it = m_geomLayers.find( key );
258+
if ( it == m_geomLayers.end() ) return false;
259+
260+
VaoIndices* vao = new VaoIndices;
261+
auto& geomLayer = m_geom.getLayerWithLock( key );
262+
int observerId = geomLayer.attach( VaoIndices::IndicesObserver( vao ) );
263+
m_geom.unlockLayer( key );
264+
265+
m_geomLayers[key] = { observerId, vao };
266+
267+
return false;
268+
}
269+
bool GeometryDisplayable::removeRenderLayer( LayerKeyType key ) {
270+
auto it = m_geomLayers.find( key );
271+
if ( it == m_geomLayers.end() ) return false;
272+
273+
// the layer might have already been deleted
274+
if ( m_geom.containsLayer( key ) )
275+
{
276+
auto& geomLayer = m_geom.getLayerWithLock( key );
277+
geomLayer.detach( it->second.first );
278+
m_geom.unlockLayer( key );
279+
}
280+
delete ( it->second.second );
281+
m_geomLayers.erase( it );
282+
283+
return true;
284+
}
285+
286+
void GeometryDisplayable::updateGL_specific_impl() {
287+
CORE_ASSERT( false, "not implemented yet" );
288+
// if ( !m_indices )
289+
// {
290+
// m_indices = globjects::Buffer::create();
291+
// m_indicesDirty = true;
292+
// }
293+
// if ( m_indicesDirty )
294+
// {
295+
// /// this one do not work since m_indices is not a std::vector
296+
// // m_indices->setData( m_mesh.m_indices, GL_DYNAMIC_DRAW );
297+
// m_numElements =
298+
// base::m_mesh.getIndices().size() *
299+
// base::CoreGeometry::IndexType::RowsAtCompileTime;
300+
//
301+
// m_indices->setData(
302+
// static_cast<gl::GLsizeiptr>( base::m_mesh.getIndices().size() *
303+
// sizeof( typename base::CoreGeometry::IndexType ) ),
304+
// base::m_mesh.getIndices().data(),
305+
// GL_STATIC_DRAW );
306+
// m_indicesDirty = false;
307+
// }
308+
// if ( !base::m_vao ) { base::m_vao = globjects::VertexArray::create(); }
309+
// base::m_vao->bind();
310+
// base::m_vao->bindElementBuffer( m_indices.get() );
311+
// base::m_vao->unbind();
312+
/// \todo implement !
313+
}
314+
315+
void GeometryDisplayable::render( const ShaderProgram* ) {
316+
CORE_ASSERT( false, "not implemented yet" );
317+
// if ( base::m_vao )
318+
// {
319+
// GL_CHECK_ERROR;
320+
// base::m_vao->bind();
321+
// base::autoVertexAttribPointer( prog );
322+
// GL_CHECK_ERROR;
323+
// base::m_vao->drawElements( static_cast<GLenum>( base::m_renderMode ),
324+
// GLsizei( m_numElements ),
325+
// GL_UNSIGNED_INT,
326+
// nullptr );
327+
// GL_CHECK_ERROR;
328+
// base::m_vao->unbind();
329+
// GL_CHECK_ERROR;
330+
// }
331+
/// \todo implement !
332+
}
159333

160334
void PointCloud::render( const ShaderProgram* prog ) {
161335
if ( m_vao )

src/Engine/Data/Mesh.hpp

Lines changed: 70 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ class RA_ENGINE_API AttribArrayDisplayable : public Displayable
162162
protected:
163163
std::unique_ptr<globjects::VertexArray> m_vao;
164164

165-
MeshRenderMode m_renderMode {MeshRenderMode::RM_TRIANGLES};
165+
MeshRenderMode m_renderMode { MeshRenderMode::RM_TRIANGLES };
166166

167167
// m_vbos and m_dataDirty have the same size and are indexed thru m_handleToBuffer[attribName]
168168
std::vector<std::unique_ptr<globjects::Buffer>> m_vbos;
@@ -174,7 +174,7 @@ class RA_ENGINE_API AttribArrayDisplayable : public Displayable
174174

175175
/// General dirty bit of the mesh. Must be equivalent of the "or" of the other dirty flags.
176176
/// an empty mesh is not dirty
177-
bool m_isDirty {false};
177+
bool m_isDirty { false };
178178
};
179179

180180
/// Concept class to ensure consistent naming of VaoIndices accross derived classes.
@@ -189,20 +189,20 @@ class RA_ENGINE_API VaoIndices
189189
{
190190
public:
191191
/// not tested
192-
explicit IndicesObserver( VaoIndices* displayable ) : m_displayable {displayable} {}
192+
explicit IndicesObserver( VaoIndices* displayable ) : m_displayable { displayable } {}
193193
/// not tested
194194
void operator()() { m_displayable->m_indicesDirty = true; }
195195

196196
private:
197-
VaoIndices* m_displayable;
197+
VaoIndices* m_displayable { nullptr };
198198
};
199199

200200
protected:
201-
std::unique_ptr<globjects::Buffer> m_indices {nullptr};
202-
bool m_indicesDirty {true};
201+
std::unique_ptr<globjects::Buffer> m_indices { nullptr };
202+
bool m_indicesDirty { true };
203203
/// number of elements to draw (i.e number of indices to use)
204204
/// automatically set by updateGL(), not meaningfull if m_indicesDirty.
205-
size_t m_numElements {0};
205+
size_t m_numElements { 0 };
206206
};
207207

208208
/// This class handles an attrib array displayable on gpu only, without core
@@ -358,44 +358,76 @@ class IndexedGeometry : public CoreGeometryDisplayable<T>, public VaoIndices
358358
};
359359

360360
/// An engine mesh owning a MultiIndexedCoreGeometry, with multiple indices layer.
361-
/// \todo Work in progress.
362-
template <typename T>
363-
class MultiIndexedGeometry : public CoreGeometryDisplayable<T>
361+
class GeometryDisplayable : public AttribArrayDisplayable
364362
{
365363
public:
366-
using base = CoreGeometryDisplayable<T>;
367-
using CoreGeometryDisplayable<T>::CoreGeometryDisplayable;
368-
explicit MultiIndexedGeometry(
364+
using base = AttribArrayDisplayable;
365+
366+
using LayerSemanticCollection =
367+
typename Core::Geometry::MultiIndexedGeometry::LayerSemanticCollection;
368+
using LayerSemantic = typename Core::Geometry::MultiIndexedGeometry::LayerSemantic;
369+
using LayerKeyType = typename Core::Geometry::MultiIndexedGeometry::LayerKeyType;
370+
using LayerKeyHash = Core::Geometry::MultiIndexedGeometry::LayerKeyHash;
371+
372+
explicit GeometryDisplayable(
369373
const std::string& name,
370-
typename base::CoreGeometry&& geom,
374+
typename Core::Geometry::MultiIndexedGeometry&& geom,
371375
typename base::MeshRenderMode renderMode = base::MeshRenderMode::RM_TRIANGLES );
376+
virtual inline ~GeometryDisplayable();
372377
void render( const ShaderProgram* prog ) override;
373378

374-
void loadGeometry( T&& mesh ) override;
379+
inline Core::Geometry::MultiIndexedGeometry& getGeometry() { return m_geom; }
380+
inline const Core::Geometry::MultiIndexedGeometry& getGeometry() const { return m_geom; }
381+
382+
/// Bind meshAttribName to shaderAttribName.
383+
/// meshAttribName is a vertex attrib added to the underlying CoreGeometry
384+
/// shaderAttribName is the name of the input paramter of the shader.
385+
/// By default the same name is used, but this mecanism allows to override
386+
/// this behavior.
387+
/// Only one shaderAttribName can be bound to a meshAttribName and the other
388+
/// way round.
389+
/// \param meshAttribName: name of the attribute on the CoreGeometry side
390+
/// \param shaderAttribName: name of the input vertex attribute on the
391+
/// shader side.
392+
void setAttribNameCorrespondence( const std::string& meshAttribName,
393+
const std::string& shaderAttribName );
394+
395+
void loadGeometry( Core::Geometry::MultiIndexedGeometry&& mesh );
396+
inline void loadGeometry( Core::Geometry::MultiIndexedGeometry&& mesh, LayerKeyType key ) {
397+
loadGeometry( std::move( mesh ) );
398+
addRenderLayer( key );
399+
}
400+
template <typename RangeOfLayerKeys>
401+
inline void loadGeometry( Core::Geometry::MultiIndexedGeometry&& mesh,
402+
const RangeOfLayerKeys& r ) {
403+
loadGeometry( std::move( mesh ) );
404+
for ( const auto& k : r )
405+
addRenderLayer( k );
406+
}
407+
bool addRenderLayer( LayerKeyType key );
408+
bool removeRenderLayer( LayerKeyType key );
375409

376410
protected:
377-
void updateGL_specific_impl() override;
411+
void updateGL_specific_impl();
412+
void setupCoreMeshObservers();
378413

379-
using LayerSemanticCollection = Core::Utils::ObjectWithSemantic::SemanticNameCollection;
380-
using LayerSemantic = Core::Utils::ObjectWithSemantic::SemanticName;
381-
using LayerKeyType = std::pair<LayerSemanticCollection, std::string>;
382-
383-
using EntryType = std::pair<bool, VaoIndices*>;
384-
struct RA_CORE_API KeyHash {
385-
std::size_t operator()( const LayerKeyType& k ) const {
386-
// Mix semantic collection into a single identifier string
387-
std::ostringstream stream;
388-
std::copy(
389-
k.first.begin(), k.first.end(), std::ostream_iterator<std::string>( stream, "" ) );
390-
std::string result = stream.str();
391-
std::sort( result.begin(), result.end() );
392-
393-
// Combine with layer name hash
394-
return std::hash<std::string> {}( result ) ^
395-
( std::hash<std::string> {}( k.second ) << 1 );
396-
}
397-
};
398-
std::unordered_map<LayerKeyType, EntryType, KeyHash> m_indices;
414+
/// m_mesh Observer method, called whenever an attrib is added or removed from
415+
/// m_mesh.
416+
/// it adds an observer to the new attrib.
417+
void addAttribObserver( const std::string& name );
418+
419+
void addToTranslationTable( const std::string& name );
420+
421+
// <observerId, vao>
422+
using LayerEntryType = std::pair<int, VaoIndices*>; // std::pair<bool, VaoIndices*>;
423+
424+
using TranslationTable = std::map<std::string, std::string>;
425+
TranslationTable m_translationTableMeshToShader;
426+
TranslationTable m_translationTableShaderToMesh;
427+
428+
private:
429+
Core::Geometry::MultiIndexedGeometry m_geom;
430+
std::unordered_map<LayerKeyType, LayerEntryType, LayerKeyHash> m_geomLayers;
399431
};
400432

401433
/// LineMesh, own a Core::Geometry::LineMesh
@@ -507,9 +539,7 @@ CoreMeshType createCoreMeshFromGeometryData( const Ra::Core::Asset::GeometryData
507539
}
508540

509541
if ( data->hasColors() )
510-
{
511-
mesh.addAttrib( Data::Mesh::getAttribName( Data::Mesh::VERTEX_COLOR ), data->getColors() );
512-
}
542+
{ mesh.addAttrib( Data::Mesh::getAttribName( Data::Mesh::VERTEX_COLOR ), data->getColors() ); }
513543

514544
// add custom attribs
515545
// only attributs not handled before are handled by data->getAttribManager()
@@ -553,7 +583,7 @@ createMeshFromGeometryData( const std::string& name, const Ra::Core::Asset::Geom
553583

554584
CoreMeshType mesh = createCoreMeshFromGeometryData<CoreMeshType>( data );
555585

556-
MeshType* ret = new MeshType {name};
586+
MeshType* ret = new MeshType { name };
557587
ret->loadGeometry( std::move( mesh ) );
558588

559589
return ret;

0 commit comments

Comments
 (0)