1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include "qquick3dlightmapbaker_p.h"
5#include "qquick3dviewport_p.h"
6
7QT_BEGIN_NAMESPACE
8
9QQuick3DLightmapBaker::QQuick3DLightmapBaker(QQuick3DViewport *view) :
10 QObject(view), m_bakingControl(new BakingControl()), m_view(view)
11{
12
13}
14
15QQuick3DLightmapBaker::~QQuick3DLightmapBaker()
16{
17 if (m_lmWindow) {
18 m_lmWindow->close();
19 delete m_lmWindow;
20 }
21
22 delete m_bakingControl;
23}
24
25/*!
26 Triggers a new frame where lightmap baking will take place.
27 Will call \a callback for feedback and handling.
28
29 \note Lightmap baking is a slow blocking operation running on the
30 render thread. The application will be frozen until completed.
31*/
32void QQuick3DLightmapBaker::bake(Callback callback)
33{
34 Q_ASSERT(m_view);
35 m_bakingRequested = true;
36 m_bakingControl->reset();
37 m_callback = callback;
38 updateView();
39}
40
41/*!
42 \internal
43*/
44void QQuick3DLightmapBaker::bake()
45{
46 Q_ASSERT(m_view);
47 m_bakingRequested = true;
48 m_bakingControl->reset();
49
50 m_windowCancelRequested = false;
51 if (m_lmWindow)
52 m_lmWindow->close();
53
54 m_lmWindow = new QQuickView();
55 m_lmWindow->setSource(QUrl::fromLocalFile(QStringLiteral(":/qt-project.org/imports/QtQuick3D/Helpers/impl/LightmapperOutputWindow.qml")));
56 m_lmWindow->show();
57 m_lmWindow->setProperty(name: "width", value: 400);
58 m_lmWindow->setProperty(name: "height", value: 400);
59
60 QObject *rootObject = m_lmWindow->rootObject();
61 QObject *cancelButton = rootObject->findChild<QObject*>(QStringLiteral("cancelButton"));
62 if (cancelButton)
63 QObject::connect(sender: cancelButton, SIGNAL(clicked()), receiver: this, SLOT(onLmCancelButtonClicked()));
64
65 QObject::connect(sender: m_lmWindow, signal: &QQuickWindow::closing, context: this, slot: &QQuick3DLightmapBaker::onLmWindowClosing);
66
67 m_callback = [this, rootObject] (
68 BakingStatus status,
69 std::optional<QString> msg,
70 BakingControl *bakingControl) {
71
72 QQuickWindow *window = m_view->window();
73 if (status == BakingStatus::Complete) {
74 QMetaObject::invokeMethod(obj: window, member: "releaseResources", c: Qt::QueuedConnection);
75 updateView();
76 QQuickWindowPrivate::get(c: window)->updatesEnabled = true;
77 } else if (status != BakingStatus::None) {
78 if (status == BakingStatus::Progress)
79 QQuickWindowPrivate::get(c: window)->updatesEnabled = false;
80 else if (status == BakingStatus::Cancelled)
81 QQuickWindowPrivate::get(c: window)->updatesEnabled = true;
82
83 if (msg.has_value()) {
84 QString result = msg.value();
85 if (status == BakingStatus::Warning)
86 result.prepend(QStringLiteral("Warning: "));
87 else if (status == BakingStatus::Error)
88 result.prepend(QStringLiteral("Error: "));
89
90 QMetaObject::invokeMethod(obj: rootObject,
91 member: "appendText",
92 Q_ARG(QString, result));
93 }
94
95 if (m_windowCancelRequested && !bakingControl->isCancelled())
96 bakingControl->requestCancel();
97 }
98 };
99
100 updateView();
101}
102
103void QQuick3DLightmapBaker::updateView()
104{
105 QMetaObject::invokeMethod(obj: m_view, member: "update", c: Qt::QueuedConnection);
106}
107
108void QQuick3DLightmapBaker::onLmCancelButtonClicked()
109{
110 if (m_windowCancelRequested)
111 return;
112
113 m_windowCancelRequested = true;
114}
115
116void QQuick3DLightmapBaker::onLmWindowClosing(QQuickCloseEvent *event)
117{
118 Q_UNUSED(event);
119
120 onLmCancelButtonClicked();
121}
122
123void QQuick3DLightmapBaker::BakingControl::reset() {
124 if (isCancelled())
125 cancelFlag.store(i: 0, m: std::memory_order_release);
126}
127
128void QQuick3DLightmapBaker::BakingControl::requestCancel() {
129 if (!isCancelled())
130 cancelFlag.store(i: 1, m: std::memory_order_release);
131}
132
133bool QQuick3DLightmapBaker::BakingControl::isCancelled() const {
134 return cancelFlag.load(m: std::memory_order_acquire) == 1;
135}
136
137QT_END_NAMESPACE
138

source code of qtquick3d/src/quick3d/qquick3dlightmapbaker.cpp