1// Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
4#include <Qt3DQuickExtras/qt3dquickwindow.h>
5#include <Qt3DExtras/Qt3DWindow>
6#include "qt3dquickwindow_p.h"
7#include <Qt3DQuick/QQmlAspectEngine>
8#include <Qt3DQuickExtras/qt3dquickwindow.h>
9#include <Qt3DInput/qinputaspect.h>
10#include <Qt3DInput/qinputsettings.h>
11#include <Qt3DLogic/qlogicaspect.h>
12#include <Qt3DRender/qcamera.h>
13#include <Qt3DRender/qrenderaspect.h>
14#include <Qt3DRender/qrendersurfaceselector.h>
15#include <Qt3DCore/qcoreaspect.h>
16#include <QtGui/QGuiApplication>
17#include <QtGui/QScreen>
18#include <qopenglcontext.h>
19#include <QtQml/QQmlContext>
20#include <QtQml/qqmlincubator.h>
21
22#include <Qt3DQuickExtras/private/qt3dquickwindowlogging_p.h>
23#include <Qt3DRender/private/qrendersurfaceselector_p.h>
24#include <Qt3DRender/private/qrenderaspect_p.h>
25
26QT_BEGIN_NAMESPACE
27
28namespace Qt3DExtras {
29
30namespace Quick {
31
32namespace {
33
34class Qt3DQuickWindowIncubationController : public QObject, public QQmlIncubationController
35{
36 Q_OBJECT
37public:
38 explicit Qt3DQuickWindowIncubationController(QObject *parent = nullptr)
39 : QObject(parent)
40 , m_incubationTime(std::max(a: 1, b: int(1000 / QGuiApplication::primaryScreen()->refreshRate()) / 3))
41 {
42 startTimer(interval: QGuiApplication::primaryScreen()->refreshRate());
43 }
44
45 void timerEvent(QTimerEvent *) override
46 {
47 incubateFor(msecs: m_incubationTime);
48 }
49
50private:
51 const int m_incubationTime;
52};
53
54} // anonymous
55
56Qt3DQuickWindowPrivate::Qt3DQuickWindowPrivate()
57 : m_engine(nullptr)
58 , m_renderAspect(nullptr)
59 , m_inputAspect(nullptr)
60 , m_logicAspect(nullptr)
61 , m_initialized(false)
62 , m_cameraAspectRatioMode(Qt3DQuickWindow::AutomaticAspectRatio)
63 , m_incubationController(nullptr)
64{
65}
66
67Qt3DQuickWindow::Qt3DQuickWindow(QWindow *parent)
68 : QWindow(*new Qt3DQuickWindowPrivate(), parent)
69{
70 Q_D(Qt3DQuickWindow);
71
72 resize(w: 1024, h: 768);
73
74 Qt3DExtras::setupWindowSurface(window: this, Qt3DRender::API::RHI);
75
76 auto coreAspect = new Qt3DCore::QCoreAspect;
77 d->m_renderAspect = new Qt3DRender::QRenderAspect;
78 if (parent && parent->screen())
79 static_cast<Qt3DRender::QRenderAspectPrivate*>(Qt3DRender::QRenderAspectPrivate::get(q: d->m_renderAspect))->m_screen = parent->screen();
80 d->m_inputAspect = new Qt3DInput::QInputAspect;
81 d->m_logicAspect = new Qt3DLogic::QLogicAspect;
82 d->m_engine = new Qt3DCore::Quick::QQmlAspectEngine;
83
84 d->m_engine->aspectEngine()->registerAspect(aspect: coreAspect);
85 d->m_engine->aspectEngine()->registerAspect(aspect: d->m_renderAspect);
86 d->m_engine->aspectEngine()->registerAspect(aspect: d->m_inputAspect);
87 d->m_engine->aspectEngine()->registerAspect(aspect: d->m_logicAspect);
88}
89
90Qt3DQuickWindow::~Qt3DQuickWindow()
91{
92 Q_D(Qt3DQuickWindow);
93 delete d->m_engine;
94}
95
96void Qt3DQuickWindow::registerAspect(Qt3DCore::QAbstractAspect *aspect)
97{
98 Q_ASSERT(!isVisible());
99 Q_D(Qt3DQuickWindow);
100 d->m_engine->aspectEngine()->registerAspect(aspect);
101}
102
103void Qt3DQuickWindow::registerAspect(const QString &name)
104{
105 Q_ASSERT(!isVisible());
106 Q_D(Qt3DQuickWindow);
107 d->m_engine->aspectEngine()->registerAspect(name);
108}
109
110void Qt3DQuickWindow::setSource(const QUrl &source)
111{
112 Q_D(Qt3DQuickWindow);
113 d->m_source = source;
114}
115
116Qt3DCore::Quick::QQmlAspectEngine *Qt3DQuickWindow::engine() const
117{
118 Q_D(const Qt3DQuickWindow);
119 return d->m_engine;
120}
121
122void Qt3DQuickWindow::setCameraAspectRatioMode(CameraAspectRatioMode mode)
123{
124 Q_D(Qt3DQuickWindow);
125 if (d->m_cameraAspectRatioMode == mode)
126 return;
127
128 d->m_cameraAspectRatioMode = mode;
129 setCameraAspectModeHelper();
130 emit cameraAspectRatioModeChanged(mode);
131}
132
133Qt3DQuickWindow::CameraAspectRatioMode Qt3DQuickWindow::cameraAspectRatioMode() const
134{
135 Q_D(const Qt3DQuickWindow);
136 return d->m_cameraAspectRatioMode;
137}
138
139void Qt3DQuickWindow::showEvent(QShowEvent *e)
140{
141 Q_D(Qt3DQuickWindow);
142 if (!d->m_initialized) {
143
144 // Connect to the QQmlAspectEngine's statusChanged signal so that when the QML is loaded
145 // and th eobjects hav ebeen instantiated, but before we set them on the QAspectEngine we
146 // can swoop in and set the window surface and camera on the framegraph and ensure the camera
147 // respects the window's aspect ratio
148 connect(sender: d->m_engine, signal: &Qt3DCore::Quick::QQmlAspectEngine::sceneCreated,
149 context: this, slot: &Qt3DQuickWindow::onSceneCreated);
150
151 d->m_engine->setSource(d->m_source);
152
153 // Set the QQmlIncubationController on the window
154 // to benefit from asynchronous incubation
155 if (!d->m_incubationController)
156 d->m_incubationController = new Qt3DQuickWindowIncubationController(this);
157
158 d->m_engine->qmlEngine()->setIncubationController(d->m_incubationController);
159
160 d->m_initialized = true;
161 }
162 QWindow::showEvent(e);
163}
164
165void Qt3DQuickWindow::onSceneCreated(QObject *rootObject)
166{
167 Q_ASSERT(rootObject);
168 Q_D(Qt3DQuickWindow);
169
170 setWindowSurface(rootObject);
171
172 if (d->m_cameraAspectRatioMode == AutomaticAspectRatio) {
173 // Set aspect ratio of first camera to match the window
174 QList<Qt3DRender::QCamera *> cameras
175 = rootObject->findChildren<Qt3DRender::QCamera *>();
176 if (cameras.isEmpty()) {
177 qCDebug(QuickWindow) << "No camera found";
178 } else {
179 d->m_camera = cameras.first();
180 setCameraAspectModeHelper();
181 }
182 }
183
184 // Set ourselves up as a source of input events for the input aspect
185 Qt3DInput::QInputSettings *inputSettings = rootObject->findChild<Qt3DInput::QInputSettings *>();
186 if (inputSettings) {
187 inputSettings->setEventSource(this);
188 } else {
189 qCDebug(QuickWindow) << "No Input Settings found, keyboard and mouse events won't be handled";
190 }
191}
192
193void Qt3DQuickWindow::setWindowSurface(QObject *rootObject)
194{
195 Qt3DRender::QRenderSurfaceSelector *surfaceSelector = Qt3DRender::QRenderSurfaceSelectorPrivate::find(rootObject);
196 if (surfaceSelector)
197 surfaceSelector->setSurface(this);
198}
199
200void Qt3DQuickWindow::setCameraAspectModeHelper()
201{
202 Q_D(Qt3DQuickWindow);
203 switch (d->m_cameraAspectRatioMode) {
204 case AutomaticAspectRatio:
205 connect(sender: this, signal: &QWindow::widthChanged, context: this, slot: &Qt3DQuickWindow::updateCameraAspectRatio);
206 connect(sender: this, signal: &QWindow::heightChanged, context: this, slot: &Qt3DQuickWindow::updateCameraAspectRatio);
207 // Update the aspect ratio the first time the surface is set
208 updateCameraAspectRatio();
209 break;
210 case UserAspectRatio:
211 disconnect(sender: this, signal: &QWindow::widthChanged, receiver: this, slot: &Qt3DQuickWindow::updateCameraAspectRatio);
212 disconnect(sender: this, signal: &QWindow::heightChanged, receiver: this, slot: &Qt3DQuickWindow::updateCameraAspectRatio);
213 break;
214 }
215}
216
217void Qt3DQuickWindow::updateCameraAspectRatio()
218{
219 Q_D(Qt3DQuickWindow);
220 if (d->m_camera) {
221 d->m_camera->setAspectRatio(static_cast<float>(width()) /
222 std::max(a: 1.f, b: static_cast<float>(height())));
223 }
224}
225
226} // Quick
227
228} // Qt3DExtras
229
230QT_END_NAMESPACE
231
232#include "moc_qt3dquickwindow.cpp"
233#include "qt3dquickwindow.moc"
234

source code of qt3d/src/quick3d/quick3dextras/qt3dquickwindow.cpp