diff options
Diffstat (limited to 'src/runtime/q3dsscenemanager.cpp')
-rw-r--r-- | src/runtime/q3dsscenemanager.cpp | 820 |
1 files changed, 514 insertions, 306 deletions
diff --git a/src/runtime/q3dsscenemanager.cpp b/src/runtime/q3dsscenemanager.cpp index 6c40962..77d4c61 100644 --- a/src/runtime/q3dsscenemanager.cpp +++ b/src/runtime/q3dsscenemanager.cpp @@ -47,6 +47,7 @@ #include "q3dslogging_p.h" #include "q3dsviewportsettings_p.h" #include "q3dstextmesh_p.h" +#include "q3dsimagemanager_p.h" #if QT_CONFIG(q3ds_profileui) #include "profileui/q3dsprofileui_p.h" #include "q3dsconsolecommands_p.h" @@ -58,6 +59,7 @@ #include <qmath.h> #include <QTextLayout> #include <QOpenGLContext> +#include <QTimer> #include <Qt3DCore/QEntity> #include <Qt3DCore/QTransform> @@ -447,7 +449,7 @@ static const int LAYER_CACHING_THRESHOLD = 4; */ -Q3DSSceneManager::Q3DSSceneManager() +Q3DSSceneManager::Q3DSSceneManager(ParentChildPairs *pairs) : m_gfxLimits(Q3DS::graphicsLimits()), m_matGen(new Q3DSDefaultMaterialGenerator), m_customMaterialGen(new Q3DSCustomMaterialGenerator), @@ -459,7 +461,8 @@ Q3DSSceneManager::Q3DSSceneManager() m_glyphCacheManager(nullptr), #endif m_profiler(new Q3DSProfiler), - m_inputManager(new Q3DSInputManager(this)) + m_inputManager(new Q3DSInputManager(this)), + m_pairs(pairs) { if (Q3DSSlideUtils::useDragonWings()) m_slidePlayer = new Q3DSSlidePlayerNg(this); @@ -648,7 +651,10 @@ void Q3DSSceneManager::uncacheLayers() void Q3DSSceneManager::prepareAnimators() { - m_slidePlayer->sceneReady(); + if (!m_animatorsInitialized) { + m_slidePlayer->sceneReady(); + m_animatorsInitialized = true; + } } QDebug operator<<(QDebug dbg, const Q3DSSceneManager::SceneBuilderParams &p) @@ -668,6 +674,8 @@ void Q3DSSceneManager::prepareEngineReset() delete m_slidePlayer; m_slidePlayer = nullptr; + m_animatorsInitialized = false; + #if QT_CONFIG(q3ds_profileui) if (m_profileUi) m_profileUi->releaseResources(); @@ -813,6 +821,10 @@ Q3DSSceneManager::Scene Q3DSSceneManager::buildScene(Q3DSUipPresentation *presen Qt3DLogic::QFrameAction *nodeUpdater = new Qt3DLogic::QFrameAction; m_frameUpdater = new Q3DSFrameUpdater(this); QObject::connect(nodeUpdater, &Qt3DLogic::QFrameAction::triggered, m_frameUpdater, &Q3DSFrameUpdater::frameAction); + if (m_pairs) { + m_pairs->addPair(m_rootEntity, nodeUpdater); + m_pairs->addPair(m_rootEntity, m_frameUpdater); + } m_rootEntity->addComponent(nodeUpdater); Qt3DRender::QRenderSettings *frameGraphComponent; @@ -854,14 +866,19 @@ Q3DSSceneManager::Scene Q3DSSceneManager::buildScene(Q3DSUipPresentation *presen // Do some pre-processing and early setup for some objects. initSubTree(m_scene); + m_engine->loadSlideResources(m_masterSlide, m_presentation); + m_engine->loadSlideResources(m_currentSlide, m_presentation); + // Build the (offscreen) Qt3D scene m_layerContainerFg = new Qt3DRender::QFrameGraphNode(frameGraphRoot); new Qt3DRender::QNoDraw(m_layerContainerFg); // in case there are no layers at all + Q3DSUipPresentation::forAllLayers(m_scene, [=](Q3DSLayerNode *layer3DS) { if (layer3DS->sourcePath().isEmpty()) buildLayer(layer3DS, m_layerContainerFg, m_outputPixelSize); else buildSubPresentationLayer(layer3DS, m_outputPixelSize); + }); // The Scene object may have non-layer children. @@ -874,7 +891,6 @@ Q3DSSceneManager::Scene Q3DSSceneManager::buildScene(Q3DSUipPresentation *presen // Onscreen (or not) compositor (still offscreen when this is a subpresentation) buildCompositor(frameGraphRoot, m_rootEntity); - // Profiling UI (main presentation only) #if QT_CONFIG(q3ds_profileui) if (!m_flags.testFlag(SubPresentation)) { @@ -981,16 +997,17 @@ void Q3DSSceneManager::finalizeMainScene() #endif } -void Q3DSSceneManager::loadSubUipPresentation(Q3DSSubPresentation *sp) +void Q3DSSceneManager::finalizeSubpresentationLoading(Q3DSSubPresentation *sp) { - const QString id = sp->id; - Q_ASSERT(!id.isEmpty()); - *sp = m_engine->loadSubUipPresentation(sp->id); - sp->id = id; if (sp->colorTex && sp->sceneManager) { + for (int i = 0; i < m_subPresentations.size(); ++i) { + if (m_subPresentations[i].id == sp->id) { + m_subPresentations[i] = *sp; + break; + } + } sp->sceneManager->setSubPresentations(m_subPresentations); if (!m_inSetSubPresentations) { - sp->sceneManager->prepareAnimators(); m_profiler->registerSubPresentationProfiler(sp->sceneManager->m_profiler); Q3DSUipPresentation::forAllObjectsOfType(sp->sceneManager->m_presentation->scene(), Q3DSGraphObject::Behavior, @@ -1004,6 +1021,12 @@ void Q3DSSceneManager::loadSubUipPresentation(Q3DSSubPresentation *sp) } } +static bool isAsyncSubpresentationLoadingEnabled() +{ + static bool enabled = (qEnvironmentVariableIntValue("Q3DS_ASYNC_LOADING") & 8) > 0; + return enabled; +} + void Q3DSSceneManager::updateSubPresentationHosts() { for (Q3DSLayerNode *layer3DS : m_pendingSubPresLayers) { @@ -1012,25 +1035,39 @@ void Q3DSSceneManager::updateSubPresentationHosts() auto it = std::find_if(m_subPresentations.begin(), m_subPresentations.end(), [subPresId](const Q3DSSubPresentation &sp) { return sp.id == subPresId; }); if (it != m_subPresentations.end()) { - if (!it->colorTex) - loadSubUipPresentation(it); - if (it->colorTex) { - qCDebug(lcScene, "Directing subpresentation %s to layer %s", qPrintable(it->id), layer3DS->id().constData()); - Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer3DS->attached()); - layerData->eyeMono->layerTexture = it->colorTex; + + auto setSubpresentationTolayer = [this](Q3DSLayerNode *layer, Q3DSSubPresentation *sp){ + qCDebug(lcScene, "Directing subpresentation %s to layer %s", qPrintable(sp->id), layer->id().constData()); + Q3DSLayerAttached *layerData = static_cast<Q3DSLayerAttached *>(layer->attached()); + layerData->eyeMono->layerTexture = sp->colorTex; layerData->eyeMono->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeMono->layerTexture)); - layerData->eyeLeft->layerTexture = it->colorTex; - layerData->eyeRight->layerTexture = it->colorTex; + layerData->eyeLeft->layerTexture = sp->colorTex; + layerData->eyeRight->layerTexture = sp->colorTex; layerData->eyeLeft->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeLeft->layerTexture)); layerData->eyeRight->compositorSourceParam->setValue(QVariant::fromValue(layerData->eyeRight->layerTexture)); layerData->updateSubPresentationSize(); + }; + + if (!it->colorTex) { + if (isAsyncSubpresentationLoadingEnabled()) { + m_engine->loadSubUipPresentation(subPresId, [this, setSubpresentationTolayer]( + Q3DSSubPresentation *sp, Q3DSLayerNode *layer) { + finalizeSubpresentationLoading(sp); + setSubpresentationTolayer(layer, sp); + }, layer3DS); + } else { + *it = m_engine->loadSubUipPresentation(subPresId); + finalizeSubpresentationLoading(it); + setSubpresentationTolayer(layer3DS, it); + } + } else { + setSubpresentationTolayer(layer3DS, it); } } else { qCDebug(lcScene, "Subpresentation %s for layer %s not found", qPrintable(subPresId), layer3DS->id().constData()); } } - for (auto p : m_pendingSubPresImages) setImageTextureFromSubPresentation(p.first, p.second); @@ -1563,7 +1600,9 @@ void Q3DSSceneManager::buildLayer(Q3DSLayerNode *layer3DS, // Generate Qt3D material components. Q3DSUipPresentation::forAllModels(layer3DS->firstChild(), - [this](Q3DSModelNode *model3DS) { buildModelMaterial(model3DS); }, + [this](Q3DSModelNode *model3DS) { + buildModelMaterial(model3DS); + }, true); // include hidden ones too // Set up effects. @@ -2152,7 +2191,7 @@ void Q3DSSceneManager::setLayerProperties(Q3DSLayerNode *layer3DS) if (layer3DS->lightProbe()) { // initialize light probe parameters if necessary if (!data->iblProbeData.lightProbeTexture) { - data->iblProbeData.lightProbeTexture = Q3DSImageManager::instance().newTextureForImage( + data->iblProbeData.lightProbeTexture = Q3DSImageManager::instance().newReloadableTextureForImage( m_rootEntity, Q3DSImageManager::GenerateMipMapsForIBL, layer3DS->lightProbe()->id(), m_profiler, "iblProbe texture for image %s", layer3DS->lightProbe()->id().constData()); @@ -2175,59 +2214,75 @@ void Q3DSSceneManager::setLayerProperties(Q3DSLayerNode *layer3DS) // Update light probe parameter values // also sets min/mag and generates mipmaps - Q3DSImageManager::instance().setSource(data->iblProbeData.lightProbeTexture, - QUrl::fromLocalFile(layer3DS->lightProbe()->sourcePath()), - m_presentation->preferKtx()); - data->iblProbeData.lightProbeSampler->setValue(QVariant::fromValue(data->iblProbeData.lightProbeTexture)); + data->iblProbeData.lightProbeTexture->setSource(m_presentation->imageUrl( + layer3DS->lightProbe()->sourcePath())); + data->iblProbeData.lightProbeTexture->onLoad([](Qt3DRender::QAbstractTexture *texture, + Q3DSLayerNode *layer3DS) { + Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached()); + data->iblProbeData.lightProbeSampler->setValue(QVariant::fromValue(texture)); - Qt3DRender::QTextureWrapMode wrapMode; + Qt3DRender::QTextureWrapMode wrapMode; - switch (layer3DS->lightProbe()->horizontalTiling()) { - case Q3DSImage::Tiled: - wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); - break; - case Q3DSImage::Mirrored: - wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); - break; - default: - wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; - } + switch (layer3DS->lightProbe()->horizontalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } - switch (layer3DS->lightProbe()->verticalTiling()) { - case Q3DSImage::Tiled: - wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); - break; - case Q3DSImage::Mirrored: - wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); - break; - default: - wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; - } + switch (layer3DS->lightProbe()->verticalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } - Qt3DRender::QAbstractTexture *texture = data->iblProbeData.lightProbeTexture; - texture->setWrapMode(wrapMode); + texture->setWrapMode(wrapMode); - const QMatrix4x4 &textureTransform = layer3DS->lightProbe()->textureTransform(); - const float *m = textureTransform.constData(); + const QMatrix4x4 &textureTransform = layer3DS->lightProbe()->textureTransform(); + const float *m = textureTransform.constData(); - // offsets.w = max mip level - const QSize texSize = Q3DSImageManager::instance().size(texture); - float mipLevels = float(qCeil(qLog2(qMax(texSize.width(), texSize.height())))); - QVector4D offsets(m[12], m[13], 0.0f, mipLevels); - data->iblProbeData.lightProbeOffset->setValue(offsets); + const QSize texSize = Q3DSImageManager::instance().size(texture); + float mipLevels = float(qCeil(qLog2(qMax(texSize.width(), texSize.height())))); + QVector4D offsets(m[12], m[13], 0.0f, mipLevels); + data->iblProbeData.lightProbeOffset->setValue(offsets); + + QVector4D rotations(m[0], m[4], m[1], m[5]); + data->iblProbeData.lightProbeRotation->setValue(rotations); + }, layer3DS); + + data->iblProbeData.lightProbeTexture->onUnload([](Qt3DRender::QAbstractTexture *texture, + Q3DSLayerNode *layer3DS) { + Q_UNUSED(texture); + Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached()); + data->iblProbeData.lightProbeSampler->setValue({}); + QVector4D offsets(0.f, 0.f, 0.f, 0.f); + data->iblProbeData.lightProbeOffset->setValue(offsets); + + QVector4D rotations(0.f, 0.f, 0.f, 0.f); + data->iblProbeData.lightProbeRotation->setValue(rotations); + }, layer3DS); - QVector4D rotations(m[0], m[4], m[1], m[5]); - data->iblProbeData.lightProbeRotation->setValue(rotations); if (layer3DS->lightProbe2()) { // Initialize light probe 2 parameters if (!data->iblProbeData.lightProbe2Texture) { - data->iblProbeData.lightProbe2Texture = Q3DSImageManager::instance().newTextureForImage( + data->iblProbeData.lightProbe2Texture + = Q3DSImageManager::instance().newReloadableTextureForImage( m_rootEntity, Q3DSImageManager::GenerateMipMapsForIBL, layer3DS->lightProbe2()->id(), - m_profiler, "iblProbe2 texture for image %s", layer3DS->lightProbe2()->id().constData()); + m_profiler, "iblProbe2 texture for image %s", + layer3DS->lightProbe2()->id().constData()); } if (!data->iblProbeData.lightProbe2Sampler) { @@ -2238,22 +2293,63 @@ void Q3DSSceneManager::setLayerProperties(Q3DSLayerNode *layer3DS) // Update light probe 2 parameter values // also sets min/mag and generates mipmaps - Q3DSImageManager::instance().setSource(data->iblProbeData.lightProbe2Texture, - QUrl::fromLocalFile(layer3DS->lightProbe2()->sourcePath()), - m_presentation->preferKtx()); - data->iblProbeData.lightProbe2Sampler->setValue(QVariant::fromValue(data->iblProbeData.lightProbe2Texture)); + data->iblProbeData.lightProbe2Texture->setSource( + m_presentation->imageUrl(layer3DS->lightProbe2()->sourcePath())); + data->iblProbeData.lightProbe2Texture->onLoad([](Qt3DRender::QAbstractTexture *texture, + Q3DSLayerNode *layer3DS) { + Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached()); + data->iblProbeData.lightProbe2Sampler->setValue(QVariant::fromValue(texture)); + + Qt3DRender::QTextureWrapMode wrapMode; + + switch (layer3DS->lightProbe()->horizontalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } - data->iblProbeData.lightProbe2Texture->setWrapMode(wrapMode); + switch (layer3DS->lightProbe()->verticalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } - QVector4D probe2Props(layer3DS->probe2Window(), layer3DS->probe2Pos(), layer3DS->probe2Fade(), 1.0f); - data->iblProbeData.lightProbe2Properties->setValue(probe2Props); - const QMatrix4x4 &textureTransform = layer3DS->lightProbe2()->textureTransform(); - const float *m = textureTransform.constData(); - QVector4D probeProps(m[12], m[13], layer3DS->probeHorizon(), layer3DS->probeBright() * 0.01f); - data->iblProbeData.lightProbeProperties->setValue(probeProps); + texture->setWrapMode(wrapMode); + + QVector4D probe2Props(layer3DS->probe2Window(), layer3DS->probe2Pos(), + layer3DS->probe2Fade(), 1.0f); + data->iblProbeData.lightProbe2Properties->setValue(probe2Props); + const QMatrix4x4 &textureTransform = layer3DS->lightProbe2()->textureTransform(); + const float *m = textureTransform.constData(); + QVector4D probeProps(m[12], m[13], layer3DS->probeHorizon(), + layer3DS->probeBright() * 0.01f); + data->iblProbeData.lightProbeProperties->setValue(probeProps); + }, layer3DS); + data->iblProbeData.lightProbe2Texture->onUnload( + [](Qt3DRender::QAbstractTexture *texture, Q3DSLayerNode *layer3DS) { + Q_UNUSED(texture); + Q3DSLayerAttached *data = static_cast<Q3DSLayerAttached *>(layer3DS->attached()); + data->iblProbeData.lightProbe2Sampler->setValue({}); + data->iblProbeData.lightProbe2Properties->setValue({}); + data->iblProbeData.lightProbeProperties->setValue({}); + }, layer3DS); } else { data->iblProbeData.lightProbe2Properties->setValue(QVector4D(0.0f, 0.0f, 0.0f, 0.0f)); - data->iblProbeData.lightProbeProperties->setValue(QVector4D(0.0f, 0.0f, layer3DS->probeHorizon(), layer3DS->probeBright() * 0.01f)); + data->iblProbeData.lightProbeProperties->setValue( + QVector4D(0.0f, 0.0f, layer3DS->probeHorizon(), + layer3DS->probeBright() * 0.01f)); } } } @@ -4814,7 +4910,8 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN data->entity->setObjectName(QObject::tr("top level text %1").arg(QString::fromUtf8(text3DS->id()))); #if QT_VERSION >= QT_VERSION_CHECK(5,12,2) - if (shouldDistanceFieldRender) { + bool useDistanceFields = shouldDistanceFieldRender && text3DS->wordWrap() != Q3DSTextNode::Clip; + if (useDistanceFields) { data->distanceFieldText = true; data->dropShadow = text3DS->shadow(); QVector2D boundingBox = text3DS->boundingBox(); @@ -5049,8 +5146,10 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN cache->processPendingGlyphs(); qreal fontPixelSize = glyphRun.rawFont().pixelSize(); - float shadowOffsetX = float(fontPixelSize) * text3DS->shadowOffsetX() / 1000.0f; - float shadowOffsetY = float(fontPixelSize) * text3DS->shadowOffsetY() / 1000.0f; + + float shadowOffsetX = float(cache->fontSize()) * text3DS->shadowOffsetX() / 1000.0f; + float shadowOffsetY = float(cache->fontSize()) * text3DS->shadowOffsetY() / 1000.0f; + qreal maxTexMargin = cache->distanceFieldRadius(); qreal fontScale = cache->fontScale(fontPixelSize); qreal margin = 2; @@ -5087,8 +5186,15 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN float cy2 = cy1 + float(metrics.height); if (text3DS->shadow()) { - cx2 += shadowOffsetX; - cy2 += shadowOffsetY; + if (shadowOffsetX < 0.0) + cx1 += shadowOffsetX * fontScale; + else + cx2 += shadowOffsetX * fontScale; + + if (shadowOffsetY < 0.0) + cy1 += shadowOffsetY * fontScale; + else + cy2 += shadowOffsetY * fontScale; } float tx1 = float(c.x + c.xMargin); @@ -5096,12 +5202,22 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN float ty1 = float(c.y + c.yMargin); float ty2 = ty1 + float(c.height); + // Preserve original bounds of glyphs + float ttx1 = tx1; + float tty1 = ty1; float ttx2 = tx2; float tty2 = ty2; if (text3DS->shadow()) { - tx2 += float(c.width) * shadowOffsetX / float(metrics.width); - ty2 += float(c.height) * shadowOffsetY / float(metrics.height); + if (shadowOffsetX < 0.0) + tx1 += float(c.width) * shadowOffsetX * fontScale / float(metrics.width); + else + tx2 += float(c.width) * shadowOffsetX * fontScale / float(metrics.width); + + if (shadowOffsetY < 0.0) + ty1 += float(c.height) * shadowOffsetY * fontScale / float(metrics.height); + else + ty2 += float(c.height) * shadowOffsetY * fontScale / float(metrics.height); } const QSGDistanceFieldGlyphCache::Texture *texture = cache->glyphTexture(glyphIndex); @@ -5127,8 +5243,8 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN vertexes.append(ty1); if (text3DS->shadow()) { - vertexes.append(tx1); - vertexes.append(ty1); + vertexes.append(ttx1); + vertexes.append(tty1); vertexes.append(ttx2); vertexes.append(tty2); } @@ -5140,8 +5256,8 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN vertexes.append(ty1); if (text3DS->shadow()) { - vertexes.append(tx1); - vertexes.append(ty1); + vertexes.append(ttx1); + vertexes.append(tty1); vertexes.append(ttx2); vertexes.append(tty2); } @@ -5153,8 +5269,8 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN vertexes.append(ty2); if (text3DS->shadow()) { - vertexes.append(tx1); - vertexes.append(ty1); + vertexes.append(ttx1); + vertexes.append(tty1); vertexes.append(ttx2); vertexes.append(tty2); } @@ -5166,8 +5282,8 @@ Qt3DCore::QEntity *Q3DSSceneManager::buildText(Q3DSTextNode *text3DS, Q3DSLayerN vertexes.append(ty2); if (text3DS->shadow()) { - vertexes.append(tx1); - vertexes.append(ty1); + vertexes.append(ttx1); + vertexes.append(tty1); vertexes.append(ttx2); vertexes.append(tty2); } @@ -5380,7 +5496,6 @@ void Q3DSSceneManager::updateText(Q3DSTextNode *text3DS, bool needsNewImage) Qt3DCore::QEntity *parentEntity = data->entity->parentEntity(); buildText(text3DS, data->layer3DS, parentEntity); - setNodeVisibility(text3DS, text3DS->flags().testFlag(Q3DSNode::Active)); } } else #endif @@ -5434,6 +5549,10 @@ void Q3DSSceneManager::updateText(Q3DSTextNode *text3DS, bool needsNewImage) if (textOffsetX != 0 || textOffsetY != 0) { QVector3D pos = text3DS->position(); + QVector3D rot = text3DS->rotation(); + // Apply text rotation to the translation amount + textOffsetX *= qCos(qDegreesToRadians(rot.y())); + textOffsetY *= qCos(qDegreesToRadians(rot.x())); data->transform->setTranslation(QVector3D(pos.x() + textOffsetX, pos.y() + textOffsetY, pos.z())); @@ -5757,7 +5876,6 @@ static void addShadowSsaoParams(Q3DSLayerAttached *layerData, QVector<Qt3DRender void Q3DSSceneManager::buildModelMaterial(Q3DSModelNode *model3DS) { // Scene building phase 2: all lights are known -> generate actual Qt3D materials - Q3DSModelAttached *modelData = static_cast<Q3DSModelAttached *>(model3DS->attached()); if (!modelData) return; @@ -5785,7 +5903,6 @@ void Q3DSSceneManager::buildModelMaterial(Q3DSModelNode *model3DS) // matters so much. lightNodes.resize(m_gfxLimits.maxLightsPerLayer); } - for (Q3DSModelAttached::SubMesh &sm : modelData->subMeshes) { if (sm.resolvedMaterial && !sm.materialComponent && sm.resolvedMaterial->type() != Q3DSGraphObject::ReferencedMaterial) { Q_ASSERT(sm.resolvedMaterial->attached()); @@ -5867,7 +5984,7 @@ void Q3DSSceneManager::buildModelMaterial(Q3DSModelNode *model3DS) param->setParent(layerData->entity); } - sm.materialComponent = m_matGen->generateMaterial(defaultMaterial, sm.referencingMaterial, params, lightNodes, modelData->layer3DS); + sm.materialComponent = m_matGen->generateMaterial(m_pairs, defaultMaterial, sm.referencingMaterial, params, lightNodes, modelData->layer3DS); sm.entity->addComponent(sm.materialComponent); } else if (sm.resolvedMaterial->type() == Q3DSGraphObject::CustomMaterial) { Q3DSCustomMaterialInstance *customMaterial = static_cast<Q3DSCustomMaterialInstance *>(sm.resolvedMaterial); @@ -5948,7 +6065,8 @@ void Q3DSSceneManager::buildModelMaterial(Q3DSModelNode *model3DS) if (!passes.isEmpty()) { // ### TODO support more than one pass auto pass = passes.first(); - sm.materialComponent = m_customMaterialGen->generateMaterial(customMaterial, sm.referencingMaterial, params, lightNodes, modelData->layer3DS, pass); + bool gles = m_gfxLimits.format.renderableType() == QSurfaceFormat::OpenGLES; + sm.materialComponent = m_customMaterialGen->generateMaterial(m_pairs, customMaterial, sm.referencingMaterial, params, lightNodes, modelData->layer3DS, pass, gles); } else { qCDebug(lcScene, "Custom material %s has no passes. Using dummy material. Object %s will not show.", customMaterial->id().constData(), model3DS->id().constData()); @@ -5972,6 +6090,7 @@ void Q3DSSceneManager::rebuildModelMaterial(Q3DSModelNode *model3DS) for (Q3DSModelAttached::SubMesh &sm : modelData->subMeshes) { if (sm.resolvedMaterial && sm.materialComponent) { qCDebug(lcPerf, "Rebuilding material for %s (entity %p)", model3DS->id().constData(), sm.entity); + delete sm.materialComponent; sm.materialComponent = nullptr; } @@ -6062,15 +6181,58 @@ void Q3DSSceneManager::prepareTextureParameters(Q3DSTextureParameters &texturePa textureParameters.size = new Qt3DRender::QParameter; textureParameters.size->setName(name + QLatin1String("_size")); - - textureParameters.texture = Q3DSImageManager::instance().newTextureForImage( - m_rootEntity, 0, image3DS->id(), m_profiler, "Texture for image %s", image3DS->id().constData()); } void Q3DSSceneManager::updateTextureParameters(Q3DSTextureParameters &textureParameters, Q3DSImage *image) { // note that this function is called frequently (whenever any Image parameter changes) + auto setupTexture = [](Q3DSTextureParameters &textureParameters, Q3DSImage *image) { + Qt3DRender::QTextureWrapMode wrapMode; + switch (image->horizontalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } + switch (image->verticalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } + + Qt3DRender::QAbstractTexture *texture + = textureParameters.sampler->value().value<Qt3DRender::QAbstractTexture *>(); + Q_ASSERT(texture || !image->subPresentation().isEmpty()); + if (!texture) + return; + + texture->setWrapMode(wrapMode); + // min/mag are already set at this point + + const QMatrix4x4 &textureTransform = image->textureTransform(); + const float *m = textureTransform.constData(); + + QVector3D offsets(m[12], m[13], image->hasPremultipliedAlpha() ? 1 : 0); + textureParameters.offsets->setValue(offsets); + + QVector4D rotations(m[0], m[4], m[1], m[5]); + textureParameters.rotations->setValue(rotations); + const QSize size = Q3DSImageManager::instance().size(texture); + textureParameters.size->setValue(QVector2D(size.width(), size.height())); + }; + if (!image->subPresentation().isEmpty()) { if (textureParameters.subPresId != image->subPresentation()) { textureParameters.subPresId = image->subPresentation(); @@ -6082,60 +6244,40 @@ void Q3DSSceneManager::updateTextureParameters(Q3DSTextureParameters &texturePar setImageTextureFromSubPresentation(textureParameters.sampler, image); } } + setupTexture(textureParameters, image); } else if (!image->sourcePath().isEmpty()) { - Q3DSImageManager::instance().setSource(textureParameters.texture, QUrl::fromLocalFile(image->sourcePath()), - m_presentation->preferKtx()); - textureParameters.sampler->setValue(QVariant::fromValue(textureParameters.texture)); + if (!textureParameters.textureSource) { + textureParameters.textureSource + = Q3DSImageManager::instance().newReloadableTextureForImage( + m_rootEntity, 0, image->id(), m_profiler, "Texture for image %s", + image->id().constData()); + } + textureParameters.textureSource->setSource(m_presentation->imageUrl(image->sourcePath())); + textureParameters.textureSource->onLoad( + [setupTexture](Qt3DRender::QAbstractTexture *texture, + Q3DSTextureParameters *param, Q3DSImage *image) { + param->sampler->setValue(QVariant::fromValue(texture)); + setupTexture(*param, image); + }, &textureParameters, image); + textureParameters.textureSource->onUnload([](Qt3DRender::QAbstractTexture *texture, + Q3DSTextureParameters *param) { + Q_UNUSED(texture); + param->sampler->setValue({}); + param->offsets->setValue({}); + param->rotations->setValue({}); + param->size->setValue({}); + }, &textureParameters); } else if (!image->customImage().isNull()) { + textureParameters.texture + = Q3DSImageManager::instance().newTextureForImage(m_rootEntity, 0, image->id(), + m_profiler, QStringLiteral("Texture for image %1").arg(image->id().constData())); Q3DSImageManager::instance().setSource(textureParameters.texture, image->customImage()); textureParameters.sampler->setValue(QVariant::fromValue(textureParameters.texture)); + setupTexture(textureParameters, image); } else { textureParameters.sampler->setValue(QVariant::fromValue(dummyTexture(image->id()))); + setupTexture(textureParameters, image); } - - Qt3DRender::QTextureWrapMode wrapMode; - switch (image->horizontalTiling()) { - case Q3DSImage::Tiled: - wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); - break; - case Q3DSImage::Mirrored: - wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); - break; - default: - wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; - } - switch (image->verticalTiling()) { - case Q3DSImage::Tiled: - wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); - break; - case Q3DSImage::Mirrored: - wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); - break; - default: - wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; - } - - Qt3DRender::QAbstractTexture *texture = textureParameters.sampler->value().value<Qt3DRender::QAbstractTexture *>(); - Q_ASSERT(texture || !image->subPresentation().isEmpty()); - if (!texture) - return; - - texture->setWrapMode(wrapMode); - // min/mag are already set at this point - - const QMatrix4x4 &textureTransform = image->textureTransform(); - const float *m = textureTransform.constData(); - - QVector3D offsets(m[12], m[13], image->hasPremultipliedAlpha() ? 1 : 0); - textureParameters.offsets->setValue(offsets); - - QVector4D rotations(m[0], m[4], m[1], m[5]); - textureParameters.rotations->setValue(rotations); - - const QSize size = Q3DSImageManager::instance().size(texture); - textureParameters.size->setValue(QVector2D(size.width(), size.height())); } void Q3DSSceneManager::setImageTextureFromSubPresentation(Qt3DRender::QParameter *sampler, Q3DSImage *image) @@ -6143,17 +6285,36 @@ void Q3DSSceneManager::setImageTextureFromSubPresentation(Qt3DRender::QParameter auto it = std::find_if(m_subPresentations.begin(), m_subPresentations.end(), [image](const Q3DSSubPresentation &sp) { return sp.id == image->subPresentation(); }); if (it != m_subPresentations.cend()) { - if (!it->colorTex) - loadSubUipPresentation(it); - qCDebug(lcScene, "Directing subpresentation %s to image %s", - qPrintable(image->subPresentation()), image->id().constData()); - sampler->setValue(QVariant::fromValue(it->colorTex)); - qCDebug(lcPerf, "Using a subpresentation as texture map (not as layer) makes layer caching in main presentation less efficient"); - // QML subpresentations will not have a scenemanager - if (it->sceneManager) - m_layerCacheDeps.insert(it->sceneManager); - else - m_hasQmlSubPresAsTextureMap = true; + auto handleSubpresentation = [this]( + Q3DSSubPresentation *sp, Qt3DRender::QParameter *sampler, Q3DSImage *image) { + qCDebug(lcScene, "Directing subpresentation %s to image %s", + qPrintable(image->subPresentation()), image->id().constData()); + sampler->setValue(QVariant::fromValue(sp->colorTex)); + qCDebug(lcPerf, "Using a subpresentation as texture map (not as layer) makes layer caching in main presentation less efficient"); + // QML subpresentations will not have a scenemanager + if (sp->sceneManager) + m_layerCacheDeps.insert(sp->sceneManager); + else + m_hasQmlSubPresAsTextureMap = true; + }; + if (!it->colorTex) { + if (isAsyncSubpresentationLoadingEnabled()) { + m_engine->loadSubUipPresentation(image->subPresentation(), + [this, handleSubpresentation] + (Q3DSSubPresentation *sp, + Qt3DRender::QParameter *sampler, + Q3DSImage *image) { + finalizeSubpresentationLoading(sp); + handleSubpresentation(sp, sampler, image); + }, sampler, image); + } else { + *it = m_engine->loadSubUipPresentation(image->subPresentation()); + finalizeSubpresentationLoading(it); + handleSubpresentation(it, sampler, image); + } + } else { + handleSubpresentation(it, sampler, image); + } } else { qCDebug(lcScene, "Subpresentation %s for image %s not found", qPrintable(image->subPresentation()), image->id().constData()); @@ -6389,10 +6550,11 @@ QVector<Qt3DRender::QParameter *> Q3DSSceneManager::prepareDefaultMaterial(Q3DSD iblOverrideImage = m->lightProbe(); if (iblOverrideImage) { if (!data->lightProbeOverrideTexture) { - data->lightProbeOverrideTexture = Q3DSImageManager::instance().newTextureForImage( + data->lightProbeOverrideTexture + = Q3DSImageManager::instance().newReloadableTextureForImage( m_rootEntity, Q3DSImageManager::GenerateMipMapsForIBL, - iblOverrideImage->id(), - m_profiler, "Texture for image %s", iblOverrideImage->id().constData()); + iblOverrideImage->id(), m_profiler, + "Texture for image %s", iblOverrideImage->id().constData()); data->lightProbeSampler = new Qt3DRender::QParameter; data->lightProbeSampler->setName(QLatin1String("light_probe")); @@ -6534,6 +6696,48 @@ void Q3DSSceneManager::updateDefaultMaterial(Q3DSDefaultMaterial *m, Q3DSReferen // IBL if (iblOverride) { + auto setupTexture = [](Qt3DRender::QAbstractTexture *texture, + Q3DSDefaultMaterialAttached *data, Q3DSImage *iblOverride) { + Qt3DRender::QTextureWrapMode wrapMode; + + switch (iblOverride->horizontalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } + + switch (iblOverride->verticalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } + + texture->setWrapMode(wrapMode); + + const QMatrix4x4 &textureTransform = iblOverride->textureTransform(); + const float *m = textureTransform.constData(); + + // offsets.w = max mip level + const QSize texSize = Q3DSImageManager::instance().size(texture); + float mipLevels = float(qCeil(qLog2(qMax(texSize.width(), texSize.height())))); + QVector4D offsets(m[12], m[13], 0.0f, mipLevels); + data->lightProbeOffset->setValue(offsets); + + QVector4D rotations(m[0], m[4], m[1], m[5]); + data->lightProbeRotation->setValue(rotations); + }; // also sets min/mag and generates mipmaps if (!iblOverride->subPresentation().isEmpty()) { if (m_subPresentations.isEmpty()) @@ -6541,52 +6745,23 @@ void Q3DSSceneManager::updateDefaultMaterial(Q3DSDefaultMaterial *m, Q3DSReferen else setImageTextureFromSubPresentation(data->lightProbeSampler, iblOverride); } else { - Q3DSImageManager::instance().setSource(data->lightProbeOverrideTexture, - QUrl::fromLocalFile(iblOverride->sourcePath()), - m_presentation->preferKtx()); - data->lightProbeSampler->setValue(QVariant::fromValue(data->lightProbeOverrideTexture)); - } - - Qt3DRender::QTextureWrapMode wrapMode; - - switch (iblOverride->horizontalTiling()) { - case Q3DSImage::Tiled: - wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); - break; - case Q3DSImage::Mirrored: - wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); - break; - default: - wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; - } - - switch (iblOverride->verticalTiling()) { - case Q3DSImage::Tiled: - wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); - break; - case Q3DSImage::Mirrored: - wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); - break; - default: - wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; + data->lightProbeOverrideTexture->setSource( + m_presentation->imageUrl(iblOverride->sourcePath())); + data->lightProbeOverrideTexture->onLoad([setupTexture]( + Qt3DRender::QAbstractTexture *texture, + Q3DSDefaultMaterialAttached *data, + Q3DSImage *iblOverride) { + data->lightProbeSampler->setValue(QVariant::fromValue(texture)); + setupTexture(texture, data, iblOverride); + }, data, iblOverride); + data->lightProbeOverrideTexture->onUnload([](Qt3DRender::QAbstractTexture *texture, + Q3DSDefaultMaterialAttached *data) { + Q_UNUSED(texture); + data->lightProbeSampler->setValue({}); + data->lightProbeOffset->setValue({}); + data->lightProbeRotation->setValue({}); + }, data); } - - Q_ASSERT(data->lightProbeOverrideTexture); - data->lightProbeOverrideTexture->setWrapMode(wrapMode); - - const QMatrix4x4 &textureTransform = iblOverride->textureTransform(); - const float *m = textureTransform.constData(); - - // offsets.w = max mip level - const QSize texSize = Q3DSImageManager::instance().size(data->lightProbeOverrideTexture); - float mipLevels = float(qCeil(qLog2(qMax(texSize.width(), texSize.height())))); - QVector4D offsets(m[12], m[13], 0.0f, mipLevels); - data->lightProbeOffset->setValue(offsets); - - QVector4D rotations(m[0], m[4], m[1], m[5]); - data->lightProbeRotation->setValue(rotations); } } @@ -6614,71 +6789,91 @@ static inline void forAllCustomProperties(Q3DSEffectInstance *eff3DS, CustomProp iterateCustomProperties(eff3DS->dynamicProperties(), eff3DS->effect()->properties(), callback); } -Qt3DRender::QAbstractTexture *Q3DSSceneManager::createCustomPropertyTexture(const Q3DSCustomPropertyParameter &p, const QByteArray &id) +void Q3DSSceneManager::createCustomPropertyTexture(Q3DSCustomPropertyParameter &p, + const QByteArray &id) { + // now override the defaults set in setSource() with whatever the metadata specifies + auto setupTexture = [](Q3DSCustomPropertyParameter *p, Qt3DRender::QAbstractTexture *texture) { + switch (p->meta.magFilterType) { + case Q3DSMaterial::Nearest: + texture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Nearest); + break; + default: + texture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); + break; + } + + switch (p->meta.minFilterType) { + case Q3DSMaterial::Nearest: + texture->setMinificationFilter(Qt3DRender::QAbstractTexture::Nearest); + break; + case Q3DSMaterial::Linear: + texture->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); + break; + case Q3DSMaterial::NearestMipmapNearest: + texture->setMinificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapNearest); + texture->setGenerateMipMaps(true); + break; + case Q3DSMaterial::NearestMipmapLinear: + texture->setMinificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapLinear); + texture->setGenerateMipMaps(true); + break; + case Q3DSMaterial::LinearMipmapNearest: + texture->setMinificationFilter(Qt3DRender::QAbstractTexture::LinearMipMapNearest); + texture->setGenerateMipMaps(true); + break; + default: + texture->setMinificationFilter(Qt3DRender::QAbstractTexture::LinearMipMapLinear); + texture->setGenerateMipMaps(true); + break; + } + + Qt3DRender::QTextureWrapMode wrapMode; + switch (p->meta.clampType) { + case Q3DSMaterial::Repeat: + wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); + wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); + break; + default: + wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); + wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } + texture->setWrapMode(wrapMode); + }; + const QString source = p.inputValue.toString(); Qt3DRender::QAbstractTexture *texture; if (source.isEmpty()) { texture = dummyTexture(id); + setupTexture(&p, texture); + p.param->setValue(QVariant::fromValue(texture)); } else { - texture = Q3DSImageManager::instance().newTextureForImage(m_rootEntity, 0, id, m_profiler, - "Custom property texture %s", qPrintable(source)); + p.texture = Q3DSImageManager::instance().newReloadableTextureForImage( + m_rootEntity, 0, id, m_profiler, "Custom property texture %s", + qPrintable(source)); qCDebug(lcScene, "Creating custom property texture %s", qPrintable(source)); - Q3DSImageManager::instance().setSource(texture, QUrl::fromLocalFile(source), - m_presentation->preferKtx()); - } - - // now override the defaults set in setSource() with whatever the metadata specifies - - switch (p.meta.magFilterType) { - case Q3DSMaterial::Nearest: - texture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Nearest); - break; - default: - texture->setMagnificationFilter(Qt3DRender::QAbstractTexture::Linear); - break; - } - - switch (p.meta.minFilterType) { - case Q3DSMaterial::Nearest: - texture->setMinificationFilter(Qt3DRender::QAbstractTexture::Nearest); - break; - case Q3DSMaterial::Linear: - texture->setMinificationFilter(Qt3DRender::QAbstractTexture::Linear); - break; - case Q3DSMaterial::NearestMipmapNearest: - texture->setMinificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapNearest); - texture->setGenerateMipMaps(true); - break; - case Q3DSMaterial::NearestMipmapLinear: - texture->setMinificationFilter(Qt3DRender::QAbstractTexture::NearestMipMapLinear); - texture->setGenerateMipMaps(true); - break; - case Q3DSMaterial::LinearMipmapNearest: - texture->setMinificationFilter(Qt3DRender::QAbstractTexture::LinearMipMapNearest); - texture->setGenerateMipMaps(true); - break; - default: - texture->setMinificationFilter(Qt3DRender::QAbstractTexture::LinearMipMapLinear); - texture->setGenerateMipMaps(true); - break; - - } - - Qt3DRender::QTextureWrapMode wrapMode; - switch (p.meta.clampType) { - case Q3DSMaterial::Repeat: - wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); - wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); - break; - default: - wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); - wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; + p.texture->setSource(m_presentation->imageUrl(source)); + p.texture->onLoad([setupTexture](Qt3DRender::QAbstractTexture *texture, + Q3DSCustomPropertyParameter *p) { + p->param->setValue(QVariant::fromValue(texture)); + if (p->texFlagParam) + p->texFlagParam->setValue(1); + const QSize size = Q3DSImageManager::instance().size(texture); + const bool isPremultiplied = false; + if (p->texInfoParam) { + p->texInfoParam->setValue(QVector4D(size.width(), size.height(), + isPremultiplied ? 1 : 0, 0)); + } + setupTexture(p, texture); + }, &p); + p.texture->onUnload([](Qt3DRender::QAbstractTexture *texture, + Q3DSCustomPropertyParameter *p) { + Q_UNUSED(texture); + p->param->setValue({}); + p->texInfoParam->setValue({}); + }, &p); } - texture->setWrapMode(wrapMode); - - return texture; } QVector<Qt3DRender::QParameter *> Q3DSSceneManager::prepareCustomMaterial(Q3DSCustomMaterialInstance *m, Q3DSReferencedMaterial *rm, Q3DSModelNode *model3DS) @@ -6770,7 +6965,8 @@ QVector<Qt3DRender::QParameter *> Q3DSSceneManager::prepareCustomMaterial(Q3DSCu iblOverrideImage = m->lightProbe(); if (iblOverrideImage) { if (!data->lightProbeOverrideTexture) { - data->lightProbeOverrideTexture = Q3DSImageManager::instance().newTextureForImage( + data->lightProbeOverrideTexture + = Q3DSImageManager::instance().newReloadableTextureForImage( m_rootEntity, Q3DSImageManager::GenerateMipMapsForIBL, iblOverrideImage->id(), m_profiler, "Texture for image %s", iblOverrideImage->id().constData()); @@ -6818,7 +7014,7 @@ void Q3DSSceneManager::updateCustomMaterial(Q3DSCustomMaterialInstance *m, Q3DSR // point whereas we need a proper Qt 3D texture. switch (p.meta.type) { case Q3DS::Texture: - p.param->setValue(QVariant::fromValue(createCustomPropertyTexture(p, m->id()))); + createCustomPropertyTexture(p, m->id()); break; // Buffer, Image2D, etc. are not used for custom materials @@ -6868,52 +7064,61 @@ void Q3DSSceneManager::updateCustomMaterial(Q3DSCustomMaterialInstance *m, Q3DSR // IBL if (iblOverride) { // also sets min/mag and generates mipmaps - Q3DSImageManager::instance().setSource(data->lightProbeOverrideTexture, - QUrl::fromLocalFile(iblOverride->sourcePath()), - m_presentation->preferKtx()); - data->lightProbeSampler->setValue(QVariant::fromValue(data->lightProbeOverrideTexture)); - - Qt3DRender::QTextureWrapMode wrapMode; - wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); - - switch (iblOverride->horizontalTiling()) { - case Q3DSImage::Tiled: + data->lightProbeOverrideTexture->setSource( + m_presentation->imageUrl(iblOverride->sourcePath())); + data->lightProbeOverrideTexture->onLoad([](Qt3DRender::QAbstractTexture *texture, + Q3DSImage *iblOverride, + Q3DSCustomMaterialAttached *data) { + data->lightProbeSampler->setValue(QVariant::fromValue(texture)); + + Qt3DRender::QTextureWrapMode wrapMode; wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); - break; - case Q3DSImage::Mirrored: - wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); - break; - default: - wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; - } - switch (iblOverride->verticalTiling()) { - case Q3DSImage::Tiled: - wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); - break; - case Q3DSImage::Mirrored: - wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); - break; - default: - wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); - break; - } + switch (iblOverride->horizontalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setX(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setX(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setX(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } + + switch (iblOverride->verticalTiling()) { + case Q3DSImage::Tiled: + wrapMode.setY(Qt3DRender::QTextureWrapMode::Repeat); + break; + case Q3DSImage::Mirrored: + wrapMode.setY(Qt3DRender::QTextureWrapMode::MirroredRepeat); + break; + default: + wrapMode.setY(Qt3DRender::QTextureWrapMode::ClampToEdge); + break; + } - Q_ASSERT(data->lightProbeOverrideTexture); - data->lightProbeOverrideTexture->setWrapMode(wrapMode); + texture->setWrapMode(wrapMode); - const QMatrix4x4 &textureTransform = iblOverride->textureTransform(); - const float *m = textureTransform.constData(); + const QMatrix4x4 &textureTransform = iblOverride->textureTransform(); + const float *m = textureTransform.constData(); - // offsets.w = max mip level - const QSize texSize = Q3DSImageManager::instance().size(data->lightProbeOverrideTexture); - float mipLevels = float(qCeil(qLog2(qMax(texSize.width(), texSize.height())))); - QVector4D offsets(m[12], m[13], 0.0f, mipLevels); - data->lightProbeOffset->setValue(offsets); + // offsets.w = max mip level + const QSize texSize = Q3DSImageManager::instance().size(texture); + float mipLevels = float(qCeil(qLog2(qMax(texSize.width(), texSize.height())))); + QVector4D offsets(m[12], m[13], 0.0f, mipLevels); + data->lightProbeOffset->setValue(offsets); - QVector4D rotations(m[0], m[4], m[1], m[5]); - data->lightProbeRotation->setValue(rotations); + QVector4D rotations(m[0], m[4], m[1], m[5]); + data->lightProbeRotation->setValue(rotations); + }, iblOverride, data); + data->lightProbeOverrideTexture->onUnload([](Qt3DRender::QAbstractTexture *texture, + Q3DSCustomMaterialAttached *data) { + Q_UNUSED(texture); + data->lightProbeSampler->setValue({}); + data->lightProbeOffset->setValue({}); + data->lightProbeRotation->setValue({}); + }, data); } } @@ -7896,10 +8101,7 @@ void Q3DSSceneManager::updateEffect(Q3DSEffectInstance *eff3DS) switch (p.meta.type) { case Q3DS::Texture: { - Qt3DRender::QAbstractTexture *tex = createCustomPropertyTexture(p, eff3DS->id()); - p.param->setValue(QVariant::fromValue(tex)); - setTextureInfoUniform(p.texInfoParam, tex); - p.texFlagParam->setValue(1); + createCustomPropertyTexture(p, eff3DS->id()); } break; @@ -8397,7 +8599,8 @@ void Q3DSSceneManager::syncScene() for (Q3DSModelNode *model3DS : needsRebuild) rebuildModelMaterial(model3DS); - Q3DSImageManager::instance().finishAsyncLoad(); + m_engine->finishAsyncLoad(false); + Q3DSImageManager::instance().finishAsyncLoad(false); } void Q3DSSceneManager::setPendingVisibilities() @@ -9073,6 +9276,11 @@ void Q3DSFrameUpdater::frameAction(float dt) // the time includes all subpresentations too) m_sceneManager->m_profiler->reportTotalParseBuildTime(m_sceneManager->m_engine->totalLoadTimeMsecs()); } + + // At this point do synchronized start of engine animations + QTimer::singleShot(0, [this]() { + m_sceneManager->engine()->startAnimations(); + }); } m_sceneManager->m_profiler->reportBehaviorStats(m_sceneManager->m_engine->behaviorLoadTimeMsecs(), m_sceneManager->m_engine->behaviorHandles().count()); |