forked from qt-creator/qt-creator
QmlDesigner: Implement basic lights baking support
It is expected that user manually specifies all necessary light baking related properties, including exposing them from subcomponents if needed. qlmdenoiser that is used to denoise generated light maps is a third party application. It can be found here: https://git.qt.io/laagocs/qlmdenoiser Fixes: QDS-9403 Change-Id: Ida6fc142440b9ffa8cc97d578f85d8b76cb4b43f Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io> Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
This commit is contained in:
committed by
Mahmoud Badri
parent
2175b976fb
commit
e82898a184
@@ -0,0 +1,90 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import QtQuick.Layouts
|
||||
import QtQuickDesignerTheme
|
||||
import HelperWidgets
|
||||
import StudioControls as StudioControls
|
||||
import StudioTheme as StudioTheme
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
color: StudioTheme.Values.themePanelBackground
|
||||
|
||||
Column {
|
||||
id: col
|
||||
padding: 5
|
||||
leftPadding: 10
|
||||
spacing: 5
|
||||
|
||||
Text {
|
||||
id: title
|
||||
text: qsTr("Baking lights for 3D view: %1").arg(sceneId)
|
||||
font.bold: true
|
||||
font.pixelSize: StudioTheme.Values.myFontSize
|
||||
color: StudioTheme.Values.themeTextColor
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: root.width - 16
|
||||
height: root.height - title.height - button.height - 20
|
||||
|
||||
color: StudioTheme.Values.themePanelBackground
|
||||
border.color: StudioTheme.Values.themeControlOutline
|
||||
border.width: StudioTheme.Values.border
|
||||
|
||||
ScrollView {
|
||||
id: scrollView
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: 4
|
||||
|
||||
clip: true
|
||||
|
||||
Behavior on contentY {
|
||||
PropertyAnimation {
|
||||
easing.type: Easing.InOutQuad
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: progressText
|
||||
width: scrollView.width
|
||||
font.pixelSize: StudioTheme.Values.myFontSize
|
||||
color: StudioTheme.Values.themeTextColor
|
||||
}
|
||||
|
||||
function ensureVisible()
|
||||
{
|
||||
let newPos = scrollView.contentHeight - scrollView.height
|
||||
scrollView.contentY = newPos < 0 ? 0 : newPos
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: rootView
|
||||
function onProgress(msg) {
|
||||
progressText.text += progressText.text === "" ? msg : "\n" + msg
|
||||
scrollView.ensureVisible()
|
||||
}
|
||||
|
||||
function onFinished() {
|
||||
button.text = qsTr("Close")
|
||||
}
|
||||
}
|
||||
|
||||
Button {
|
||||
id: button
|
||||
text: qsTr("Cancel")
|
||||
anchors.right: parent.right
|
||||
anchors.margins: StudioTheme.Values.dialogButtonPadding
|
||||
|
||||
onClicked: rootView.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,11 @@ public:
|
||||
RenderModelNodePreviewImage,
|
||||
Import3DSupport,
|
||||
NodeAtPos,
|
||||
None };
|
||||
BakeLightsProgress,
|
||||
BakeLightsFinished,
|
||||
BakeLightsAborted,
|
||||
None
|
||||
};
|
||||
|
||||
PuppetToCreatorCommand(Type type, const QVariant &data);
|
||||
PuppetToCreatorCommand() = default;
|
||||
|
||||
@@ -48,7 +48,8 @@ enum class View3DActionType {
|
||||
SelectGridColor,
|
||||
ResetBackgroundColor,
|
||||
SyncBackgroundColor,
|
||||
GetNodeAtPos
|
||||
GetNodeAtPos,
|
||||
SetBakeLightsView3D
|
||||
};
|
||||
|
||||
constexpr bool isNanotraceEnabled()
|
||||
|
||||
@@ -653,6 +653,8 @@ extend_qtc_plugin(QmlDesigner
|
||||
edit3dactions.cpp edit3dactions.h
|
||||
edit3dvisibilitytogglesmenu.cpp edit3dvisibilitytogglesmenu.h
|
||||
backgroundcolorselection.cpp backgroundcolorselection.h
|
||||
bakelights.cpp bakelights.h
|
||||
bakelightsconnectionmanager.cpp bakelightsconnectionmanager.h
|
||||
edit3d.qrc
|
||||
)
|
||||
|
||||
|
||||
250
src/plugins/qmldesigner/components/edit3d/bakelights.cpp
Normal file
250
src/plugins/qmldesigner/components/edit3d/bakelights.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "bakelights.h"
|
||||
|
||||
#include "abstractview.h"
|
||||
#include "bakelightsconnectionmanager.h"
|
||||
#include "documentmanager.h"
|
||||
#include "modelnode.h"
|
||||
#include "nodeabstractproperty.h"
|
||||
#include "nodeinstanceview.h"
|
||||
#include "nodemetainfo.h"
|
||||
#include "plaintexteditmodifier.h"
|
||||
#include "rewriterview.h"
|
||||
#include "variantproperty.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/environment.h>
|
||||
#include <utils/filepath.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QQmlContext>
|
||||
#include <QQmlEngine>
|
||||
#include <QQuickView>
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocument>
|
||||
#include <QTimer>
|
||||
#include <QVariant>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
static QString propertyEditorResourcesPath()
|
||||
{
|
||||
#ifdef SHARE_QML_PATH
|
||||
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
|
||||
return QLatin1String(SHARE_QML_PATH) + "/propertyEditorQmlSources";
|
||||
#endif
|
||||
return Core::ICore::resourcePath("qmldesigner/propertyEditorQmlSources").toString();
|
||||
}
|
||||
|
||||
static QString qmlSourcesPath()
|
||||
{
|
||||
#ifdef SHARE_QML_PATH
|
||||
if (Utils::qtcEnvironmentVariableIsSet("LOAD_QML_FROM_SOURCE"))
|
||||
return QLatin1String(SHARE_QML_PATH) + "/edit3dQmlSource";
|
||||
#endif
|
||||
return Core::ICore::resourcePath("qmldesigner/edit3dQmlSource").toString();
|
||||
}
|
||||
|
||||
BakeLights::BakeLights(AbstractView *view)
|
||||
: QObject(view)
|
||||
, m_view(view)
|
||||
{
|
||||
m_view3dId = resolveView3dId(view);
|
||||
|
||||
if (m_view3dId.isEmpty()) {
|
||||
// It should never get here, baking controls should be disabled in this case
|
||||
qWarning() << __FUNCTION__ << "Active scene is not View3D";
|
||||
deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// Create folders for lightmaps if they do not exist
|
||||
PropertyName loadPrefixPropName{"loadPrefix"};
|
||||
const QList<ModelNode> bakedLightmapNodes = m_view->allModelNodesOfType(
|
||||
m_view->model()->qtQuick3DBakedLightmapMetaInfo());
|
||||
Utils::FilePath currentPath = DocumentManager::currentFilePath().absolutePath();
|
||||
QSet<Utils::FilePath> pathSet;
|
||||
for (const ModelNode &node : bakedLightmapNodes) {
|
||||
if (node.hasVariantProperty(loadPrefixPropName)) {
|
||||
QString prefix = node.variantProperty(loadPrefixPropName).value().toString();
|
||||
Utils::FilePath fp = Utils::FilePath::fromString(prefix);
|
||||
if (fp.isRelativePath()) {
|
||||
fp = currentPath.pathAppended(prefix);
|
||||
if (!fp.exists())
|
||||
pathSet.insert(fp);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const Utils::FilePath &fp : std::as_const(pathSet))
|
||||
fp.createDir();
|
||||
|
||||
// Show non-modal progress dialog with cancel button
|
||||
QString path = qmlSourcesPath() + "/BakeLightsDialog.qml";
|
||||
|
||||
m_dialog = new QQuickView;
|
||||
m_dialog->setTitle(tr("Bake Lights"));
|
||||
m_dialog->setResizeMode(QQuickView::SizeRootObjectToView);
|
||||
m_dialog->setMinimumSize({150, 100});
|
||||
m_dialog->setWidth(800);
|
||||
m_dialog->setHeight(400);
|
||||
m_dialog->setFlags(Qt::Dialog);
|
||||
m_dialog->setModality(Qt::NonModal);
|
||||
m_dialog->engine()->addImportPath(propertyEditorResourcesPath() + "/imports");
|
||||
|
||||
m_dialog->rootContext()->setContextProperties({
|
||||
{"rootView", QVariant::fromValue(this)},
|
||||
{"sceneId", QVariant::fromValue(m_view3dId)}
|
||||
});
|
||||
m_dialog->setSource(QUrl::fromLocalFile(path));
|
||||
m_dialog->installEventFilter(this);
|
||||
m_dialog->show();
|
||||
|
||||
QTimer::singleShot(0, this, &BakeLights::bakeLights);
|
||||
}
|
||||
|
||||
BakeLights::~BakeLights()
|
||||
{
|
||||
if (m_connectionManager) {
|
||||
m_connectionManager->setProgressCallback({});
|
||||
m_connectionManager->setFinishedCallback({});
|
||||
m_connectionManager->setCrashCallback({});
|
||||
}
|
||||
|
||||
if (m_model) {
|
||||
m_model->setNodeInstanceView({});
|
||||
m_model->setRewriterView({});
|
||||
m_model.reset();
|
||||
}
|
||||
|
||||
delete m_dialog;
|
||||
delete m_rewriterView;
|
||||
delete m_nodeInstanceView;
|
||||
delete m_connectionManager;
|
||||
}
|
||||
|
||||
QString BakeLights::resolveView3dId(AbstractView *view)
|
||||
{
|
||||
if (!view || !view->model())
|
||||
return {};
|
||||
|
||||
QString view3dId;
|
||||
ModelNode activeView3D;
|
||||
ModelNode activeScene = view->active3DSceneNode();
|
||||
|
||||
if (activeScene.isValid()) {
|
||||
if (activeScene.metaInfo().isQtQuick3DView3D()) {
|
||||
activeView3D = activeScene;
|
||||
} else {
|
||||
ModelNode sceneParent = activeScene.parentProperty().parentModelNode();
|
||||
if (sceneParent.metaInfo().isQtQuick3DView3D())
|
||||
activeView3D = sceneParent;
|
||||
}
|
||||
view3dId = activeView3D.id();
|
||||
}
|
||||
|
||||
return view3dId;
|
||||
}
|
||||
|
||||
void BakeLights::raiseDialog()
|
||||
{
|
||||
if (m_dialog)
|
||||
m_dialog->raise();
|
||||
}
|
||||
|
||||
void BakeLights::bakeLights()
|
||||
{
|
||||
if (!m_view || !m_view->model())
|
||||
return;
|
||||
|
||||
// Start baking process
|
||||
m_connectionManager = new BakeLightsConnectionManager;
|
||||
m_rewriterView = new RewriterView{m_view->externalDependencies(), RewriterView::Amend};
|
||||
m_nodeInstanceView = new NodeInstanceView{*m_connectionManager, m_view->externalDependencies()};
|
||||
|
||||
m_model = QmlDesigner::Model::create("QtQuick/Item", 2, 1);
|
||||
m_model->setFileUrl(m_view->model()->fileUrl());
|
||||
|
||||
// Take the current unsaved state of the main model and apply it to our copy
|
||||
auto textDocument = std::make_unique<QTextDocument>(
|
||||
m_view->model()->rewriterView()->textModifier()->textDocument()->toRawText());
|
||||
|
||||
auto modifier = std::make_unique<NotIndentingTextEditModifier>(textDocument.get(),
|
||||
QTextCursor{textDocument.get()});
|
||||
|
||||
m_rewriterView->setTextModifier(modifier.get());
|
||||
m_model->setRewriterView(m_rewriterView);
|
||||
|
||||
auto rootModelNodeMetaInfo = m_rewriterView->rootModelNode().metaInfo();
|
||||
bool is3DRoot = m_rewriterView->errors().isEmpty()
|
||||
&& (rootModelNodeMetaInfo.isQtQuick3DNode()
|
||||
|| rootModelNodeMetaInfo.isQtQuick3DMaterial());
|
||||
|
||||
if (!m_rewriterView->errors().isEmpty()
|
||||
|| (!m_rewriterView->rootModelNode().metaInfo().isGraphicalItem() && !is3DRoot)) {
|
||||
emit progress(tr("Invalid root node, baking aborted."));
|
||||
emit finished();
|
||||
m_dialog->raise();
|
||||
return;
|
||||
}
|
||||
|
||||
m_nodeInstanceView->setTarget(m_view->nodeInstanceView()->target());
|
||||
|
||||
auto progressCallback = [this](const QString &msg) {
|
||||
emit progress(msg);
|
||||
};
|
||||
|
||||
auto finishedCallback = [this](const QString &msg) {
|
||||
m_dialog->raise();
|
||||
emit progress(msg);
|
||||
emit finished();
|
||||
|
||||
// Puppet reset is needed to update baking results to current views
|
||||
m_view->resetPuppet();
|
||||
};
|
||||
|
||||
auto crashCallback = [this]() {
|
||||
m_dialog->raise();
|
||||
emit progress(tr("Baking process crashed, baking aborted."));
|
||||
emit finished();
|
||||
};
|
||||
|
||||
m_connectionManager->setProgressCallback(std::move(progressCallback));
|
||||
m_connectionManager->setFinishedCallback(std::move(finishedCallback));
|
||||
m_connectionManager->setCrashCallback(std::move(crashCallback));
|
||||
|
||||
m_model->setNodeInstanceView(m_nodeInstanceView);
|
||||
|
||||
// InternalIds are not guaranteed to match between normal model and our copy of it, so
|
||||
// we identify the View3D by its qml id.
|
||||
m_nodeInstanceView->view3DAction(View3DActionType::SetBakeLightsView3D, m_view3dId);
|
||||
}
|
||||
|
||||
void BakeLights::cancel()
|
||||
{
|
||||
if (!m_dialog.isNull() && m_dialog->isVisible())
|
||||
m_dialog->close();
|
||||
|
||||
deleteLater();
|
||||
}
|
||||
|
||||
bool BakeLights::eventFilter(QObject *obj, QEvent *event)
|
||||
{
|
||||
if (obj == m_dialog) {
|
||||
if (event->type() == QEvent::KeyPress) {
|
||||
QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
|
||||
if (keyEvent->key() == Qt::Key_Escape)
|
||||
cancel();
|
||||
} else if (event->type() == QEvent::Close) {
|
||||
cancel();
|
||||
}
|
||||
}
|
||||
|
||||
return QObject::eventFilter(obj, event);
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
54
src/plugins/qmldesigner/components/edit3d/bakelights.h
Normal file
54
src/plugins/qmldesigner/components/edit3d/bakelights.h
Normal file
@@ -0,0 +1,54 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
#pragma once
|
||||
|
||||
#include "qmldesignercorelib_global.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QQuickView;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class AbstractView;
|
||||
class BakeLightsConnectionManager;
|
||||
class NodeInstanceView;
|
||||
class RewriterView;
|
||||
|
||||
class BakeLights : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
BakeLights(AbstractView *view);
|
||||
~BakeLights();
|
||||
|
||||
Q_INVOKABLE void cancel();
|
||||
|
||||
void raiseDialog();
|
||||
|
||||
static QString resolveView3dId(AbstractView *view);
|
||||
|
||||
signals:
|
||||
void finished();
|
||||
void progress(const QString &msg);
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||
|
||||
private:
|
||||
void bakeLights();
|
||||
|
||||
QPointer<QQuickView> m_dialog;
|
||||
QPointer<BakeLightsConnectionManager> m_connectionManager;
|
||||
QPointer<NodeInstanceView> m_nodeInstanceView;
|
||||
QPointer<RewriterView> m_rewriterView;
|
||||
QPointer<AbstractView> m_view;
|
||||
ModelPointer m_model;
|
||||
QString m_view3dId;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "bakelightsconnectionmanager.h"
|
||||
|
||||
#include <puppettocreatorcommand.h>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
BakeLightsConnectionManager::BakeLightsConnectionManager()
|
||||
{
|
||||
connections().emplace_back("Bake lights", "bakelightsmode");
|
||||
}
|
||||
|
||||
void BakeLightsConnectionManager::setProgressCallback(Callback callback)
|
||||
{
|
||||
m_progressCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void BakeLightsConnectionManager::setFinishedCallback(Callback callback)
|
||||
{
|
||||
m_finishedCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void BakeLightsConnectionManager::dispatchCommand(const QVariant &command,
|
||||
ConnectionManagerInterface::Connection &)
|
||||
{
|
||||
static const int commandType = QMetaType::type("PuppetToCreatorCommand");
|
||||
|
||||
if (command.userType() == commandType) {
|
||||
auto cmd = command.value<PuppetToCreatorCommand>();
|
||||
switch (cmd.type()) {
|
||||
case PuppetToCreatorCommand::BakeLightsProgress:
|
||||
m_progressCallback(cmd.data().toString());
|
||||
break;
|
||||
case PuppetToCreatorCommand::BakeLightsAborted:
|
||||
m_finishedCallback(tr("Baking aborted!"));
|
||||
break;
|
||||
case PuppetToCreatorCommand::BakeLightsFinished:
|
||||
m_finishedCallback(tr("Baking finished!"));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,28 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "connectionmanager.h"
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class BakeLightsConnectionManager : public ConnectionManager
|
||||
{
|
||||
public:
|
||||
using Callback = std::function<void(const QString &)>;
|
||||
|
||||
BakeLightsConnectionManager();
|
||||
|
||||
void setProgressCallback(Callback callback);
|
||||
void setFinishedCallback(Callback callback);
|
||||
|
||||
protected:
|
||||
void dispatchCommand(const QVariant &command, Connection &connection) override;
|
||||
|
||||
private:
|
||||
Callback m_progressCallback;
|
||||
Callback m_finishedCallback;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -2,18 +2,15 @@
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "edit3dactions.h"
|
||||
#include "edit3dview.h"
|
||||
|
||||
#include <viewmanager.h>
|
||||
#include <nodeinstanceview.h>
|
||||
#include <nodemetainfo.h>
|
||||
#include <qmldesignerplugin.h>
|
||||
#include "bakelights.h"
|
||||
#include "edit3dview.h"
|
||||
#include "nodemetainfo.h"
|
||||
#include "qmldesignerconstants.h"
|
||||
#include "seekerslider.h"
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
Edit3DActionTemplate::Edit3DActionTemplate(const QString &description,
|
||||
@@ -147,4 +144,33 @@ bool Edit3DParticleSeekerAction::isEnabled(const SelectionContext &) const
|
||||
return m_seeker->isEnabled();
|
||||
}
|
||||
|
||||
Edit3DBakeLightsAction::Edit3DBakeLightsAction(const QIcon &icon,
|
||||
Edit3DView *view,
|
||||
SelectionContextOperation selectionAction)
|
||||
: Edit3DAction(QmlDesigner::Constants::EDIT3D_BAKE_LIGHTS,
|
||||
View3DActionType::Empty,
|
||||
QCoreApplication::translate("BakeLights", "Bake Lights"),
|
||||
QKeySequence(),
|
||||
false,
|
||||
false,
|
||||
icon,
|
||||
view,
|
||||
selectionAction,
|
||||
QCoreApplication::translate("BakeLights", "Bake lights for the current 3D scene."))
|
||||
, m_view(view)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
bool Edit3DBakeLightsAction::isVisible(const SelectionContext &) const
|
||||
{
|
||||
return m_view->isBakingLightsSupported();
|
||||
}
|
||||
|
||||
bool Edit3DBakeLightsAction::isEnabled(const SelectionContext &) const
|
||||
{
|
||||
return m_view->isBakingLightsSupported()
|
||||
&& !BakeLights::resolveView3dId(m_view).isEmpty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -122,4 +122,19 @@ private:
|
||||
SeekerSliderAction *m_seeker = nullptr;
|
||||
};
|
||||
|
||||
class Edit3DBakeLightsAction : public Edit3DAction
|
||||
{
|
||||
public:
|
||||
Edit3DBakeLightsAction(const QIcon &icon,
|
||||
Edit3DView *view,
|
||||
SelectionContextOperation selectionAction);
|
||||
|
||||
protected:
|
||||
bool isVisible(const SelectionContext &) const override;
|
||||
bool isEnabled(const SelectionContext &) const override;
|
||||
|
||||
private:
|
||||
Edit3DView *m_view = nullptr;
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "edit3dview.h"
|
||||
|
||||
#include "backgroundcolorselection.h"
|
||||
#include "bakelights.h"
|
||||
#include "designeractionmanager.h"
|
||||
#include "designericons.h"
|
||||
#include "designersettings.h"
|
||||
@@ -20,11 +21,16 @@
|
||||
#include "qmldesignerplugin.h"
|
||||
#include "qmlvisualnode.h"
|
||||
#include "seekerslider.h"
|
||||
#include "theme.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/messagebox.h>
|
||||
|
||||
#include <theme.h>
|
||||
#include <projectexplorer/target.h>
|
||||
#include <projectexplorer/kit.h>
|
||||
|
||||
#include <qtsupport/qtkitinformation.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/stylehelper.h>
|
||||
@@ -204,6 +210,12 @@ void Edit3DView::updateActiveScene3D(const QVariantMap &sceneState)
|
||||
m_particlesPlayAction->action()->setChecked(sceneState[particlesPlayKey].toBool());
|
||||
else
|
||||
m_particlesPlayAction->action()->setChecked(true);
|
||||
|
||||
// Selection context change updates visible and enabled states
|
||||
SelectionContext selectionContext(this);
|
||||
selectionContext.setUpdateMode(SelectionContext::UpdateMode::Fast);
|
||||
if (m_bakeLightsAction)
|
||||
m_bakeLightsAction->currentContextChanged(selectionContext);
|
||||
}
|
||||
|
||||
void Edit3DView::modelAttached(Model *model)
|
||||
@@ -219,6 +231,13 @@ void Edit3DView::modelAttached(Model *model)
|
||||
|
||||
edit3DWidget()->canvas()->busyIndicator()->show();
|
||||
|
||||
m_isBakingLightsSupported = false;
|
||||
ProjectExplorer::Target *target = QmlDesignerPlugin::instance()->currentDesignDocument()->currentTarget();
|
||||
if (target && target->kit()) {
|
||||
if (QtSupport::QtVersion *qtVer = QtSupport::QtKitAspect::qtVersion(target->kit()))
|
||||
m_isBakingLightsSupported = qtVer->qtVersion() >= QVersionNumber(6, 5, 0);
|
||||
}
|
||||
|
||||
connect(model->metaInfo().itemLibraryInfo(), &ItemLibraryInfo::entriesChanged, this,
|
||||
&Edit3DView::onEntriesChanged, Qt::UniqueConnection);
|
||||
}
|
||||
@@ -279,6 +298,11 @@ void Edit3DView::handleEntriesChanged()
|
||||
|
||||
void Edit3DView::modelAboutToBeDetached(Model *model)
|
||||
{
|
||||
m_isBakingLightsSupported = false;
|
||||
|
||||
if (m_bakeLights)
|
||||
m_bakeLights->cancel();
|
||||
|
||||
// Hide the canvas when model is detached (i.e. changing documents)
|
||||
if (edit3DWidget() && edit3DWidget()->canvas()) {
|
||||
m_canvasCache.insert(model, edit3DWidget()->canvas()->renderImage());
|
||||
@@ -702,6 +726,17 @@ void Edit3DView::createEdit3DActions()
|
||||
m_seekerAction->action()->setEnabled(!m_particlesPlayAction->action()->isChecked());
|
||||
};
|
||||
|
||||
SelectionContextOperation bakeLightsTrigger = [this](const SelectionContext &) {
|
||||
if (!m_isBakingLightsSupported)
|
||||
return;
|
||||
|
||||
// BakeLights cleans itself up when its dialog is closed
|
||||
if (!m_bakeLights)
|
||||
m_bakeLights = new BakeLights(this);
|
||||
else
|
||||
m_bakeLights->raiseDialog();
|
||||
};
|
||||
|
||||
m_particleViewModeAction = new Edit3DAction(
|
||||
QmlDesigner::Constants::EDIT3D_PARTICLE_MODE,
|
||||
View3DActionType::Edit3DParticleModeToggle,
|
||||
@@ -804,6 +839,11 @@ void Edit3DView::createEdit3DActions()
|
||||
|
||||
m_seekerAction = createSeekerSliderAction();
|
||||
|
||||
m_bakeLightsAction = new Edit3DBakeLightsAction(
|
||||
toolbarIcon(Theme::editLightOn_medium), //: TODO placeholder icon
|
||||
this,
|
||||
bakeLightsTrigger);
|
||||
|
||||
m_leftActions << m_selectionModeAction;
|
||||
m_leftActions << nullptr; // Null indicates separator
|
||||
m_leftActions << nullptr; // Second null after separator indicates an exclusive group
|
||||
@@ -830,6 +870,7 @@ void Edit3DView::createEdit3DActions()
|
||||
m_rightActions << nullptr;
|
||||
m_rightActions << m_seekerAction;
|
||||
m_rightActions << nullptr;
|
||||
m_rightActions << m_bakeLightsAction;
|
||||
m_rightActions << m_resetAction;
|
||||
|
||||
m_visibilityToggleActions << m_showGridAction;
|
||||
@@ -870,6 +911,11 @@ Edit3DAction *Edit3DView::edit3DAction(View3DActionType type) const
|
||||
return m_edit3DActions.value(type, nullptr).data();
|
||||
}
|
||||
|
||||
Edit3DBakeLightsAction *Edit3DView::bakeLightsAction() const
|
||||
{
|
||||
return m_bakeLightsAction;
|
||||
}
|
||||
|
||||
void Edit3DView::addQuick3DImport()
|
||||
{
|
||||
DesignDocument *document = QmlDesignerPlugin::instance()->currentDesignDocument();
|
||||
@@ -939,4 +985,9 @@ void Edit3DView::dropAsset(const QString &file, const QPointF &pos)
|
||||
emitView3DAction(View3DActionType::GetNodeAtPos, pos);
|
||||
}
|
||||
|
||||
bool Edit3DView::isBakingLightsSupported() const
|
||||
{
|
||||
return m_isBakingLightsSupported;
|
||||
}
|
||||
|
||||
} // namespace QmlDesigner
|
||||
|
||||
@@ -22,8 +22,10 @@ QT_END_NAMESPACE
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class BakeLights;
|
||||
class Edit3DWidget;
|
||||
class Edit3DAction;
|
||||
class Edit3DBakeLightsAction;
|
||||
class Edit3DCameraAction;
|
||||
|
||||
class QMLDESIGNERCOMPONENTS_EXPORT Edit3DView : public AbstractView
|
||||
@@ -57,6 +59,7 @@ public:
|
||||
QVector<Edit3DAction *> visibilityToggleActions() const;
|
||||
QVector<Edit3DAction *> backgroundColorActions() const;
|
||||
Edit3DAction *edit3DAction(View3DActionType type) const;
|
||||
Edit3DBakeLightsAction *bakeLightsAction() const;
|
||||
|
||||
void addQuick3DImport();
|
||||
void startContextMenu(const QPoint &pos);
|
||||
@@ -66,6 +69,8 @@ public:
|
||||
void dropComponent(const ItemLibraryEntry &entry, const QPointF &pos);
|
||||
void dropAsset(const QString &file, const QPointF &pos);
|
||||
|
||||
bool isBakingLightsSupported() const;
|
||||
|
||||
private slots:
|
||||
void onEntriesChanged();
|
||||
|
||||
@@ -122,6 +127,7 @@ private:
|
||||
Edit3DAction *m_visibilityTogglesAction = nullptr;
|
||||
Edit3DAction *m_backgrondColorMenuAction = nullptr;
|
||||
Edit3DAction *m_seekerAction = nullptr;
|
||||
Edit3DBakeLightsAction *m_bakeLightsAction = nullptr;
|
||||
int particlemode;
|
||||
ModelCache<QImage> m_canvasCache;
|
||||
ModelNode m_droppedModelNode;
|
||||
@@ -130,6 +136,8 @@ private:
|
||||
NodeAtPosReqType m_nodeAtPosReqType;
|
||||
QPoint m_contextMenuPos;
|
||||
QTimer m_compressionTimer;
|
||||
QPointer<BakeLights> m_bakeLights;
|
||||
bool m_isBakingLightsSupported = false;
|
||||
|
||||
friend class Edit3DAction;
|
||||
};
|
||||
|
||||
@@ -261,6 +261,12 @@ void Edit3DWidget::createContextMenu()
|
||||
view()->emitView3DAction(View3DActionType::AlignViewToCamera, true);
|
||||
});
|
||||
|
||||
m_bakeLightsAction = m_contextMenu->addAction(
|
||||
contextIcon(DesignerIcons::LightIcon), // TODO: placeholder icon
|
||||
tr("Bake Lights"), [&] {
|
||||
view()->bakeLightsAction()->action()->trigger();
|
||||
});
|
||||
|
||||
m_contextMenu->addSeparator();
|
||||
|
||||
m_selectParentAction = m_contextMenu->addAction(
|
||||
@@ -466,6 +472,8 @@ void Edit3DWidget::showContextMenu(const QPoint &pos, const ModelNode &modelNode
|
||||
m_alignViewAction->setEnabled(isCamera);
|
||||
m_selectParentAction->setEnabled(selectionExcludingRoot);
|
||||
m_toggleGroupAction->setEnabled(true);
|
||||
m_bakeLightsAction->setVisible(view()->bakeLightsAction()->action()->isVisible());
|
||||
m_bakeLightsAction->setEnabled(view()->bakeLightsAction()->action()->isEnabled());
|
||||
|
||||
m_contextMenu->popup(mapToGlobal(pos));
|
||||
}
|
||||
|
||||
@@ -75,6 +75,7 @@ private:
|
||||
QPointer<QMenu> m_visibilityTogglesMenu;
|
||||
QPointer<QMenu> m_backgroundColorMenu;
|
||||
QPointer<QMenu> m_contextMenu;
|
||||
QPointer<QAction> m_bakeLightsAction;
|
||||
QPointer<QAction> m_editComponentAction;
|
||||
QPointer<QAction> m_editMaterialAction;
|
||||
QPointer<QAction> m_duplicateAction;
|
||||
|
||||
@@ -87,6 +87,7 @@ public:
|
||||
NodeMetaInfo flowViewFlowTransitionMetaInfo() const;
|
||||
NodeMetaInfo flowViewFlowWildcardMetaInfo() const;
|
||||
NodeMetaInfo fontMetaInfo() const;
|
||||
NodeMetaInfo qtQuick3DBakedLightmapMetaInfo() const;
|
||||
NodeMetaInfo qtQuick3DDefaultMaterialMetaInfo() const;
|
||||
NodeMetaInfo qtQuick3DMaterialMetaInfo() const;
|
||||
NodeMetaInfo qtQuick3DModelMetaInfo() const;
|
||||
|
||||
@@ -122,6 +122,7 @@ public:
|
||||
QImage statePreviewImage(const ModelNode &stateNode) const;
|
||||
|
||||
void setTarget(ProjectExplorer::Target *newTarget);
|
||||
ProjectExplorer::Target *target() const;
|
||||
|
||||
void sendToken(const QString &token, int number, const QVector<ModelNode> &nodeVector);
|
||||
|
||||
|
||||
@@ -1572,6 +1572,11 @@ void NodeInstanceView::setTarget(ProjectExplorer::Target *newTarget)
|
||||
}
|
||||
}
|
||||
|
||||
ProjectExplorer::Target *NodeInstanceView::target() const
|
||||
{
|
||||
return m_currentTarget;
|
||||
}
|
||||
|
||||
void NodeInstanceView::statePreviewImagesChanged(const StatePreviewImageChangedCommand &command)
|
||||
{
|
||||
if (!model())
|
||||
|
||||
@@ -1939,6 +1939,16 @@ NodeMetaInfo Model::qtQuick3DTextureMetaInfo() const
|
||||
}
|
||||
}
|
||||
|
||||
NodeMetaInfo Model::qtQuick3DBakedLightmapMetaInfo() const
|
||||
{
|
||||
if constexpr (useProjectStorage()) {
|
||||
using namespace Storage::Info;
|
||||
return createNodeMetaInfo<QtQuick3D, BakedLightmap>();
|
||||
} else {
|
||||
return metaInfo("QtQuick3D.BakedLightmap");
|
||||
}
|
||||
}
|
||||
|
||||
NodeMetaInfo Model::qtQuick3DMaterialMetaInfo() const
|
||||
{
|
||||
if constexpr (useProjectStorage()) {
|
||||
|
||||
@@ -62,7 +62,7 @@ const char EDIT3D_PARTICLES_SEEKER[] = "QmlDesigner.Editor3D.ParticlesSeeker"
|
||||
const char EDIT3D_PARTICLES_RESTART[] = "QmlDesigner.Editor3D.ParticlesRestart";
|
||||
const char EDIT3D_VISIBILITY_TOGGLES[] = "QmlDesigner.Editor3D.VisibilityToggles";
|
||||
const char EDIT3D_BACKGROUND_COLOR_ACTIONS[] = "QmlDesigner.Editor3D.BackgroundColorActions";
|
||||
|
||||
const char EDIT3D_BAKE_LIGHTS[] = "QmlDesigner.Editor3D.BakeLights";
|
||||
|
||||
const char QML_DESIGNER_SUBFOLDER[] = "/designer/";
|
||||
const char COMPONENT_BUNDLES_FOLDER[] = "/ComponentBundles";
|
||||
|
||||
@@ -41,7 +41,7 @@ namespace Internal {
|
||||
|
||||
static QStringList puppetModes()
|
||||
{
|
||||
static QStringList puppetModeList{"", "all", "editormode", "rendermode", "previewmode"};
|
||||
static QStringList puppetModeList{"", "all", "editormode", "rendermode", "previewmode", "bakelightsmode"};
|
||||
return puppetModeList;
|
||||
}
|
||||
|
||||
|
||||
@@ -175,6 +175,7 @@ extend_qtc_executable(qml2puppet
|
||||
qmlstatenodeinstance.cpp qmlstatenodeinstance.h
|
||||
qmltransitionnodeinstance.cpp qmltransitionnodeinstance.h
|
||||
qt3dpresentationnodeinstance.cpp qt3dpresentationnodeinstance.h
|
||||
qt5bakelightsnodeinstanceserver.cpp qt5bakelightsnodeinstanceserver.h
|
||||
qt5informationnodeinstanceserver.cpp qt5informationnodeinstanceserver.h
|
||||
qt5nodeinstanceclientproxy.cpp qt5nodeinstanceclientproxy.h
|
||||
qt5nodeinstanceserver.cpp qt5nodeinstanceserver.h
|
||||
|
||||
@@ -25,6 +25,7 @@ HEADERS += $$PWD/qt5nodeinstanceserver.h \
|
||||
$$PWD/qt5captureimagenodeinstanceserver.h \
|
||||
$$PWD/qt5capturepreviewnodeinstanceserver.h \
|
||||
$$PWD/qt5testnodeinstanceserver.h \
|
||||
$$PWD/qt5bakelightsnodeinstanceserver.h \
|
||||
$$PWD/qt5informationnodeinstanceserver.h \
|
||||
$$PWD/qt5rendernodeinstanceserver.h \
|
||||
$$PWD/qt5previewnodeinstanceserver.h \
|
||||
@@ -60,6 +61,7 @@ SOURCES += $$PWD/qt5nodeinstanceserver.cpp \
|
||||
$$PWD/qt5captureimagenodeinstanceserver.cpp \
|
||||
$$PWD/qt5capturepreviewnodeinstanceserver.cpp \
|
||||
$$PWD/qt5testnodeinstanceserver.cpp \
|
||||
$$PWD/qt5bakelightsnodeinstanceserver.cpp \
|
||||
$$PWD/qt5informationnodeinstanceserver.cpp \
|
||||
$$PWD/qt5rendernodeinstanceserver.cpp \
|
||||
$$PWD/qt5previewnodeinstanceserver.cpp \
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "nodeinstanceserverdispatcher.h"
|
||||
|
||||
#include "qt5bakelightsnodeinstanceserver.h"
|
||||
#include "qt5captureimagenodeinstanceserver.h"
|
||||
#include "qt5capturepreviewnodeinstanceserver.h"
|
||||
#include "qt5informationnodeinstanceserver.h"
|
||||
@@ -170,6 +171,8 @@ std::unique_ptr<NodeInstanceServer> createNodeInstanceServer(
|
||||
return std::make_unique<Qt5InformationNodeInstanceServer>(nodeInstanceClient);
|
||||
else if (serverName == "previewmode")
|
||||
return std::make_unique<Qt5PreviewNodeInstanceServer>(nodeInstanceClient);
|
||||
else if (serverName == "bakelightsmode")
|
||||
return std::make_unique<Qt5BakeLightsNodeInstanceServer>(nodeInstanceClient);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include "qt5bakelightsnodeinstanceserver.h"
|
||||
|
||||
#if BAKE_LIGHTS_SUPPORTED
|
||||
#include "createscenecommand.h"
|
||||
#include "view3dactioncommand.h"
|
||||
|
||||
#include "nodeinstanceclientinterface.h"
|
||||
#include "puppettocreatorcommand.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFileInfo>
|
||||
#include <QLibraryInfo>
|
||||
#include <QProcess>
|
||||
#include <QQuickView>
|
||||
#include <QQuickItem>
|
||||
|
||||
#include <private/qquickdesignersupport_p.h>
|
||||
#include <private/qquick3dviewport_p.h>
|
||||
#endif
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
Qt5BakeLightsNodeInstanceServer::Qt5BakeLightsNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient) :
|
||||
Qt5NodeInstanceServer(nodeInstanceClient)
|
||||
{
|
||||
setSlowRenderTimerInterval(100000000);
|
||||
setRenderTimerInterval(100);
|
||||
}
|
||||
|
||||
#if BAKE_LIGHTS_SUPPORTED
|
||||
|
||||
Qt5BakeLightsNodeInstanceServer::~Qt5BakeLightsNodeInstanceServer()
|
||||
{
|
||||
cleanup();
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::createScene(const CreateSceneCommand &command)
|
||||
{
|
||||
initializeView();
|
||||
registerFonts(command.resourceUrl);
|
||||
setTranslationLanguage(command.language);
|
||||
setupScene(command);
|
||||
startRenderTimer();
|
||||
|
||||
// Set working directory to a temporary directory, as baking process creates a file there
|
||||
if (m_workingDir.isValid())
|
||||
QDir::setCurrent(m_workingDir.path());
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::view3DAction(const View3DActionCommand &command)
|
||||
{
|
||||
switch (command.type()) {
|
||||
case View3DActionType::SetBakeLightsView3D: {
|
||||
QString id = command.value().toString();
|
||||
const QList<ServerNodeInstance> allViews = allView3DInstances();
|
||||
for (const auto &view : allViews) {
|
||||
if (view.id() == id) {
|
||||
m_view3D = qobject_cast<QQuick3DViewport *>(view.internalObject());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_view3D)
|
||||
abort(tr("View3D not found: '%1'").arg(id));
|
||||
else
|
||||
startRenderTimer();
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::startRenderTimer()
|
||||
{
|
||||
if (timerId() != 0)
|
||||
killTimer(timerId());
|
||||
|
||||
int timerId = startTimer(renderTimerInterval());
|
||||
|
||||
setTimerId(timerId);
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::bakeLights()
|
||||
{
|
||||
if (!m_view3D) {
|
||||
abort(tr("Invalid View3D object set."));
|
||||
return;
|
||||
}
|
||||
|
||||
QQuick3DLightmapBaker::Callback callback = [this](QQuick3DLightmapBaker::BakingStatus status,
|
||||
std::optional<QString> msg, QQuick3DLightmapBaker::BakingControl *) {
|
||||
switch (status) {
|
||||
case QQuick3DLightmapBaker::BakingStatus::Progress:
|
||||
case QQuick3DLightmapBaker::BakingStatus::Warning:
|
||||
case QQuick3DLightmapBaker::BakingStatus::Error:
|
||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||
{PuppetToCreatorCommand::BakeLightsProgress, msg.value_or("")});
|
||||
break;
|
||||
case QQuick3DLightmapBaker::BakingStatus::Cancelled:
|
||||
abort(tr("Baking cancelled."));
|
||||
break;
|
||||
case QQuick3DLightmapBaker::BakingStatus::Complete:
|
||||
runDenoiser();
|
||||
break;
|
||||
default:
|
||||
qWarning() << __FUNCTION__ << "Unexpected light baking status received:"
|
||||
<< int(status) << msg.value_or("");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
QQuick3DLightmapBaker *baker = m_view3D->lightmapBaker();
|
||||
baker->bake(callback);
|
||||
|
||||
m_bakingStarted = true;
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::cleanup()
|
||||
{
|
||||
m_workingDir.remove();
|
||||
if (m_denoiser) {
|
||||
if (m_denoiser->state() == QProcess::Running)
|
||||
m_denoiser->terminate();
|
||||
m_denoiser->deleteLater();
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::abort(const QString &msg)
|
||||
{
|
||||
cleanup();
|
||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||
{PuppetToCreatorCommand::BakeLightsAborted, msg});
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::finish()
|
||||
{
|
||||
cleanup();
|
||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||
{PuppetToCreatorCommand::BakeLightsFinished, {}});
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::runDenoiser()
|
||||
{
|
||||
// Check if denoiser exists (as it is third party app)
|
||||
QString binPath = QLibraryInfo::path(QLibraryInfo::BinariesPath);
|
||||
#if defined(Q_OS_WIN)
|
||||
binPath += "/qlmdenoiser.exe";
|
||||
#elif defined(Q_OS_MACOS)
|
||||
// TODO: What is the path in mac?
|
||||
#else
|
||||
binPath += "/qlmdenoiser";
|
||||
#endif
|
||||
|
||||
QFileInfo fi(binPath);
|
||||
if (!fi.exists()) {
|
||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||
{PuppetToCreatorCommand::BakeLightsProgress,
|
||||
tr("Warning: Denoiser executable not found, cannot denoise baked lightmaps (%1).")
|
||||
.arg(binPath)});
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
|
||||
m_denoiser = new QProcess();
|
||||
|
||||
QObject::connect(m_denoiser, &QProcess::errorOccurred, this, [this](QProcess::ProcessError error) {
|
||||
m_workingDir.remove();
|
||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||
{PuppetToCreatorCommand::BakeLightsProgress,
|
||||
tr("Warning: An error occurred while running denoiser process!")});
|
||||
finish();
|
||||
});
|
||||
|
||||
QObject::connect(m_denoiser, &QProcess::finished, this, [this](int exitCode,
|
||||
QProcess::ExitStatus exitStatus) {
|
||||
if (exitCode == 0 && exitStatus == QProcess::NormalExit) {
|
||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||
{PuppetToCreatorCommand::BakeLightsProgress,
|
||||
tr("Denoising finished.")});
|
||||
} else {
|
||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||
{PuppetToCreatorCommand::BakeLightsProgress,
|
||||
tr("Warning: Denoiser process failed with exit code '%1'!").arg(exitCode)});
|
||||
}
|
||||
finish();
|
||||
});
|
||||
|
||||
nodeInstanceClient()->handlePuppetToCreatorCommand(
|
||||
{PuppetToCreatorCommand::BakeLightsProgress,
|
||||
tr("Denoising baked lightmaps...")});
|
||||
|
||||
m_denoiser->setWorkingDirectory(m_workingDir.path());
|
||||
m_denoiser->start(binPath, {"qlm_list.txt"});
|
||||
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::collectItemChangesAndSendChangeCommands()
|
||||
{
|
||||
static bool inFunction = false;
|
||||
|
||||
if (!rootNodeInstance().holdsGraphical())
|
||||
return;
|
||||
|
||||
if (!inFunction) {
|
||||
inFunction = true;
|
||||
|
||||
QQuickDesignerSupport::polishItems(quickWindow());
|
||||
|
||||
render();
|
||||
|
||||
inFunction = false;
|
||||
}
|
||||
}
|
||||
|
||||
void Qt5BakeLightsNodeInstanceServer::render()
|
||||
{
|
||||
// Render multiple times to make sure everything gets rendered correctly before baking
|
||||
if (++m_renderCount == 4) {
|
||||
bakeLights();
|
||||
} else {
|
||||
rootNodeInstance().updateDirtyNodeRecursive();
|
||||
renderWindow();
|
||||
if (m_bakingStarted)
|
||||
slowDownRenderTimer(); // No more renders needed
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -0,0 +1,57 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0 WITH Qt-GPL-exception-1.0
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "qt5nodeinstanceserver.h"
|
||||
|
||||
#if QUICK3D_MODULE && QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||
#include <QTemporaryDir>
|
||||
#define BAKE_LIGHTS_SUPPORTED 1
|
||||
#endif
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QProcess;
|
||||
class QQuick3DViewport;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
namespace QmlDesigner {
|
||||
|
||||
class Qt5BakeLightsNodeInstanceServer : public Qt5NodeInstanceServer
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Qt5BakeLightsNodeInstanceServer(NodeInstanceClientInterface *nodeInstanceClient);
|
||||
|
||||
#if BAKE_LIGHTS_SUPPORTED
|
||||
public:
|
||||
virtual ~Qt5BakeLightsNodeInstanceServer();
|
||||
|
||||
void createScene(const CreateSceneCommand &command) override;
|
||||
void view3DAction(const View3DActionCommand &command) override;
|
||||
|
||||
void render();
|
||||
|
||||
protected:
|
||||
void collectItemChangesAndSendChangeCommands() override;
|
||||
void startRenderTimer() override;
|
||||
void bakeLights();
|
||||
|
||||
private:
|
||||
void abort(const QString &msg);
|
||||
void runDenoiser();
|
||||
void finish();
|
||||
void cleanup();
|
||||
|
||||
QQuick3DViewport *m_view3D = nullptr;
|
||||
bool m_bakingStarted = false;
|
||||
int m_renderCount = 0;
|
||||
QProcess *m_denoiser = nullptr;
|
||||
QTemporaryDir m_workingDir;
|
||||
#else
|
||||
protected:
|
||||
void collectItemChangesAndSendChangeCommands() override {};
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace QmlDesigner
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "capturenodeinstanceserverdispatcher.h"
|
||||
#include "qt5bakelightsnodeinstanceserver.h"
|
||||
#include "qt5captureimagenodeinstanceserver.h"
|
||||
#include "qt5capturepreviewnodeinstanceserver.h"
|
||||
#include "qt5informationnodeinstanceserver.h"
|
||||
@@ -74,6 +75,9 @@ Qt5NodeInstanceClientProxy::Qt5NodeInstanceClientProxy(QObject *parent) :
|
||||
} else if (QCoreApplication::arguments().at(2) == QLatin1String("captureiconmode")) {
|
||||
setNodeInstanceServer(std::make_unique<Qt5CaptureImageNodeInstanceServer>(this));
|
||||
initializeSocket();
|
||||
} else if (QCoreApplication::arguments().at(2) == QLatin1String("bakelightsmode")) {
|
||||
setNodeInstanceServer(std::make_unique<Qt5BakeLightsNodeInstanceServer>(this));
|
||||
initializeSocket();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ using QHashValueType = size_t;
|
||||
friend class Qt4PreviewNodeInstanceServer;
|
||||
friend class Qt5InformationNodeInstanceServer;
|
||||
friend class Qt5NodeInstanceServer;
|
||||
friend class Qt5BakeLightsNodeInstanceServer;
|
||||
friend class Qt5PreviewNodeInstanceServer;
|
||||
friend class Qt5CapturePreviewNodeInstanceServer;
|
||||
friend class Qt5TestNodeInstanceServer;
|
||||
|
||||
Reference in New Issue
Block a user