diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-08-22 11:25:57 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2018-08-23 17:33:46 +0000 |
commit | 87a8a864327da7c64232ab44881310133107d29b (patch) | |
tree | 79184da6ecf9b15bd42cb8436bec5d92f1b4e1e9 | |
parent | 10b0cabebd9f07725191f463e807ea815d68ceb2 (diff) |
Make ReferencedMaterial more dynamic
The ill-named ReferencedMaterial lacked quite some of the dynamic
property handling, meaning it was not possible to change the
referencedmaterial property to a different target material instance.
This is now corrected.
Therefore, the following console command sequence generates a green
sphere, where the Model's child is a ReferencedMaterial that points to a
DefaultMaterial living somewhere else, not associated (in the object tree
at least) with any model.
object(mm,mm,DefaultMaterial,Layer,Slide1)
object(kk,kk,Model,Layer,Slide1)
set(kk,sourcepath,#Sphere)
object(rm,rm,ReferencedMaterial,kk,Slide1)
set(rm,referencedmaterial,#mm)
set(mm, diffuse, 0 1 0)
Note that we continue with the assumption that a ReferencedMaterial
cannot reference another ReferencedMaterial, meaning the target is
always a default or custom material (or unset).
Change-Id: I2cebb9689167f0ecb409d1bf73ee3df2364f3e04
Reviewed-by: Christian Stromme <christian.stromme@qt.io>
-rw-r--r-- | src/runtime/q3dsscenemanager.cpp | 53 | ||||
-rw-r--r-- | src/runtime/q3dsscenemanager_p.h | 5 | ||||
-rw-r--r-- | src/runtime/q3dsuippresentation.cpp | 10 | ||||
-rw-r--r-- | src/runtime/q3dsuippresentation_p.h | 9 |
4 files changed, 74 insertions, 3 deletions
diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp index ea52921..ffef07c 100644 --- a/src/runtime/q3dsscenemanager.cpp +++ b/src/runtime/q3dsscenemanager.cpp @@ -3877,6 +3877,16 @@ void Q3DSSceneManager::initCustomMaterial(Q3DSCustomMaterialInstance *m) data->eventObserverIndex = m->addEventHandler(QString(), std::bind(&Q3DSSceneManager::handleEvent, this, std::placeholders::_1)); } +void Q3DSSceneManager::initReferencedMaterial(Q3DSReferencedMaterial *m) +{ + Q3DSReferencedMaterialAttached *data = new Q3DSReferencedMaterialAttached; + m->setAttached(data); + + data->propertyChangeObserverIndex = m->addPropertyChangeObserver( + std::bind(&Q3DSSceneManager::handlePropertyChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + data->eventObserverIndex = m->addEventHandler(QString(), std::bind(&Q3DSSceneManager::handleEvent, this, std::placeholders::_1)); +} + // Recursively builds the Qt3D scene for the given node tree under a layer. (or // sub-tree, when called in response to a dynamic scene change with DirtyNodeAdded). void Q3DSSceneManager::buildLayerScene(Q3DSGraphObject *obj, Q3DSLayerNode *layer3DS, Qt3DCore::QEntity *parent) @@ -3909,6 +3919,9 @@ void Q3DSSceneManager::buildLayerScene(Q3DSGraphObject *obj, Q3DSLayerNode *laye case Q3DSGraphObject::CustomMaterial: initCustomMaterial(static_cast<Q3DSCustomMaterialInstance *>(obj)); break; + case Q3DSGraphObject::ReferencedMaterial: + initReferencedMaterial(static_cast<Q3DSReferencedMaterial *>(obj)); + break; default: break; } @@ -4597,10 +4610,12 @@ void Q3DSSceneManager::rebuildModelSubMeshes(Q3DSModelNode *model3DS) sm.entity->addComponent(mesh); sm.material = material; sm.resolvedMaterial = material; - // follow the reference for ReferencedMaterial + // follow the reference for ReferencedMaterial (which is more like a referencING material...) if (sm.material->type() == Q3DSGraphObject::ReferencedMaterial) { Q3DSReferencedMaterial *matRef = static_cast<Q3DSReferencedMaterial *>(sm.material); sm.referencingMaterial = matRef; + // only if set (i.e. non-null), keep pointing to itself otherwise + // (resolvedMaterial must not be null no matter what) if (matRef->referencedMaterial()) sm.resolvedMaterial = matRef->referencedMaterial(); } @@ -4673,7 +4688,7 @@ void Q3DSSceneManager::buildModelMaterial(Q3DSModelNode *model3DS) } for (Q3DSModelAttached::SubMesh &sm : modelData->subMeshes) { - if (sm.resolvedMaterial && !sm.materialComponent) { + if (sm.resolvedMaterial && !sm.materialComponent && sm.resolvedMaterial->type() != Q3DSGraphObject::ReferencedMaterial) { Q_ASSERT(sm.resolvedMaterial->attached()); if (sm.resolvedMaterial->type() == Q3DSGraphObject::DefaultMaterial) { Q3DSDefaultMaterial *defaultMaterial = static_cast<Q3DSDefaultMaterial *>(sm.resolvedMaterial); @@ -7041,6 +7056,12 @@ void Q3DSSceneManager::handlePropertyChange(Q3DSGraphObject *obj, const QSet<QSt data->frameChangeFlags |= changeFlags; } break; + case Q3DSGraphObject::ReferencedMaterial: + { + data->frameDirty |= Q3DSGraphObjectAttached::ReferencedMaterialDirty; + data->frameChangeFlags |= changeFlags; + } + break; case Q3DSGraphObject::Effect: { data->frameDirty |= Q3DSGraphObjectAttached::EffectDirty; @@ -7346,6 +7367,7 @@ void Q3DSSceneManager::prepareNextFrame() static void markLayerForObjectDirty(Q3DSGraphObject *obj) { auto findLayersForMat = [](Q3DSGraphObject *obj) { + Q_ASSERT(obj->type() == Q3DSGraphObject::DefaultMaterial || obj->type() == Q3DSGraphObject::CustomMaterial); QVector<Q3DSLayerNode *> layers; Q3DSMaterialAttached *data = static_cast<Q3DSMaterialAttached *>(obj->attached()); if (data) { @@ -7376,6 +7398,12 @@ static void markLayerForObjectDirty(Q3DSGraphObject *obj) } else if (obj->type() == Q3DSGraphObject::DefaultMaterial || obj->type() == Q3DSGraphObject::CustomMaterial) { for (Q3DSLayerNode *layer3DS : findLayersForMat(obj)) markLayerDirty(layer3DS); + } else if (obj->type() == Q3DSGraphObject::ReferencedMaterial) { + Q3DSGraphObject *targetMat = static_cast<Q3DSReferencedMaterial *>(obj)->referencedMaterial(); + if (targetMat && targetMat->type() != Q3DSGraphObject::ReferencedMaterial) { + for (Q3DSLayerNode *layer3DS : findLayersForMat(targetMat)) + markLayerDirty(layer3DS); + } } else if (obj->type() == Q3DSGraphObject::Effect) { Q3DSEffectAttached *data = static_cast<Q3DSEffectAttached *>(obj->attached()); if (data && data->layer3DS) @@ -7540,6 +7568,27 @@ void Q3DSSceneManager::updateSubTreeRecursive(Q3DSGraphObject *obj) } } break; + case Q3DSGraphObject::ReferencedMaterial: + { + Q3DSReferencedMaterial *mat3DS = static_cast<Q3DSReferencedMaterial *>(obj); + Q3DSReferencedMaterialAttached *data = static_cast<Q3DSReferencedMaterialAttached *>(mat3DS->attached()); + if (data && (data->frameDirty & Q3DSGraphObjectAttached::ReferencedMaterialDirty)) { + const bool refChanges = data->frameChangeFlags & Q3DSReferencedMaterial::ReferenceChanges; + if (refChanges) { + mat3DS->resolveReferences(*m_presentation); + if (mat3DS->parent() && mat3DS->parent()->type() == Q3DSGraphObject::Model) { + Q3DSModelNode *model3DS = static_cast<Q3DSModelNode *>(mat3DS->parent()); + qCDebug(lcPerf, "Rebuilding submeshes for %s due to material reference change", + model3DS->id().constData()); + rebuildModelSubMeshes(model3DS); + rebuildModelMaterial(model3DS); + } + } + m_wasDirty = true; + markLayerForObjectDirty(mat3DS); + } + } + break; case Q3DSGraphObject::Effect: { Q3DSEffectInstance *eff3DS = static_cast<Q3DSEffectInstance *>(obj); diff --git a/src/runtime/q3dsscenemanager_p.h b/src/runtime/q3dsscenemanager_p.h index 84c9cb9..4b2f4cd 100644 --- a/src/runtime/q3dsscenemanager_p.h +++ b/src/runtime/q3dsscenemanager_p.h @@ -567,6 +567,10 @@ public: Qt3DRender::QParameter *lightProbeOffset = nullptr; }; +class Q3DSReferencedMaterialAttached : public Q3DSGraphObjectAttached +{ +}; + class Q3DSEffectAttached : public Q3DSGraphObjectAttached { public: @@ -854,6 +858,7 @@ private: void initImage(Q3DSImage *image); void initDefaultMaterial(Q3DSDefaultMaterial *m); void initCustomMaterial(Q3DSCustomMaterialInstance *m); + void initReferencedMaterial(Q3DSReferencedMaterial *m); void buildLayerQuadEntity(Q3DSLayerNode *layer3DS, Qt3DCore::QEntity *parentEntity, Qt3DRender::QLayer *tag, BuildLayerQuadFlags flags, int layerDepth = 0); diff --git a/src/runtime/q3dsuippresentation.cpp b/src/runtime/q3dsuippresentation.cpp index b475c2a..1c32d94 100644 --- a/src/runtime/q3dsuippresentation.cpp +++ b/src/runtime/q3dsuippresentation.cpp @@ -2103,6 +2103,16 @@ void Q3DSReferencedMaterial::resolveReferences(Q3DSUipPresentation &pres) resolveRef(m_lightProbe_unresolved, Q3DSGraphObject::Image, &m_lightProbe, pres); } +int Q3DSReferencedMaterial::mapChangeFlags(const Q3DSPropertyChangeList &changeList) +{ + int changeFlags = Q3DSGraphObject::mapChangeFlags(changeList); + for (auto it = changeList.cbegin(), itEnd = changeList.cend(); it != itEnd; ++it) { + if (it->nameStr() == QStringLiteral("referencedmaterial")) + changeFlags |= ReferenceChanges; + } + return changeFlags; +} + Q3DSPropertyChange Q3DSReferencedMaterial::setReferencedMaterial(Q3DSGraphObject *v) { return createPropSetter(m_referencedMaterial, v, "referencedmaterial"); diff --git a/src/runtime/q3dsuippresentation_p.h b/src/runtime/q3dsuippresentation_p.h index adc8191..b6623e9 100644 --- a/src/runtime/q3dsuippresentation_p.h +++ b/src/runtime/q3dsuippresentation_p.h @@ -211,7 +211,8 @@ public: CustomMaterialDirty = 0x1000, EffectDirty = 0x2000, AliasDirty = 0x4000, - BehaviorDirty = 0x8000 + BehaviorDirty = 0x8000, + ReferencedMaterialDirty = 0x10000 }; Q_DECLARE_FLAGS(FrameDirtyFlags, FrameDirtyFlag) @@ -1763,6 +1764,7 @@ private: Q3DSImage *m_lightProbe = nullptr; }; +// this should have been named Q3DSReferencingMaterialInstance or something like that class Q3DSV_PRIVATE_EXPORT Q3DSReferencedMaterial : public Q3DSGraphObject { Q3DS_OBJECT @@ -1772,11 +1774,16 @@ class Q3DSV_PRIVATE_EXPORT Q3DSReferencedMaterial : public Q3DSGraphObject Q_PROPERTY(Q3DSImage * lightmapshadow READ lightmapShadowMap WRITE setLightmapShadowMap) Q_PROPERTY(Q3DSImage * iblprobe READ lightProbe WRITE setLightProbe) public: + enum ReferencedMaterialPropertyChanges { + ReferenceChanges = 1 << 0 + }; + Q3DSReferencedMaterial(); void setProperties(const QXmlStreamAttributes &attrs, PropSetFlags flags) override; void applyPropertyChanges(const Q3DSPropertyChangeList &changeList) override; void resolveReferences(Q3DSUipPresentation &pres) override; + int mapChangeFlags(const Q3DSPropertyChangeList &changeList) override; // Properties Q3DSGraphObject *referencedMaterial() const { return m_referencedMaterial; } |