1 /***************************************************************************
2                          qgsmesh3dgeometry_p.cpp
3                          -------------------------
4     begin                : january 2020
5     copyright            : (C) 2020 by Vincent Cloarec
6     email                : vcloarec at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "qgsmesh3dgeometry_p.h"
19 
20 #include <Qt3DRender/qattribute.h>
21 #include <Qt3DRender/qbuffer.h>
22 
23 #include <Qt3DRender/qbufferdatagenerator.h>
24 #include "qgsmeshlayer.h"
25 #include "qgstriangularmesh.h"
26 #include "qgsmeshlayerutils.h"
27 
28 
29 ///@cond PRIVATE
30 
31 using namespace Qt3DRender;
32 
createTerrainVertexData(const QgsTriangularMesh & mesh,const QgsVector3D & origin,float vertScale)33 static QByteArray createTerrainVertexData( const QgsTriangularMesh &mesh,
34     const QgsVector3D &origin,
35     float vertScale )
36 {
37   const int nVerts = mesh.vertices().count();
38 
39   QVector<QVector3D> normals = mesh.vertexNormals( vertScale );
40 
41   // Populate a buffer with the interleaved per-vertex data with
42   // vec3 pos,  vec3 normal
43   const quint32 elementSize = 3 + 3;
44   const quint32 stride = elementSize * sizeof( float );
45   QByteArray bufferBytes;
46   bufferBytes.resize( stride * nVerts );
47 
48   float *fptr = reinterpret_cast<float *>( bufferBytes.data() );
49 
50   for ( int i = 0; i < nVerts; i++ )
51   {
52     const QgsMeshVertex &vert = mesh.vertices().at( i );
53     *fptr++ = float( vert.x() - origin.x() );
54     *fptr++ = float( vert.z() - origin.z() ) * vertScale ;
55     *fptr++ = float( -vert.y() + origin.y() );
56 
57     QVector3D normal = normals.at( i );
58     normal = QVector3D( normal.x() * vertScale, -normal.y() * vertScale, normal.z() );
59     normal.normalized();
60 
61     *fptr++ = normal.x();
62     *fptr++ = normal.z();
63     *fptr++ = normal.y();
64   }
65 
66   return bufferBytes;
67 }
68 
createDatasetVertexData(const QgsTriangularMesh & mesh,const QVector<double> verticalMagnitude,const QVector<double> scalarMagnitude,const QgsVector3D & origin,float vertScale,bool verticalRelative=false)69 static QByteArray createDatasetVertexData( const QgsTriangularMesh &mesh,
70     const QVector<double> verticalMagnitude,
71     const QVector<double> scalarMagnitude,
72     const QgsVector3D &origin,
73     float vertScale,
74     bool verticalRelative = false )
75 {
76   const int nVerts = mesh.vertices().count();
77 
78   //Calculate normales with Z value equal to verticaleMagnitude
79   QVector<QVector3D> normals = QgsMeshLayerUtils::calculateNormals( mesh, verticalMagnitude, verticalRelative );
80 
81   // Populate a buffer with the interleaved per-vertex data with
82   // vec3 pos, vec3 normal, float magnitude
83   const quint32 elementSize = 3 + 3 + 1 ;
84   const quint32 stride = elementSize * sizeof( float );
85   QByteArray bufferBytes;
86   bufferBytes.resize( stride * nVerts );
87 
88   float *fptr = reinterpret_cast<float *>( bufferBytes.data() );
89 
90   for ( int i = 0; i < nVerts; i++ )
91   {
92     const QgsMeshVertex &vert = mesh.vertices().at( i );
93     double vertMag = verticalMagnitude.at( i );
94     double scalarMag = scalarMagnitude.at( i );
95     if ( verticalRelative )
96       vertMag += vert.z();
97 
98     *fptr++ = float( vert.x() - origin.x() );
99     *fptr++ = float( vertMag - origin.z() ) * vertScale ;
100     *fptr++ = float( -vert.y() + origin.y() );
101 
102     QVector3D normal = normals.at( i );
103     normal = QVector3D( normal.x() * vertScale, -normal.y() * vertScale, normal.z() );
104     normal.normalized();
105 
106     *fptr++ = normal.x();
107     *fptr++ = normal.z();
108     *fptr++ = normal.y();
109 
110     *fptr++ = float( scalarMag );
111   }
112 
113   return bufferBytes;
114 }
115 
createIndexData(const QgsTriangularMesh & mesh)116 static QByteArray createIndexData( const QgsTriangularMesh &mesh )
117 {
118   const int faces = mesh.triangles().count();
119   const quint32 indices = static_cast<quint32>( 3 * faces );
120   Q_ASSERT( indices < std::numeric_limits<quint32>::max() );
121   QByteArray indexBytes;
122   indexBytes.resize( int( indices * sizeof( quint32 ) ) );
123   quint32 *indexPtr = reinterpret_cast<quint32 *>( indexBytes.data() );
124 
125   for ( int i = 0; i < faces; ++i )
126   {
127     const QgsMeshFace &face = mesh.triangles().at( i );
128     for ( int i = 0; i < 3; ++i )
129       *indexPtr++ = quint32( face.at( i ) );
130   }
131 
132   return indexBytes;
133 }
134 
135 
createDatasetIndexData(const QgsTriangularMesh & mesh,const QgsMeshDataBlock & mActiveFaceFlagValues,int activeFaceCount)136 static QByteArray createDatasetIndexData( const QgsTriangularMesh &mesh, const QgsMeshDataBlock &mActiveFaceFlagValues, int activeFaceCount )
137 {
138   const int trianglesCount = mesh.triangles().count();
139   const quint32 indices = static_cast<quint32>( 3 * activeFaceCount );
140   QByteArray indexBytes;
141   indexBytes.resize( int( indices * sizeof( quint32 ) ) );
142   quint32 *indexPtr = reinterpret_cast<quint32 *>( indexBytes.data() );
143 
144   for ( int i = 0; i < trianglesCount; ++i )
145   {
146     int nativeFaceIndex = mesh.trianglesToNativeFaces()[i];
147     const bool isActive = mActiveFaceFlagValues.active().isEmpty() || mActiveFaceFlagValues.active( nativeFaceIndex );
148     if ( !isActive )
149       continue;
150     const QgsMeshFace &face = mesh.triangles().at( i );
151     for ( int i = 0; i < 3; ++i )
152       *indexPtr++ = quint32( face.at( i ) );
153   }
154 
155   return indexBytes;
156 }
157 
158 //! Generates vertex buffer for Mesh using vertex Z value as verticale magnitude
159 class MeshTerrainVertexBufferFunctor : public QBufferDataGenerator
160 {
161   public:
MeshTerrainVertexBufferFunctor(const QgsTriangularMesh & mesh,const QgsVector3D & origin,float vertScale)162     explicit MeshTerrainVertexBufferFunctor( const QgsTriangularMesh &mesh,
163         const QgsVector3D &origin,
164         float vertScale )
165       : mMesh( mesh ),
166         mOrigin( origin ),
167         mVertScale( vertScale )
168     {}
169 
operator ()()170     QByteArray operator()() final
171     {
172       return createTerrainVertexData( mMesh, mOrigin, mVertScale );
173     }
174 
operator ==(const QBufferDataGenerator & other) const175     bool operator ==( const QBufferDataGenerator &other ) const final
176     {
177       const MeshTerrainVertexBufferFunctor *otherFunctor = functor_cast<MeshTerrainVertexBufferFunctor>( &other );
178       if ( otherFunctor != nullptr )
179         return ( otherFunctor->mMesh.triangles().count() == mMesh.triangles().count() &&
180                  abs( otherFunctor->mVertScale - mVertScale ) < std::numeric_limits<float>::min() );
181       return false;
182     }
183 
184     QT3D_FUNCTOR( MeshTerrainVertexBufferFunctor )
185 
186   private:
187 
188     QgsTriangularMesh mMesh;
189     QgsVector3D mOrigin;
190     float mVertScale;
191 
192 };
193 
194 //! Generates index buffer for Mesh terrain
195 class MeshTerrainIndexBufferFunctor : public QBufferDataGenerator
196 {
197   public:
MeshTerrainIndexBufferFunctor(const QgsTriangularMesh & mesh)198     explicit MeshTerrainIndexBufferFunctor( const QgsTriangularMesh &mesh )
199       : mMesh( mesh )
200     {}
201 
operator ()()202     QByteArray operator()() final
203     {
204       return createIndexData( mMesh );
205     }
206 
operator ==(const QBufferDataGenerator & other) const207     bool operator ==( const QBufferDataGenerator &other ) const final
208     {
209       const MeshTerrainIndexBufferFunctor *otherFunctor = functor_cast<MeshTerrainIndexBufferFunctor>( &other );
210       if ( otherFunctor != nullptr )
211         return ( otherFunctor->mMesh.triangles().count() == mMesh.triangles().count() );
212       return false;
213     }
214 
215     QT3D_FUNCTOR( MeshTerrainIndexBufferFunctor )
216 
217   private:
218     QgsTriangularMesh mMesh;
219 };
220 
221 //! Generates index buffer for Mesh dataset
222 class MeshDatasetIndexBufferFunctor : public QBufferDataGenerator
223 {
224   public:
MeshDatasetIndexBufferFunctor(const QgsTriangularMesh & mesh,const QgsMeshDataBlock & activeFace,int activeFaceCount)225     explicit MeshDatasetIndexBufferFunctor( const QgsTriangularMesh &mesh, const QgsMeshDataBlock &activeFace, int activeFaceCount )
226       : mMesh( mesh ), mActiveFace( activeFace ), mActiveFaceCount( activeFaceCount )
227     {}
228 
operator ()()229     QByteArray operator()() final
230     {
231       return createDatasetIndexData( mMesh, mActiveFace, mActiveFaceCount );
232     }
233 
operator ==(const QBufferDataGenerator & other) const234     bool operator ==( const QBufferDataGenerator &other ) const final
235     {
236       const MeshDatasetIndexBufferFunctor *otherFunctor = functor_cast<MeshDatasetIndexBufferFunctor>( &other );
237       if ( otherFunctor != nullptr )
238         return ( otherFunctor->mMesh.triangles().count() == mMesh.triangles().count() );
239       return false;
240     }
241 
242     QT3D_FUNCTOR( MeshDatasetIndexBufferFunctor )
243   private:
244     QgsTriangularMesh mMesh;
245     QgsMeshDataBlock mActiveFace;
246     int mActiveFaceCount;
247 
248 };
249 
250 //! Generates vertex buffer for Mesh using dataset value as verticale magnitude and for color
251 class MeshDatasetVertexBufferFunctor : public QBufferDataGenerator
252 {
253   public:
254 
255     /**
256      * verticalRelative parameter is TRUE when the vertical magnitude provides from the sum of the z vertices and the scalar dataset chosen
257      * for rendering the vertical component.
258      */
MeshDatasetVertexBufferFunctor(const QgsTriangularMesh & mesh,const QVector<double> verticaleMagnitude,const QVector<double> scalarMagnitude,const QgsVector3D & origin,float vertScale,bool verticalRelative=false)259     explicit MeshDatasetVertexBufferFunctor( const QgsTriangularMesh &mesh,
260         const QVector<double> verticaleMagnitude,
261         const QVector<double> scalarMagnitude,
262         const QgsVector3D &origin,
263         float vertScale,
264         bool verticalRelative = false )
265       : mMesh( mesh ),
266         mVerticaleMagnitude( verticaleMagnitude ),
267         mScalarMagnitude( scalarMagnitude ),
268         mOrigin( origin ),
269         mVertScale( vertScale ),
270         mVerticalRelative( verticalRelative )
271     {}
272 
operator ()()273     QByteArray operator()() final
274     {
275       return createDatasetVertexData( mMesh,
276                                       mVerticaleMagnitude,
277                                       mScalarMagnitude,
278                                       mOrigin,
279                                       mVertScale,
280                                       mVerticalRelative );
281     }
282 
operator ==(const QBufferDataGenerator & other) const283     bool operator ==( const QBufferDataGenerator &other ) const final
284     {
285       const MeshDatasetVertexBufferFunctor *otherFunctor = functor_cast<MeshDatasetVertexBufferFunctor>( &other );
286       if ( otherFunctor != nullptr )
287         return ( otherFunctor->mMesh.triangles().count() == mMesh.triangles().count() &&
288                  otherFunctor->mVerticaleMagnitude.count() == mVerticaleMagnitude.count() &&
289                  otherFunctor->mScalarMagnitude.count() == mScalarMagnitude.count() &&
290                  abs( otherFunctor->mVertScale - mVertScale ) < std::numeric_limits<float>::min() &&
291                  otherFunctor->mVerticalRelative == mVerticalRelative );
292       return false;
293     }
294 
295     QT3D_FUNCTOR( MeshDatasetVertexBufferFunctor )
296 
297   private:
298     QgsTriangularMesh mMesh;
299     QVector<double> mVerticaleMagnitude;
300     QVector<double> mScalarMagnitude;
301     QgsVector3D mOrigin;
302     float mVertScale;
303     bool mVerticalRelative = false;
304 
305 };
306 
QgsMesh3dGeometry(const QgsTriangularMesh & triangularMesh,const QgsVector3D & origin,const QgsMesh3DSymbol * symbol,Qt3DCore::QNode * parent)307 QgsMesh3dGeometry::QgsMesh3dGeometry( const QgsTriangularMesh &triangularMesh,
308                                       const QgsVector3D &origin,
309                                       const QgsMesh3DSymbol *symbol,
310                                       Qt3DCore::QNode *parent )
311   : Qt3DRender::QGeometry( parent )
312   , mOrigin( origin )
313   , mVertScale( symbol->verticalScale() )
314   , mTriangulaMesh( triangularMesh )
315 {}
316 
QgsMeshDataset3dGeometry(const QgsTriangularMesh & triangularMesh,QgsMeshLayer * layer,const QgsDateTimeRange & timeRange,const QgsVector3D & origin,const QgsMesh3DSymbol * symbol,Qt3DCore::QNode * parent)317 QgsMeshDataset3dGeometry::QgsMeshDataset3dGeometry(
318   const QgsTriangularMesh &triangularMesh,
319   QgsMeshLayer *layer,
320   const QgsDateTimeRange &timeRange,
321   const QgsVector3D &origin,
322   const QgsMesh3DSymbol *symbol,
323   Qt3DCore::QNode *parent )
324   : QgsMesh3dGeometry( triangularMesh, origin, symbol, parent )
325   , mIsVerticalMagnitudeRelative( symbol->isVerticalMagnitudeRelative() )
326   , mVerticalGroupDatasetIndex( symbol->verticalDatasetGroupIndex() )
327   , mTimeRange( timeRange )
328   , mLayerRef( layer )
329 {
330   init();
331 }
332 
init()333 void QgsMeshDataset3dGeometry::init()
334 {
335   if ( mVerticalGroupDatasetIndex < 0 )
336     return;
337 
338   QVector<double> verticaleMagnitude;
339   QVector<double> scalarMagnitude;
340   QgsMeshDataBlock activeFaces;
341 
342   int activefaceCount = extractDataset( verticaleMagnitude, scalarMagnitude, activeFaces );
343   if ( activefaceCount == 0 )
344     return;
345 
346 
347   if ( verticaleMagnitude.count() != mTriangulaMesh.vertices().count()  ||
348        scalarMagnitude.count() != mTriangulaMesh.vertices().count() )
349     return;
350 
351 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
352   Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this );
353   Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer, this );
354 #else
355   Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( this );
356   Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( this );
357 #endif
358 
359   const int stride = ( 3 /*position*/ +
360                        3 /*normale*/ +
361                        1 /*magnitude*/ ) * sizeof( float );
362 
363   const uint nVerts = uint( mTriangulaMesh.vertices().count() );
364 
365   prepareVerticesPositionAttribute( vertexBuffer, nVerts, stride, 0 );
366   prepareVerticesNormalAttribute( vertexBuffer, nVerts, stride, 3 );
367   prepareVerticesDatasetAttribute( vertexBuffer, nVerts, stride, 6 );
368 
369   prepareIndexesAttribute( indexBuffer, activefaceCount );
370 
371 
372   Qt3DRender::QBufferDataGeneratorPtr vertexDataGenerator = Qt3DRender::QBufferDataGeneratorPtr(
373         new MeshDatasetVertexBufferFunctor( mTriangulaMesh, verticaleMagnitude, scalarMagnitude, mOrigin, mVertScale, mIsVerticalMagnitudeRelative ) );
374   vertexBuffer->setDataGenerator( vertexDataGenerator );
375 
376   Qt3DRender::QBufferDataGeneratorPtr indexDataGenerator( new MeshDatasetIndexBufferFunctor(
377         mTriangulaMesh, activeFaces, activefaceCount ) );
378   indexBuffer->setDataGenerator( indexDataGenerator );
379 }
380 
extractDataset(QVector<double> & verticalMagnitude,QVector<double> & scalarMagnitude,QgsMeshDataBlock & activeFaceFlagValues)381 int QgsMeshDataset3dGeometry::extractDataset( QVector<double> &verticalMagnitude, QVector<double> &scalarMagnitude, QgsMeshDataBlock &activeFaceFlagValues )
382 {
383   QgsMeshLayer *layer = meshLayer();
384 
385   if ( !layer )
386     return 0;
387 
388   QgsMeshDatasetIndex scalarDatasetIndex = layer->activeScalarDatasetAtTime( mTimeRange );
389 
390   if ( !scalarDatasetIndex.isValid() )
391     return 0;
392 
393   if ( mVerticalGroupDatasetIndex < 0 )
394     return 0;
395 
396   const QgsMesh nativeMesh = *layer->nativeMesh();
397 
398   //extract the scalar dataset used to render vertical magnitude of geometry
399   //define the vertical magnitude datasetIndex
400   QgsMeshDatasetIndex verticalMagDatasetIndex;
401   verticalMagDatasetIndex = layer->datasetIndexAtTime( mTimeRange, mVerticalGroupDatasetIndex );
402   if ( !verticalMagDatasetIndex.isValid() )
403   {
404     //if invalid (for example, static mode) use the scalar dataset index
405     int vertDataSetIndex = scalarDatasetIndex.dataset();
406     vertDataSetIndex = std::min( vertDataSetIndex, layer->datasetCount( mVerticalGroupDatasetIndex ) - 1 );
407     verticalMagDatasetIndex = QgsMeshDatasetIndex( mVerticalGroupDatasetIndex, vertDataSetIndex );
408   }
409   //define the active face for vertical magnitude, the inactive faces will not be rendered
410   // The active face flag values are defined based on the vertival magnitude dataset
411   activeFaceFlagValues = layer->areFacesActive( verticalMagDatasetIndex, 0, nativeMesh.faces.count() );
412   verticalMagnitude = QgsMeshLayerUtils::calculateMagnitudeOnVertices(
413                         layer,
414                         verticalMagDatasetIndex,
415                         &activeFaceFlagValues );
416 
417   //count active faces
418   int activeTriangularCount = 0;
419   if ( activeFaceFlagValues.active().isEmpty() )
420     activeTriangularCount = mTriangulaMesh.triangles().count();
421   else
422     for ( int i = 0; i < mTriangulaMesh.triangles().count(); ++i )
423     {
424       int nativeIndex = mTriangulaMesh.trianglesToNativeFaces()[i];
425       if ( activeFaceFlagValues.active( nativeIndex ) )
426         activeTriangularCount++;
427     }
428 
429   //extract the scalar dataset used to render color shading
430   QgsMeshDataBlock scalarActiveFaceFlagValues =
431     layer->areFacesActive( scalarDatasetIndex, 0, nativeMesh.faces.count() );
432   scalarMagnitude = QgsMeshLayerUtils::calculateMagnitudeOnVertices(
433                       layer,
434                       scalarDatasetIndex,
435                       &scalarActiveFaceFlagValues );
436 
437   return activeTriangularCount;
438 }
439 
440 
QgsMeshTerrain3dGeometry(const QgsTriangularMesh & triangularMesh,const QgsVector3D & origin,const QgsMesh3DSymbol * symbol,Qt3DCore::QNode * parent)441 QgsMeshTerrain3dGeometry::QgsMeshTerrain3dGeometry(
442   const QgsTriangularMesh &triangularMesh,
443   const QgsVector3D &origin,
444   const QgsMesh3DSymbol *symbol,
445   Qt3DCore::QNode *parent )
446   : QgsMesh3dGeometry( triangularMesh, origin, symbol, parent )
447 {
448   init();
449 }
450 
init()451 void QgsMeshTerrain3dGeometry::init()
452 {
453 #if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
454   Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::VertexBuffer, this );
455   Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( Qt3DRender::QBuffer::IndexBuffer, this );
456 #else
457   Qt3DRender::QBuffer *vertexBuffer = new Qt3DRender::QBuffer( this );
458   Qt3DRender::QBuffer *indexBuffer = new Qt3DRender::QBuffer( this );
459 #endif
460 
461   const int stride = ( 3 /*position*/ +
462                        3 /*normale*/ ) * sizeof( float );
463 
464   const uint nVerts = uint( mTriangulaMesh.vertices().count() );
465 
466   prepareVerticesPositionAttribute( vertexBuffer, nVerts, stride, 0 );
467   prepareVerticesNormalAttribute( vertexBuffer, nVerts, stride, 3 );
468   prepareIndexesAttribute( indexBuffer, mTriangulaMesh.triangles().count() );
469 
470   Qt3DRender::QBufferDataGeneratorPtr vertexDataGenerator =
471     Qt3DRender::QBufferDataGeneratorPtr( new MeshTerrainVertexBufferFunctor( mTriangulaMesh,  mOrigin, mVertScale ) );
472   vertexBuffer->setDataGenerator( vertexDataGenerator );
473 
474   Qt3DRender::QBufferDataGeneratorPtr indexDataGenerator( new MeshTerrainIndexBufferFunctor( mTriangulaMesh ) );
475   indexBuffer->setDataGenerator( indexDataGenerator );
476 
477 }
478 
prepareVerticesPositionAttribute(Qt3DRender::QBuffer * buffer,int count,int stride,int offset)479 void QgsMesh3dGeometry::prepareVerticesPositionAttribute( Qt3DRender::QBuffer *buffer, int count, int stride, int offset )
480 {
481   Qt3DRender::QAttribute *positionAttribute = new QAttribute( this );
482 
483   positionAttribute->setName( QAttribute::defaultPositionAttributeName() );
484   positionAttribute->setVertexBaseType( QAttribute::Float );
485   positionAttribute->setVertexSize( 3 );
486   positionAttribute->setAttributeType( QAttribute::VertexAttribute );
487   positionAttribute->setBuffer( buffer );
488   positionAttribute->setByteStride( stride );
489   positionAttribute->setByteOffset( offset * sizeof( float ) );
490   positionAttribute->setCount( count );
491 
492   addAttribute( positionAttribute );
493 }
494 
prepareVerticesNormalAttribute(Qt3DRender::QBuffer * buffer,int count,int stride,int offset)495 void QgsMesh3dGeometry::prepareVerticesNormalAttribute( Qt3DRender::QBuffer *buffer, int count, int stride, int offset )
496 {
497   Qt3DRender::QAttribute *normalAttribute = new QAttribute( this );
498 
499   normalAttribute->setName( QAttribute::defaultNormalAttributeName() );
500   normalAttribute->setVertexBaseType( QAttribute::Float );
501   normalAttribute->setVertexSize( 3 );
502   normalAttribute->setAttributeType( QAttribute::VertexAttribute );
503   normalAttribute->setBuffer( buffer );
504   normalAttribute->setByteStride( stride );
505   normalAttribute->setByteOffset( offset * sizeof( float ) );
506   normalAttribute->setCount( count );
507 
508   addAttribute( normalAttribute );
509 }
510 
prepareVerticesDatasetAttribute(Qt3DRender::QBuffer * buffer,int count,int stride,int offset)511 void QgsMeshDataset3dGeometry::prepareVerticesDatasetAttribute( Qt3DRender::QBuffer *buffer, int count, int stride, int offset )
512 {
513   Qt3DRender::QAttribute *magnitudeAttribute = new QAttribute( this );
514 
515   magnitudeAttribute->setName( "scalarMagnitude" );
516   magnitudeAttribute->setVertexBaseType( QAttribute::Float );
517   magnitudeAttribute->setVertexSize( 1 );
518   magnitudeAttribute->setAttributeType( QAttribute::VertexAttribute );
519   magnitudeAttribute->setBuffer( buffer );
520   magnitudeAttribute->setByteStride( stride );
521   magnitudeAttribute->setByteOffset( offset * sizeof( float ) );
522   magnitudeAttribute->setCount( count );
523 
524   addAttribute( magnitudeAttribute );
525 }
526 
meshLayer() const527 QgsMeshLayer *QgsMeshDataset3dGeometry::meshLayer() const
528 {
529   return qobject_cast<QgsMeshLayer *>( mLayerRef.layer.data() );
530 }
531 
prepareIndexesAttribute(Qt3DRender::QBuffer * buffer,int trianglesCount)532 void QgsMesh3dGeometry::prepareIndexesAttribute( Qt3DRender::QBuffer *buffer, int trianglesCount )
533 {
534 
535   Qt3DRender::QAttribute *indexAttribute = new QAttribute( this );
536   indexAttribute->setAttributeType( QAttribute::IndexAttribute );
537   indexAttribute->setVertexBaseType( QAttribute::UnsignedInt );
538   indexAttribute->setBuffer( buffer );
539 
540   // Each primitive has 3 vertices
541   indexAttribute->setCount( trianglesCount * 3 );
542 
543   addAttribute( indexAttribute );
544 }
545 
546