From 9f97b84b96a8fec13db56276d495fd090d2ce2de Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 21 Aug 2020 15:10:18 +1000 Subject: [PATCH 1/2] Don't store references to symbols in 3d symbol handlers These references are to objects belonging to another thread, which can cause crashes if the object on the main thread is deleted while the handler is still active Refs a asan report: ==677416==ERROR: AddressSanitizer: heap-use-after-free on address 0x6070029bc278 at pc 0x7f95719ccc45 bp 0x7f94bdd7a310 sp 0x7f94bdd7a300 READ of size 4 at 0x6070029bc278 thread T36 (Thread (pooled)) #0 0x7f95719ccc44 in QgsLine3DSymbol::extrusionHeight() const /home/nyall/dev/qgis-asan/src/3d/symbols/qgsline3dsymbol.h:78 #1 0x7f95674a7c01 in QgsBufferedLine3DSymbolHandler::processFeature(QgsFeature&, Qgs3DRenderContext const&) /home/nyall/dev/qgis-asan/src/3d/symbols/qgsline3dsymbol_p.cpp:126 #2 0x7f9567457045 in operator() /home/nyall/dev/qgis-asan/src/3d/qgsvectorlayerchunkloader_p.cpp:97 #3 0x7f95674597fd in runFunctor /usr/include/qt5/QtConcurrent/qtconcurrentstoredfunctioncall.h:70 #4 0x7f956744acf7 in QtConcurrent::RunFunctionTask::run() (/home/nyall/dev/build-QGIS-asan/output/lib/libqgis_3d.so.3.15.0+0x2adcf7) #5 0x7f956a275d59 (/usr/lib64/libQt5Core.so.5+0xc9d59) #6 0x7f956a27268f (/usr/lib64/libQt5Core.so.5+0xc668f) #7 0x7f956a193431 in start_thread (/usr/lib64/libpthread.so.0+0x9431) #8 0x7f955ad59912 in __GI___clone (/usr/lib64/libc.so.6+0x101912) 0x6070029bc278 is located 56 bytes inside of 72-byte region [0x6070029bc240,0x6070029bc288) freed by thread T0 here: #0 0x7f9572b86b87 in operator delete(void*) (/usr/lib64/libasan.so.6+0xb2b87) #1 0x7f956749c00b in QgsLine3DSymbol::~QgsLine3DSymbol() /home/nyall/dev/qgis-asan/src/3d/symbols/qgsline3dsymbol.cpp:30 #2 0x7f95719664ca in std::default_delete::operator()(QgsAbstract3DSymbol*) const /usr/include/c++/10/bits/unique_ptr.h:85 #3 0x7f95674428ce in std::unique_ptr >::~unique_ptr() /usr/include/c++/10/bits/unique_ptr.h:361 #4 0x7f9567459eb6 in QgsVectorLayerChunkLoaderFactory::~QgsVectorLayerChunkLoaderFactory() /home/nyall/dev/qgis-asan/src/3d/qgsvectorlayerchunkloader_p.h:53 #5 0x7f9567459edd in QgsVectorLayerChunkLoaderFactory::~QgsVectorLayerChunkLoaderFactory() /home/nyall/dev/qgis-asan/src/3d/qgsvectorlayerchunkloader_p.h:53 #6 0x7f956746e4db in QgsChunkedEntity::~QgsChunkedEntity() /home/nyall/dev/qgis-asan/src/3d/chunks/qgschunkedentity_p.cpp:122 #7 0x7f9567459358 in QgsVectorLayerChunkedEntity::~QgsVectorLayerChunkedEntity() /home/nyall/dev/qgis-asan/src/3d/qgsvectorlayerchunkloader_p.cpp:164 #8 0x7f9567459373 in QgsVectorLayerChunkedEntity::~QgsVectorLayerChunkedEntity() /home/nyall/dev/qgis-asan/src/3d/qgsvectorlayerchunkloader_p.cpp:168 #9 0x7f956a42e960 in QObject::event(QEvent*) (/usr/lib64/libQt5Core.so.5+0x282960) #10 0x7f956ada2062 in QApplicationPrivate::notify_helper(QObject*, QEvent*) (/usr/lib64/libQt5Widgets.so.5+0x172062) previously allocated by thread T0 here: #0 0x7f9572b86067 in operator new(unsigned long) (/usr/lib64/libasan.so.6+0xb2067) #1 0x7f95674a3018 in qgis::_Unique_if::_Single_object qgis::make_unique() /home/nyall/dev/qgis-asan/src/core/qgis.h:425 #2 0x7f956749c0b9 in QgsLine3DSymbol::clone() const /home/nyall/dev/qgis-asan/src/3d/symbols/qgsline3dsymbol.cpp:34 #3 0x7f9567458b5f in QgsVectorLayerChunkLoaderFactory::QgsVectorLayerChunkLoaderFactory(Qgs3DMapSettings const&, QgsVectorLayer*, QgsAbstract3DSymbol*, int) /home/nyall/dev/qgis-asan/src/3d/qgsvectorlayerchunkloader_p.cpp:141 #4 0x7f9567458d88 in QgsVectorLayerChunkedEntity::QgsVectorLayerChunkedEntity(QgsVectorLayer*, double, double, QgsVectorLayer3DTilingSettings const&, QgsAbstract3DSymbol*, Qgs3DMapSettings const&) /home/nyall/dev/qgis-asan/src/3d/qgsvectorlayerchunkloader_p.cpp:159 #5 0x7f956745558f in QgsVectorLayer3DRenderer::createEntity(Qgs3DMapSettings const&) const /home/nyall/dev/qgis-asan/src/3d/qgsvectorlayer3drenderer.cpp:76 #6 0x7f95673a71c0 in Qgs3DMapScene::addLayerEntity(QgsMapLayer*) /home/nyall/dev/qgis-asan/src/3d/qgs3dmapscene.cpp:693 #7 0x7f95673a5523 in Qgs3DMapScene::onLayerRenderer3DChanged() /home/nyall/dev/qgis-asan/src/3d/qgs3dmapscene.cpp:598 #8 0x7f95673c6c33 in QtPrivate::FunctorCall, QtPrivate::List<>, void, void (Qgs3DMapScene::*)()>::call(void (Qgs3DMapScene::*)(), Qgs3DMapScene*, void**) (/home/nyall/dev/build-QGIS-asan/output/lib/libqgis_3d.so.3.15.0+0x229c33) #9 0x7f95673c5468 in void QtPrivate::FunctionPointer::call, void>(void (Qgs3DMapScene::*)(), Qgs3DMapScene*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:185 #10 0x7f95673c1748 in QtPrivate::QSlotObject, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) /usr/include/qt5/QtCore/qobjectdefs_impl.h:418 #11 0x7f956a435f75 (/usr/lib64/libQt5Core.so.5+0x289f75) #12 0x7f956252106c in QgsMapLayer::renderer3DChanged() src/core/qgis_core_autogen/EWIEGA46WW/moc_qgsmaplayer.cpp:702 #13 0x7f9563917a12 in QgsMapLayer::setRenderer3D(QgsAbstract3DRenderer*) /home/nyall/dev/qgis-asan/src/core/qgsmaplayer.cpp:1813 #14 0x7f95719aaf52 in QgsApp3DSymbolWidgetWithPreview::updatePreview(QgsAbstract3DSymbol*) /home/nyall/dev/qgis-asan/src/app/3d/qgsapp3dsymbolwidget.cpp:243 #15 0x7f95719a97af in operator() /home/nyall/dev/qgis-asan/src/app/3d/qgsapp3dsymbolwidget.cpp:175 #16 0x7f95719ac2dd in call /usr/include/qt5/QtCore/qobjectdefs_impl.h:146 #17 0x7f95719ac24f in call, void> /usr/include/qt5/QtCore/qobjectdefs_impl.h:256 #18 0x7f95719ac21e in impl /usr/include/qt5/QtCore/qobjectdefs_impl.h:443 #19 0x7f956a435f75 (/usr/lib64/libQt5Core.so.5+0x289f75) #20 0x7f95708d15ec in QgsApp3DSymbolWidget::widgetChanged() src/app/qgis_app_autogen/6LADBHSVD5/moc_qgsapp3dsymbolwidget.cpp:144 #21 0x7f95719ae1dd in QtPrivate::FunctorCall, QtPrivate::List<>, void, void (QgsApp3DSymbolWidget::*)()>::call(void (QgsApp3DSymbolWidget::*)(), QgsApp3DSymbolWidget*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:152 #22 0x7f95719add9c in void QtPrivate::FunctionPointer::call, void>(void (QgsApp3DSymbolWidget::*)(), QgsApp3DSymbolWidget*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:185 #23 0x7f95719adbfa in QtPrivate::QSlotObject, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) /usr/include/qt5/QtCore/qobjectdefs_impl.h:418 #24 0x7f956a435f75 (/usr/lib64/libQt5Core.so.5+0x289f75) #25 0x7f956c91c63e in Qgs3DSymbolWidget::changed() src/gui/qgis_gui_autogen/EWIEGA46WW/moc_qgs3dsymbolwidget.cpp:131 #26 0x7f95719ce2ad in QtPrivate::FunctorCall, QtPrivate::List<>, void, void (Qgs3DSymbolWidget::*)()>::call(void (Qgs3DSymbolWidget::*)(), Qgs3DSymbolWidget*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:152 #27 0x7f95719ce014 in void QtPrivate::FunctionPointer::call, void>(void (Qgs3DSymbolWidget::*)(), Qgs3DSymbolWidget*, void**) /usr/include/qt5/QtCore/qobjectdefs_impl.h:185 #28 0x7f95719cdbfc in QtPrivate::QSlotObject, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) /usr/include/qt5/QtCore/qobjectdefs_impl.h:418 #29 0x7f956a435f75 (/usr/lib64/libQt5Core.so.5+0x289f75) --- src/3d/symbols/qgsline3dsymbol_p.cpp | 53 ++++++++------- src/3d/symbols/qgspoint3dsymbol_p.cpp | 89 +++++++++++++------------ src/3d/symbols/qgspolygon3dsymbol_p.cpp | 55 +++++++-------- 3 files changed, 102 insertions(+), 95 deletions(-) diff --git a/src/3d/symbols/qgsline3dsymbol_p.cpp b/src/3d/symbols/qgsline3dsymbol_p.cpp index 465562d057a1..cff6d7c77638 100644 --- a/src/3d/symbols/qgsline3dsymbol_p.cpp +++ b/src/3d/symbols/qgsline3dsymbol_p.cpp @@ -45,8 +45,9 @@ class QgsBufferedLine3DSymbolHandler : public QgsFeature3DHandler { public: - QgsBufferedLine3DSymbolHandler( const QgsLine3DSymbol &symbol, const QgsFeatureIds &selectedIds ) - : mSymbol( symbol ), mSelectedIds( selectedIds ) {} + QgsBufferedLine3DSymbolHandler( const QgsLine3DSymbol *symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( static_cast< QgsLine3DSymbol *>( symbol->clone() ) ) + , mSelectedIds( selectedIds ) {} bool prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) override; void processFeature( QgsFeature &feature, const Qgs3DRenderContext &context ) override; @@ -67,7 +68,7 @@ class QgsBufferedLine3DSymbolHandler : public QgsFeature3DHandler void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, LineData &out, bool selected ); // input specific for this class - const QgsLine3DSymbol &mSymbol; + std::unique_ptr< QgsLine3DSymbol > mSymbol; // inputs - generic QgsFeatureIds mSelectedIds; @@ -82,7 +83,7 @@ bool QgsBufferedLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, { Q_UNUSED( attributeNames ) - const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol.material() ); + const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol->material() ); outNormal.tessellator.reset( new QgsTessellator( context.map().origin().x(), context.map().origin().y(), true, false, false, false, texturedMaterialSettings ? texturedMaterialSettings->requiresTextureCoordinates() : false, @@ -118,12 +119,12 @@ void QgsBufferedLine3DSymbolHandler::processFeature( QgsFeature &f, const Qgs3DR const double mitreLimit = 0; QgsGeos engine( g ); - QgsAbstractGeometry *buffered = engine.buffer( mSymbol.width() / 2., nSegments, endCapStyle, joinStyle, mitreLimit ); // factory + QgsAbstractGeometry *buffered = engine.buffer( mSymbol->width() / 2., nSegments, endCapStyle, joinStyle, mitreLimit ); // factory if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::Polygon ) { QgsPolygon *polyBuffered = static_cast( buffered ); - processPolygon( polyBuffered, f.id(), mSymbol.height(), mSymbol.extrusionHeight(), context, out ); + processPolygon( polyBuffered, f.id(), mSymbol->height(), mSymbol->extrusionHeight(), context, out ); } else if ( QgsWkbTypes::flatType( buffered->wkbType() ) == QgsWkbTypes::MultiPolygon ) { @@ -131,7 +132,7 @@ void QgsBufferedLine3DSymbolHandler::processFeature( QgsFeature &f, const Qgs3DR for ( int i = 0; i < mpolyBuffered->numGeometries(); ++i ) { QgsPolygon *polyBuffered = static_cast( mpolyBuffered->polygonN( i ) )->clone(); // need to clone individual geometry parts - processPolygon( polyBuffered, f.id(), mSymbol.height(), mSymbol.extrusionHeight(), context, out ); + processPolygon( polyBuffered, f.id(), mSymbol->height(), mSymbol->extrusionHeight(), context, out ); } delete buffered; } @@ -139,7 +140,7 @@ void QgsBufferedLine3DSymbolHandler::processFeature( QgsFeature &f, const Qgs3DR void QgsBufferedLine3DSymbolHandler::processPolygon( QgsPolygon *polyBuffered, QgsFeatureId fid, float height, float extrusionHeight, const Qgs3DRenderContext &context, LineData &out ) { - Qgs3DUtils::clampAltitudes( polyBuffered, mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), height, context.map() ); + Qgs3DUtils::clampAltitudes( polyBuffered, mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), height, context.map() ); Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 ); uint startingTriangleIndex = static_cast( out.tessellator->dataVerticesCount() / 3 ); @@ -168,13 +169,13 @@ void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, cons QgsMaterialContext materialContext; materialContext.setIsSelected( selected ); materialContext.setSelectionColor( context.map().selectionColor() ); - Qt3DRender::QMaterial *mat = mSymbol.material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext ); + Qt3DRender::QMaterial *mat = mSymbol->material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext ); // extract vertex buffer data from tessellator QByteArray data( ( const char * )out.tessellator->data().constData(), out.tessellator->data().count() * sizeof( float ) ); int nVerts = data.count() / out.tessellator->stride(); - const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol.material() ); + const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol->material() ); QgsTessellatedPolygonGeometry *geometry = new QgsTessellatedPolygonGeometry( true, false, false, texturedMaterialSettings ? texturedMaterialSettings->requiresTextureCoordinates() : false ); @@ -203,8 +204,9 @@ void QgsBufferedLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, cons class QgsSimpleLine3DSymbolHandler : public QgsFeature3DHandler { public: - QgsSimpleLine3DSymbolHandler( const QgsLine3DSymbol &symbol, const QgsFeatureIds &selectedIds ) - : mSymbol( symbol ), mSelectedIds( selectedIds ) + QgsSimpleLine3DSymbolHandler( const QgsLine3DSymbol *symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( static_cast< QgsLine3DSymbol *>( symbol->clone() ) ) + , mSelectedIds( selectedIds ) { } @@ -218,7 +220,7 @@ class QgsSimpleLine3DSymbolHandler : public QgsFeature3DHandler Qt3DExtras::QPhongMaterial *material( const QgsLine3DSymbol &symbol ) const; // input specific for this class - const QgsLine3DSymbol &mSymbol; + std::unique_ptr< QgsLine3DSymbol > mSymbol; // inputs - generic QgsFeatureIds mSelectedIds; @@ -233,8 +235,8 @@ bool QgsSimpleLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, Q { Q_UNUSED( attributeNames ) - outNormal.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() ); - outSelected.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() ); + outNormal.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->height(), &context.map() ); + outSelected.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->height(), &context.map() ); return true; } @@ -284,7 +286,7 @@ void QgsSimpleLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const QgsMaterialContext materialContext; materialContext.setIsSelected( selected ); materialContext.setSelectionColor( context.map().selectionColor() ); - Qt3DRender::QMaterial *mat = mSymbol.material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Lines, materialContext ); + Qt3DRender::QMaterial *mat = mSymbol->material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Lines, materialContext ); // geometry renderer @@ -313,8 +315,9 @@ void QgsSimpleLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const class QgsThickLine3DSymbolHandler : public QgsFeature3DHandler { public: - QgsThickLine3DSymbolHandler( const QgsLine3DSymbol &symbol, const QgsFeatureIds &selectedIds ) - : mSymbol( symbol ), mSelectedIds( selectedIds ) + QgsThickLine3DSymbolHandler( const QgsLine3DSymbol *symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( static_cast< QgsLine3DSymbol * >( symbol->clone() ) ) + , mSelectedIds( selectedIds ) { } @@ -329,7 +332,7 @@ class QgsThickLine3DSymbolHandler : public QgsFeature3DHandler Qt3DExtras::QPhongMaterial *material( const QgsLine3DSymbol &symbol ) const; // input specific for this class - const QgsLine3DSymbol &mSymbol; + std::unique_ptr< QgsLine3DSymbol > mSymbol; // inputs - generic QgsFeatureIds mSelectedIds; @@ -346,8 +349,8 @@ bool QgsThickLine3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QS outNormal.withAdjacency = true; outSelected.withAdjacency = true; - outNormal.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() ); - outSelected.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), mSymbol.height(), &context.map() ); + outNormal.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->height(), &context.map() ); + outSelected.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), mSymbol->height(), &context.map() ); return true; } @@ -396,7 +399,7 @@ void QgsThickLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Q QgsMaterialContext materialContext; materialContext.setIsSelected( selected ); materialContext.setSelectionColor( context.map().selectionColor() ); - Qt3DRender::QMaterial *mat = mSymbol.material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Lines, materialContext ); + Qt3DRender::QMaterial *mat = mSymbol->material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Lines, materialContext ); if ( !mat ) { QgsSimpleLineMaterialSettings defaultMaterial; @@ -404,7 +407,7 @@ void QgsThickLine3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Q } if ( QgsLineMaterial *lineMaterial = dynamic_cast< QgsLineMaterial * >( mat ) ) - lineMaterial->setLineWidth( mSymbol.width() ); + lineMaterial->setLineWidth( mSymbol->width() ); Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; @@ -436,10 +439,10 @@ namespace Qgs3DSymbolImpl return nullptr; if ( lineSymbol->renderAsSimpleLines() ) - return new QgsThickLine3DSymbolHandler( *lineSymbol, layer->selectedFeatureIds() ); + return new QgsThickLine3DSymbolHandler( lineSymbol, layer->selectedFeatureIds() ); //return new QgsSimpleLine3DSymbolHandler( symbol, layer->selectedFeatureIds() ); else - return new QgsBufferedLine3DSymbolHandler( *lineSymbol, layer->selectedFeatureIds() ); + return new QgsBufferedLine3DSymbolHandler( lineSymbol, layer->selectedFeatureIds() ); } Qt3DCore::QEntity *entityForLine3DSymbol( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsLine3DSymbol &symbol ) diff --git a/src/3d/symbols/qgspoint3dsymbol_p.cpp b/src/3d/symbols/qgspoint3dsymbol_p.cpp index e2d3d41bf3f2..2aa34e034b57 100644 --- a/src/3d/symbols/qgspoint3dsymbol_p.cpp +++ b/src/3d/symbols/qgspoint3dsymbol_p.cpp @@ -65,8 +65,9 @@ class QgsInstancedPoint3DSymbolHandler : public QgsFeature3DHandler { public: - QgsInstancedPoint3DSymbolHandler( const QgsPoint3DSymbol &symbol, const QgsFeatureIds &selectedIds ) - : mSymbol( symbol ), mSelectedIds( selectedIds ) {} + QgsInstancedPoint3DSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( static_cast< QgsPoint3DSymbol *>( symbol->clone() ) ) + , mSelectedIds( selectedIds ) {} bool prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) override; void processFeature( QgsFeature &feature, const Qgs3DRenderContext &context ) override; @@ -74,8 +75,8 @@ class QgsInstancedPoint3DSymbolHandler : public QgsFeature3DHandler private: - static Qt3DRender::QMaterial *material( const QgsPoint3DSymbol &symbol ); - static Qt3DRender::QGeometryRenderer *renderer( const QgsPoint3DSymbol &symbol, const QVector &positions ); + static Qt3DRender::QMaterial *material( const QgsPoint3DSymbol *symbol ); + static Qt3DRender::QGeometryRenderer *renderer( const QgsPoint3DSymbol *symbol, const QVector &positions ); static Qt3DRender::QGeometry *symbolGeometry( QgsPoint3DSymbol::Shape shape, const QVariantMap &shapeProperties ); //! temporary data we will pass to the tessellator @@ -87,7 +88,7 @@ class QgsInstancedPoint3DSymbolHandler : public QgsFeature3DHandler void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected ); // input specific for this class - const QgsPoint3DSymbol &mSymbol; + std::unique_ptr< QgsPoint3DSymbol > mSymbol; // inputs - generic QgsFeatureIds mSelectedIds; @@ -111,7 +112,7 @@ void QgsInstancedPoint3DSymbolHandler::processFeature( QgsFeature &feature, cons if ( feature.geometry().isNull() ) return; - Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol.altitudeClamping(), out.positions ); + Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol->altitudeClamping(), out.positions ); } void QgsInstancedPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) @@ -123,7 +124,7 @@ void QgsInstancedPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, cons updateZRangeFromPositions( outSelected.positions ); // the elevation offset is applied in the vertex shader so let's account for it as well - float symbolHeight = mSymbol.transform().data()[13]; + float symbolHeight = mSymbol->transform().data()[13]; mZMin += symbolHeight; mZMax += symbolHeight; } @@ -131,7 +132,7 @@ void QgsInstancedPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, cons void QgsInstancedPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected ) { // build the default material - Qt3DRender::QMaterial *mat = material( mSymbol ); + Qt3DRender::QMaterial *mat = material( mSymbol.get() ); if ( selected ) { @@ -147,7 +148,7 @@ void QgsInstancedPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, co // build the entity Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; - entity->addComponent( renderer( mSymbol, out.positions ) ); + entity->addComponent( renderer( mSymbol.get(), out.positions ) ); entity->addComponent( mat ); entity->setParent( parent ); @@ -157,7 +158,7 @@ void QgsInstancedPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, co -Qt3DRender::QMaterial *QgsInstancedPoint3DSymbolHandler::material( const QgsPoint3DSymbol &symbol ) +Qt3DRender::QMaterial *QgsInstancedPoint3DSymbolHandler::material( const QgsPoint3DSymbol *symbol ) { Qt3DRender::QFilterKey *filterKey = new Qt3DRender::QFilterKey; filterKey->setName( QStringLiteral( "renderingStyle" ) ); @@ -181,7 +182,7 @@ Qt3DRender::QMaterial *QgsInstancedPoint3DSymbolHandler::material( const QgsPoin technique->graphicsApiFilter()->setMajorVersion( 3 ); technique->graphicsApiFilter()->setMinorVersion( 2 ); - QMatrix4x4 transformMatrix = symbol.transform(); + QMatrix4x4 transformMatrix = symbol->transform(); QMatrix3x3 normalMatrix = transformMatrix.normalMatrix(); // transponed inverse of 3x3 sub-matrix // QMatrix3x3 is not supported for passing to shaders, so we pass QMatrix4x4 @@ -205,7 +206,7 @@ Qt3DRender::QMaterial *QgsInstancedPoint3DSymbolHandler::material( const QgsPoin effect->addParameter( paramInst ); effect->addParameter( paramInstNormal ); - symbol.material()->addParametersToEffect( effect ); + symbol->material()->addParametersToEffect( effect ); Qt3DRender::QMaterial *material = new Qt3DRender::QMaterial; material->setEffect( effect ); @@ -213,7 +214,7 @@ Qt3DRender::QMaterial *QgsInstancedPoint3DSymbolHandler::material( const QgsPoin return material; } -Qt3DRender::QGeometryRenderer *QgsInstancedPoint3DSymbolHandler::renderer( const QgsPoint3DSymbol &symbol, const QVector &positions ) +Qt3DRender::QGeometryRenderer *QgsInstancedPoint3DSymbolHandler::renderer( const QgsPoint3DSymbol *symbol, const QVector &positions ) { int count = positions.count(); int byteCount = positions.count() * sizeof( QVector3D ); @@ -239,7 +240,7 @@ Qt3DRender::QGeometryRenderer *QgsInstancedPoint3DSymbolHandler::renderer( const instanceDataAttribute->setCount( count ); instanceDataAttribute->setByteStride( 3 * sizeof( float ) ); - Qt3DRender::QGeometry *geometry = symbolGeometry( symbol.shape(), symbol.shapeProperties() ); + Qt3DRender::QGeometry *geometry = symbolGeometry( symbol->shape(), symbol->shapeProperties() ); geometry->addAttribute( instanceDataAttribute ); geometry->setBoundingVolumePositionAttribute( instanceDataAttribute ); @@ -341,8 +342,9 @@ Qt3DRender::QGeometry *QgsInstancedPoint3DSymbolHandler::symbolGeometry( QgsPoin class QgsModelPoint3DSymbolHandler : public QgsFeature3DHandler { public: - QgsModelPoint3DSymbolHandler( const QgsPoint3DSymbol &symbol, const QgsFeatureIds &selectedIds ) - : mSymbol( symbol ), mSelectedIds( selectedIds ) {} + QgsModelPoint3DSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( static_cast< QgsPoint3DSymbol * >( symbol->clone() ) ) + , mSelectedIds( selectedIds ) {} bool prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) override; void processFeature( QgsFeature &feature, const Qgs3DRenderContext &context ) override; @@ -350,9 +352,9 @@ class QgsModelPoint3DSymbolHandler : public QgsFeature3DHandler private: - static void addSceneEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol &symbol, Qt3DCore::QEntity *parent ); - static void addMeshEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol &symbol, Qt3DCore::QEntity *parent, bool are_selected ); - static Qt3DCore::QTransform *transform( QVector3D position, const QgsPoint3DSymbol &symbol ); + static void addSceneEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent ); + static void addMeshEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent, bool are_selected ); + static Qt3DCore::QTransform *transform( QVector3D position, const QgsPoint3DSymbol *symbol ); //! temporary data we will pass to the tessellator struct PointData @@ -363,7 +365,7 @@ class QgsModelPoint3DSymbolHandler : public QgsFeature3DHandler void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected ); // input specific for this class - const QgsPoint3DSymbol &mSymbol; + std::unique_ptr< QgsPoint3DSymbol > mSymbol; // inputs - generic QgsFeatureIds mSelectedIds; @@ -386,7 +388,7 @@ void QgsModelPoint3DSymbolHandler::processFeature( QgsFeature &feature, const Qg if ( feature.geometry().isNull() ) return; - Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol.altitudeClamping(), out.positions ); + Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol->altitudeClamping(), out.positions ); } void QgsModelPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) @@ -398,7 +400,7 @@ void QgsModelPoint3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qg updateZRangeFromPositions( outSelected.positions ); // the elevation offset is applied separately in QTransform added to sub-entities - float symbolHeight = mSymbol.transform().data()[13]; + float symbolHeight = mSymbol->transform().data()[13]; mZMin += symbolHeight; mZMax += symbolHeight; } @@ -407,29 +409,29 @@ void QgsModelPoint3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const { if ( selected ) { - addMeshEntities( context.map(), out.positions, mSymbol, parent, true ); + addMeshEntities( context.map(), out.positions, mSymbol.get(), parent, true ); } else { - if ( mSymbol.shapeProperties()[QStringLiteral( "overwriteMaterial" )].toBool() ) + if ( mSymbol->shapeProperties()[QStringLiteral( "overwriteMaterial" )].toBool() ) { - addMeshEntities( context.map(), out.positions, mSymbol, parent, false ); + addMeshEntities( context.map(), out.positions, mSymbol.get(), parent, false ); } else { - addSceneEntities( context.map(), out.positions, mSymbol, parent ); + addSceneEntities( context.map(), out.positions, mSymbol.get(), parent ); } } } -void QgsModelPoint3DSymbolHandler::addSceneEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol &symbol, Qt3DCore::QEntity *parent ) +void QgsModelPoint3DSymbolHandler::addSceneEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent ) { Q_UNUSED( map ) for ( const QVector3D &position : positions ) { - const QString source = QgsApplication::instance()->sourceCache()->localFilePath( symbol.shapeProperties()[QStringLiteral( "model" )].toString() ); + const QString source = QgsApplication::instance()->sourceCache()->localFilePath( symbol->shapeProperties()[QStringLiteral( "model" )].toString() ); // if the source is remote, the Qgs3DMapScene will take care of refreshing this 3D symbol when the source is fetched if ( !source.isEmpty() ) { @@ -450,18 +452,18 @@ void QgsModelPoint3DSymbolHandler::addSceneEntities( const Qgs3DMapSettings &map } } -void QgsModelPoint3DSymbolHandler::addMeshEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol &symbol, Qt3DCore::QEntity *parent, bool are_selected ) +void QgsModelPoint3DSymbolHandler::addMeshEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent, bool are_selected ) { // build the default material QgsMaterialContext materialContext; materialContext.setIsSelected( are_selected ); materialContext.setSelectionColor( map.selectionColor() ); - Qt3DRender::QMaterial *mat = symbol.material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext ); + Qt3DRender::QMaterial *mat = symbol->material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext ); // get nodes for ( const QVector3D &position : positions ) { - const QString source = QgsApplication::instance()->sourceCache()->localFilePath( symbol.shapeProperties()[QStringLiteral( "model" )].toString() ); + const QString source = QgsApplication::instance()->sourceCache()->localFilePath( symbol->shapeProperties()[QStringLiteral( "model" )].toString() ); if ( !source.isEmpty() ) { // build the entity @@ -482,10 +484,10 @@ void QgsModelPoint3DSymbolHandler::addMeshEntities( const Qgs3DMapSettings &map, } } -Qt3DCore::QTransform *QgsModelPoint3DSymbolHandler::transform( QVector3D position, const QgsPoint3DSymbol &symbol ) +Qt3DCore::QTransform *QgsModelPoint3DSymbolHandler::transform( QVector3D position, const QgsPoint3DSymbol *symbol ) { Qt3DCore::QTransform *tr = new Qt3DCore::QTransform; - tr->setMatrix( symbol.transform() ); + tr->setMatrix( symbol->transform() ); tr->setTranslation( position + tr->translation() ); return tr; } @@ -497,8 +499,9 @@ Qt3DCore::QTransform *QgsModelPoint3DSymbolHandler::transform( QVector3D positio class QgsPoint3DBillboardSymbolHandler : public QgsFeature3DHandler { public: - QgsPoint3DBillboardSymbolHandler( const QgsPoint3DSymbol &symbol, const QgsFeatureIds &selectedIds ) - : mSymbol( symbol ), mSelectedIds( selectedIds ) {} + QgsPoint3DBillboardSymbolHandler( const QgsPoint3DSymbol *symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( static_cast< QgsPoint3DSymbol * >( symbol->clone() ) ) + , mSelectedIds( selectedIds ) {} bool prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) override; void processFeature( QgsFeature &feature, const Qgs3DRenderContext &context ) override; @@ -515,7 +518,7 @@ class QgsPoint3DBillboardSymbolHandler : public QgsFeature3DHandler void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PointData &out, bool selected ); // input specific for this class - const QgsPoint3DSymbol &mSymbol; + std::unique_ptr< QgsPoint3DSymbol > mSymbol; // inputs - generic QgsFeatureIds mSelectedIds; @@ -538,7 +541,7 @@ void QgsPoint3DBillboardSymbolHandler::processFeature( QgsFeature &feature, cons if ( feature.geometry().isNull() ) return; - Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol.altitudeClamping(), out.positions ); + Qgs3DUtils::extractPointPositions( feature, context.map(), mSymbol->altitudeClamping(), out.positions ); } void QgsPoint3DBillboardSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context ) @@ -550,7 +553,7 @@ void QgsPoint3DBillboardSymbolHandler::finalize( Qt3DCore::QEntity *parent, cons updateZRangeFromPositions( outSelected.positions ); // the elevation offset is applied externally through a QTransform of QEntity so let's account for it - float billboardHeight = mSymbol.transform().data()[13]; + float billboardHeight = mSymbol->transform().data()[13]; mZMin += billboardHeight; mZMax += billboardHeight; } @@ -569,7 +572,7 @@ void QgsPoint3DBillboardSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, co // Billboard Material QgsPoint3DBillboardMaterial *billboardMaterial = new QgsPoint3DBillboardMaterial(); - QgsMarkerSymbol *symbol = mSymbol.billboardSymbol(); + QgsMarkerSymbol *symbol = mSymbol->billboardSymbol(); if ( symbol ) { @@ -582,7 +585,7 @@ void QgsPoint3DBillboardSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, co // Billboard Transform Qt3DCore::QTransform *billboardTransform = new Qt3DCore::QTransform(); - billboardTransform->setMatrix( mSymbol.billboardTransform() ); + billboardTransform->setMatrix( mSymbol->billboardTransform() ); // Build the entity Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; @@ -607,12 +610,12 @@ namespace Qgs3DSymbolImpl return nullptr; if ( pointSymbol->shape() == QgsPoint3DSymbol::Model ) - return new QgsModelPoint3DSymbolHandler( *pointSymbol, layer->selectedFeatureIds() ); + return new QgsModelPoint3DSymbolHandler( pointSymbol, layer->selectedFeatureIds() ); // Add proper handler for billboard else if ( pointSymbol->shape() == QgsPoint3DSymbol::Billboard ) - return new QgsPoint3DBillboardSymbolHandler( *pointSymbol, layer->selectedFeatureIds() ); + return new QgsPoint3DBillboardSymbolHandler( pointSymbol, layer->selectedFeatureIds() ); else - return new QgsInstancedPoint3DSymbolHandler( *pointSymbol, layer->selectedFeatureIds() ); + return new QgsInstancedPoint3DSymbolHandler( pointSymbol, layer->selectedFeatureIds() ); } Qt3DCore::QEntity *entityForPoint3DSymbol( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPoint3DSymbol &symbol ) diff --git a/src/3d/symbols/qgspolygon3dsymbol_p.cpp b/src/3d/symbols/qgspolygon3dsymbol_p.cpp index 0dbc975bd76d..90bd06fba85f 100644 --- a/src/3d/symbols/qgspolygon3dsymbol_p.cpp +++ b/src/3d/symbols/qgspolygon3dsymbol_p.cpp @@ -50,8 +50,9 @@ class QgsPolygon3DSymbolHandler : public QgsFeature3DHandler { public: - QgsPolygon3DSymbolHandler( const QgsPolygon3DSymbol &symbol, const QgsFeatureIds &selectedIds ) - : mSymbol( symbol ), mSelectedIds( selectedIds ) {} + QgsPolygon3DSymbolHandler( const QgsPolygon3DSymbol *symbol, const QgsFeatureIds &selectedIds ) + : mSymbol( static_cast< QgsPolygon3DSymbol *>( symbol->clone() ) ) + , mSelectedIds( selectedIds ) {} bool prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) override; void processFeature( QgsFeature &feature, const Qgs3DRenderContext &context ) override; @@ -69,10 +70,10 @@ class QgsPolygon3DSymbolHandler : public QgsFeature3DHandler void processPolygon( QgsPolygon *polyClone, QgsFeatureId fid, float height, float extrusionHeight, const Qgs3DRenderContext &context, PolygonData &out ); void makeEntity( Qt3DCore::QEntity *parent, const Qgs3DRenderContext &context, PolygonData &out, bool selected ); - Qt3DRender::QMaterial *material( const QgsPolygon3DSymbol &symbol, bool isSelected, const Qgs3DRenderContext &context ) const; + Qt3DRender::QMaterial *material( const QgsPolygon3DSymbol *symbol, bool isSelected, const Qgs3DRenderContext &context ) const; // input specific for this class - const QgsPolygon3DSymbol &mSymbol; + std::unique_ptr< QgsPolygon3DSymbol > mSymbol; // inputs - generic QgsFeatureIds mSelectedIds; @@ -87,28 +88,28 @@ class QgsPolygon3DSymbolHandler : public QgsFeature3DHandler bool QgsPolygon3DSymbolHandler::prepare( const Qgs3DRenderContext &context, QSet &attributeNames ) { outEdges.withAdjacency = true; - outEdges.init( mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), 0, &context.map() ); + outEdges.init( mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), 0, &context.map() ); - const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol.material() ); + const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol->material() ); - outNormal.tessellator.reset( new QgsTessellator( context.map().origin().x(), context.map().origin().y(), true, mSymbol.invertNormals(), mSymbol.addBackFaces(), false, + outNormal.tessellator.reset( new QgsTessellator( context.map().origin().x(), context.map().origin().y(), true, mSymbol->invertNormals(), mSymbol->addBackFaces(), false, texturedMaterialSettings && texturedMaterialSettings->requiresTextureCoordinates(), - mSymbol.renderedFacade(), + mSymbol->renderedFacade(), texturedMaterialSettings ? texturedMaterialSettings->textureRotation() : 0 ) ); - outSelected.tessellator.reset( new QgsTessellator( context.map().origin().x(), context.map().origin().y(), true, mSymbol.invertNormals(), - mSymbol.addBackFaces(), false, + outSelected.tessellator.reset( new QgsTessellator( context.map().origin().x(), context.map().origin().y(), true, mSymbol->invertNormals(), + mSymbol->addBackFaces(), false, texturedMaterialSettings && texturedMaterialSettings->requiresTextureCoordinates(), - mSymbol.renderedFacade(), + mSymbol->renderedFacade(), texturedMaterialSettings ? texturedMaterialSettings->textureRotation() : 0 ) ); - QSet attrs = mSymbol.dataDefinedProperties().referencedFields( context.expressionContext() ); + QSet attrs = mSymbol->dataDefinedProperties().referencedFields( context.expressionContext() ); attributeNames.unite( attrs ); return true; } void QgsPolygon3DSymbolHandler::processPolygon( QgsPolygon *polyClone, QgsFeatureId fid, float height, float extrusionHeight, const Qgs3DRenderContext &context, PolygonData &out ) { - if ( mSymbol.edgesEnabled() ) + if ( mSymbol->edgesEnabled() ) { // add edges before the polygon gets the Z values modified because addLineString() does its own altitude handling outEdges.addLineString( *static_cast( polyClone->exteriorRing() ), height ); @@ -130,7 +131,7 @@ void QgsPolygon3DSymbolHandler::processPolygon( QgsPolygon *polyClone, QgsFeatur } } - Qgs3DUtils::clampAltitudes( polyClone, mSymbol.altitudeClamping(), mSymbol.altitudeBinding(), height, context.map() ); + Qgs3DUtils::clampAltitudes( polyClone, mSymbol->altitudeClamping(), mSymbol->altitudeBinding(), height, context.map() ); Q_ASSERT( out.tessellator->dataVerticesCount() % 3 == 0 ); uint startingTriangleIndex = static_cast( out.tessellator->dataVerticesCount() / 3 ); @@ -155,12 +156,12 @@ void QgsPolygon3DSymbolHandler::processFeature( QgsFeature &f, const Qgs3DRender const QgsAbstractGeometry *g = geom.constGet(); - const QgsPropertyCollection &ddp = mSymbol.dataDefinedProperties(); + const QgsPropertyCollection &ddp = mSymbol->dataDefinedProperties(); bool hasDDHeight = ddp.isActive( QgsAbstract3DSymbol::PropertyHeight ); bool hasDDExtrusion = ddp.isActive( QgsAbstract3DSymbol::PropertyExtrusionHeight ); - float height = mSymbol.height(); - float extrusionHeight = mSymbol.extrusionHeight(); + float height = mSymbol->height(); + float extrusionHeight = mSymbol->extrusionHeight(); if ( hasDDHeight ) height = ddp.valueAsDouble( QgsAbstract3DSymbol::PropertyHeight, context.expressionContext(), height ); if ( hasDDExtrusion ) @@ -206,11 +207,11 @@ void QgsPolygon3DSymbolHandler::finalize( Qt3DCore::QEntity *parent, const Qgs3D mZMax = std::max( outNormal.tessellator->zMaximum(), outSelected.tessellator->zMaximum() ); // add entity for edges - if ( mSymbol.edgesEnabled() && !outEdges.indexes.isEmpty() ) + if ( mSymbol->edgesEnabled() && !outEdges.indexes.isEmpty() ) { QgsLineMaterial *mat = new QgsLineMaterial; - mat->setLineColor( mSymbol.edgeColor() ); - mat->setLineWidth( mSymbol.edgeWidth() ); + mat->setLineColor( mSymbol->edgeColor() ); + mat->setLineWidth( mSymbol->edgeWidth() ); Qt3DCore::QEntity *entity = new Qt3DCore::QEntity; @@ -235,15 +236,15 @@ void QgsPolygon3DSymbolHandler::makeEntity( Qt3DCore::QEntity *parent, const Qgs if ( out.tessellator->dataVerticesCount() == 0 ) return; // nothing to show - no need to create the entity - Qt3DRender::QMaterial *mat = material( mSymbol, selected, context ); + Qt3DRender::QMaterial *mat = material( mSymbol.get(), selected, context ); // extract vertex buffer data from tessellator QByteArray data( ( const char * )out.tessellator->data().constData(), out.tessellator->data().count() * sizeof( float ) ); int nVerts = data.count() / out.tessellator->stride(); - const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol.material() ); + const QgsPhongTexturedMaterialSettings *texturedMaterialSettings = dynamic_cast< const QgsPhongTexturedMaterialSettings * >( mSymbol->material() ); - QgsTessellatedPolygonGeometry *geometry = new QgsTessellatedPolygonGeometry( true, mSymbol.invertNormals(), mSymbol.addBackFaces(), + QgsTessellatedPolygonGeometry *geometry = new QgsTessellatedPolygonGeometry( true, mSymbol->invertNormals(), mSymbol->addBackFaces(), texturedMaterialSettings && texturedMaterialSettings->requiresTextureCoordinates() ); geometry->setData( data, nVerts, out.triangleIndexFids, out.triangleIndexStartingIndices ); @@ -291,14 +292,14 @@ static void applyCullingMode( Qgs3DTypes::CullingMode cullingMode, Qt3DRender::Q } } -Qt3DRender::QMaterial *QgsPolygon3DSymbolHandler::material( const QgsPolygon3DSymbol &symbol, bool isSelected, const Qgs3DRenderContext &context ) const +Qt3DRender::QMaterial *QgsPolygon3DSymbolHandler::material( const QgsPolygon3DSymbol *symbol, bool isSelected, const Qgs3DRenderContext &context ) const { QgsMaterialContext materialContext; materialContext.setIsSelected( isSelected ); materialContext.setSelectionColor( context.map().selectionColor() ); - Qt3DRender::QMaterial *material = symbol.material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext ); - applyCullingMode( symbol.cullingMode(), material ); + Qt3DRender::QMaterial *material = symbol->material()->toMaterial( QgsMaterialSettingsRenderingTechnique::Triangles, materialContext ); + applyCullingMode( symbol->cullingMode(), material ); return material; } @@ -316,7 +317,7 @@ namespace Qgs3DSymbolImpl if ( !polygonSymbol ) return nullptr; - return new QgsPolygon3DSymbolHandler( *polygonSymbol, layer->selectedFeatureIds() ); + return new QgsPolygon3DSymbolHandler( polygonSymbol, layer->selectedFeatureIds() ); } Qt3DCore::QEntity *entityForPolygon3DSymbol( const Qgs3DMapSettings &map, QgsVectorLayer *layer, const QgsPolygon3DSymbol &symbol ) From a3ee8c156513b40084c0c5f8cd50f51c37048cce Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Fri, 21 Aug 2020 15:40:41 +1000 Subject: [PATCH 2/2] Fix memory leak when no model point positions are available --- src/3d/symbols/qgspoint3dsymbol_p.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/3d/symbols/qgspoint3dsymbol_p.cpp b/src/3d/symbols/qgspoint3dsymbol_p.cpp index 2aa34e034b57..7430dcf45df4 100644 --- a/src/3d/symbols/qgspoint3dsymbol_p.cpp +++ b/src/3d/symbols/qgspoint3dsymbol_p.cpp @@ -454,6 +454,9 @@ void QgsModelPoint3DSymbolHandler::addSceneEntities( const Qgs3DMapSettings &map void QgsModelPoint3DSymbolHandler::addMeshEntities( const Qgs3DMapSettings &map, const QVector &positions, const QgsPoint3DSymbol *symbol, Qt3DCore::QEntity *parent, bool are_selected ) { + if ( positions.empty() ) + return; + // build the default material QgsMaterialContext materialContext; materialContext.setIsSelected( are_selected );