1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:BSD$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** BSD License Usage |
18 | ** Alternatively, you may use this file under the terms of the BSD license |
19 | ** as follows: |
20 | ** |
21 | ** "Redistribution and use in source and binary forms, with or without |
22 | ** modification, are permitted provided that the following conditions are |
23 | ** met: |
24 | ** * Redistributions of source code must retain the above copyright |
25 | ** notice, this list of conditions and the following disclaimer. |
26 | ** * Redistributions in binary form must reproduce the above copyright |
27 | ** notice, this list of conditions and the following disclaimer in |
28 | ** the documentation and/or other materials provided with the |
29 | ** distribution. |
30 | ** * Neither the name of The Qt Company Ltd nor the names of its |
31 | ** contributors may be used to endorse or promote products derived |
32 | ** from this software without specific prior written permission. |
33 | ** |
34 | ** |
35 | ** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
36 | ** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
37 | ** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
38 | ** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
39 | ** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
40 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
41 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
42 | ** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
43 | ** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
44 | ** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
45 | ** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
46 | ** |
47 | ** $QT_END_LICENSE$ |
48 | ** |
49 | ****************************************************************************/ |
50 | |
51 | #include "qt3dwindow.h" |
52 | #include "qt3dwindow_p.h" |
53 | |
54 | #include <Qt3DCore/qaspectengine.h> |
55 | #include <Qt3DCore/qentity.h> |
56 | #include <Qt3DExtras/qforwardrenderer.h> |
57 | #include <Qt3DRender/qrendersettings.h> |
58 | #include <Qt3DRender/qrenderaspect.h> |
59 | #include <Qt3DInput/qinputaspect.h> |
60 | #include <Qt3DInput/qinputsettings.h> |
61 | #include <Qt3DLogic/qlogicaspect.h> |
62 | #include <Qt3DRender/qcamera.h> |
63 | #include <Qt3DRender/private/vulkaninstance_p.h> |
64 | #include <qopenglcontext.h> |
65 | #include <private/qrendersettings_p.h> |
66 | |
67 | #include <QEvent> |
68 | |
69 | #if QT_CONFIG(vulkan) |
70 | #include <QVulkanInstance> |
71 | #endif |
72 | |
73 | static void initResources() |
74 | { |
75 | #ifdef QT_STATIC |
76 | Q_INIT_RESOURCE(extras); |
77 | #endif |
78 | } |
79 | |
80 | QT_BEGIN_NAMESPACE |
81 | |
82 | namespace Qt3DExtras { |
83 | |
84 | Qt3DWindowPrivate::() |
85 | : m_aspectEngine(new Qt3DCore::QAspectEngine) |
86 | , m_renderAspect(new Qt3DRender::QRenderAspect) |
87 | , m_inputAspect(new Qt3DInput::QInputAspect) |
88 | , m_logicAspect(new Qt3DLogic::QLogicAspect) |
89 | , m_renderSettings(new Qt3DRender::QRenderSettings) |
90 | , m_forwardRenderer(new Qt3DExtras::QForwardRenderer) |
91 | , m_defaultCamera(new Qt3DRender::QCamera) |
92 | , m_inputSettings(new Qt3DInput::QInputSettings) |
93 | , m_root(new Qt3DCore::QEntity) |
94 | , m_userRoot(nullptr) |
95 | , m_initialized(false) |
96 | { |
97 | } |
98 | |
99 | Qt3DWindow::(QScreen *screen, Qt3DRender::API api) |
100 | : QWindow(*new Qt3DWindowPrivate(), nullptr) |
101 | { |
102 | Q_D(Qt3DWindow); |
103 | |
104 | initResources(); |
105 | |
106 | if (!d->parentWindow) |
107 | d->connectToScreen(topLevelScreen: screen ? screen : d->topLevelScreen.data()); |
108 | |
109 | setupWindowSurface(window: this, api); |
110 | |
111 | resize(w: 1024, h: 768); |
112 | d->m_aspectEngine->registerAspect(aspect: d->m_renderAspect); |
113 | d->m_aspectEngine->registerAspect(aspect: d->m_inputAspect); |
114 | d->m_aspectEngine->registerAspect(aspect: d->m_logicAspect); |
115 | |
116 | d->m_defaultCamera->setParent(d->m_root); |
117 | d->m_forwardRenderer->setCamera(d->m_defaultCamera); |
118 | d->m_forwardRenderer->setSurface(this); |
119 | d->m_renderSettings->setActiveFrameGraph(d->m_forwardRenderer); |
120 | d->m_inputSettings->setEventSource(this); |
121 | } |
122 | |
123 | Qt3DWindow::() |
124 | { |
125 | Q_D(Qt3DWindow); |
126 | delete d->m_aspectEngine; |
127 | } |
128 | |
129 | /*! |
130 | Registers the specified \a aspect. |
131 | */ |
132 | void Qt3DWindow::(Qt3DCore::QAbstractAspect *aspect) |
133 | { |
134 | Q_ASSERT(!isVisible()); |
135 | Q_D(Qt3DWindow); |
136 | d->m_aspectEngine->registerAspect(aspect); |
137 | } |
138 | |
139 | /*! |
140 | Registers the specified aspect \a name. |
141 | */ |
142 | void Qt3DWindow::(const QString &name) |
143 | { |
144 | Q_ASSERT(!isVisible()); |
145 | Q_D(Qt3DWindow); |
146 | d->m_aspectEngine->registerAspect(name); |
147 | } |
148 | |
149 | /*! |
150 | Sets the specified \a root entity of the scene. |
151 | */ |
152 | void Qt3DWindow::(Qt3DCore::QEntity *root) |
153 | { |
154 | Q_D(Qt3DWindow); |
155 | if (d->m_userRoot != root) { |
156 | if (d->m_userRoot != nullptr) |
157 | d->m_userRoot->setParent(static_cast<Qt3DCore::QNode*>(nullptr)); |
158 | if (root != nullptr) |
159 | root->setParent(d->m_root); |
160 | d->m_userRoot = root; |
161 | } |
162 | } |
163 | |
164 | /*! |
165 | Activates the specified \a activeFrameGraph. |
166 | */ |
167 | void Qt3DWindow::(Qt3DRender::QFrameGraphNode *activeFrameGraph) |
168 | { |
169 | Q_D(Qt3DWindow); |
170 | d->m_renderSettings->setActiveFrameGraph(activeFrameGraph); |
171 | } |
172 | |
173 | /*! |
174 | Returns the node of the active frame graph. |
175 | */ |
176 | Qt3DRender::QFrameGraphNode *Qt3DWindow::() const |
177 | { |
178 | Q_D(const Qt3DWindow); |
179 | return d->m_renderSettings->activeFrameGraph(); |
180 | } |
181 | |
182 | /*! |
183 | Returns the node of the default framegraph |
184 | */ |
185 | Qt3DExtras::QForwardRenderer *Qt3DWindow::() const |
186 | { |
187 | Q_D(const Qt3DWindow); |
188 | return d->m_forwardRenderer; |
189 | } |
190 | |
191 | Qt3DRender::QCamera *Qt3DWindow::() const |
192 | { |
193 | Q_D(const Qt3DWindow); |
194 | return d->m_defaultCamera; |
195 | } |
196 | |
197 | /*! |
198 | Returns the render settings of the 3D Window. |
199 | */ |
200 | Qt3DRender::QRenderSettings *Qt3DWindow::() const |
201 | { |
202 | Q_D(const Qt3DWindow); |
203 | return d->m_renderSettings; |
204 | } |
205 | |
206 | /*! |
207 | Manages the display events specified in \a e. |
208 | */ |
209 | void Qt3DWindow::(QShowEvent *e) |
210 | { |
211 | Q_D(Qt3DWindow); |
212 | if (!d->m_initialized) { |
213 | d->m_root->addComponent(comp: d->m_renderSettings); |
214 | d->m_root->addComponent(comp: d->m_inputSettings); |
215 | d->m_aspectEngine->setRootEntity(Qt3DCore::QEntityPtr(d->m_root)); |
216 | |
217 | d->m_initialized = true; |
218 | } |
219 | QWindow::showEvent(e); |
220 | } |
221 | |
222 | /*! |
223 | Resets the aspect ratio of the 3D window. |
224 | */ |
225 | void Qt3DWindow::(QResizeEvent *) |
226 | { |
227 | Q_D(Qt3DWindow); |
228 | d->m_defaultCamera->setAspectRatio(float(width()) / std::max(a: 1.f, b: static_cast<float>(height()))); |
229 | } |
230 | |
231 | /*! |
232 | \reimp |
233 | |
234 | Requests renderer to redraw if we are using OnDemand render policy. |
235 | */ |
236 | bool Qt3DWindow::(QEvent *e) |
237 | { |
238 | Q_D(Qt3DWindow); |
239 | const bool needsRedraw = (e->type() == QEvent::Expose || e->type() == QEvent::UpdateRequest); |
240 | if (needsRedraw && d->m_renderSettings->renderPolicy() == Qt3DRender::QRenderSettings::OnDemand) { |
241 | Qt3DRender::QRenderSettingsPrivate *p = static_cast<Qt3DRender::QRenderSettingsPrivate *>( |
242 | Qt3DCore::QNodePrivate::get(q: d->m_renderSettings)); |
243 | p->invalidateFrame(); |
244 | } |
245 | return QWindow::event(e); |
246 | } |
247 | |
248 | void (QWindow *window, Qt3DRender::API api) noexcept |
249 | { |
250 | // If the user pass an API through the environment, we use that over the one passed as argument. |
251 | const auto userRequestedApi = qgetenv(varName: "QT3D_RHI_DEFAULT_API" ).toLower(); |
252 | if (!userRequestedApi.isEmpty()) { |
253 | if (userRequestedApi == QByteArrayLiteral("opengl" )) { |
254 | api = Qt3DRender::API::OpenGL; |
255 | } else if (userRequestedApi == QByteArrayLiteral("vulkan" )) { |
256 | api = Qt3DRender::API::Vulkan; |
257 | } else if (userRequestedApi == QByteArrayLiteral("metal" )) { |
258 | api = Qt3DRender::API::Metal; |
259 | } else if (userRequestedApi == QByteArrayLiteral("d3d11" )) { |
260 | api = Qt3DRender::API::DirectX; |
261 | } else if (userRequestedApi == QByteArrayLiteral("null" )) { |
262 | api = Qt3DRender::API::Null; |
263 | } |
264 | } |
265 | |
266 | // We have to set the environment so that the backend is able to read it. |
267 | // Qt6: FIXME |
268 | switch (api) |
269 | { |
270 | case Qt3DRender::API::OpenGL: |
271 | qputenv(varName: "QT3D_RHI_DEFAULT_API" , value: "opengl" ); |
272 | window->setSurfaceType(QSurface::OpenGLSurface); |
273 | break; |
274 | case Qt3DRender::API::DirectX: |
275 | qputenv(varName: "QT3D_RHI_DEFAULT_API" , value: "d3d11" ); |
276 | window->setSurfaceType(QSurface::OpenGLSurface); |
277 | break; |
278 | case Qt3DRender::API::Null: |
279 | qputenv(varName: "QT3D_RHI_DEFAULT_API" , value: "null" ); |
280 | window->setSurfaceType(QSurface::OpenGLSurface); |
281 | break; |
282 | case Qt3DRender::API::Metal: |
283 | qputenv(varName: "QT3D_RHI_DEFAULT_API" , value: "metal" ); |
284 | window->setSurfaceType(QSurface::MetalSurface); |
285 | break; |
286 | #if QT_CONFIG(vulkan) |
287 | case Qt3DRender::API::Vulkan: |
288 | { |
289 | qputenv(varName: "QT3D_RHI_DEFAULT_API" , value: "vulkan" ); |
290 | window->setSurfaceType(QSurface::VulkanSurface); |
291 | window->setVulkanInstance(&Qt3DRender::staticVulkanInstance()); |
292 | break; |
293 | } |
294 | #endif |
295 | default: |
296 | break; |
297 | } |
298 | QSurfaceFormat format = QSurfaceFormat::defaultFormat(); |
299 | #ifdef QT_OPENGL_ES_2 |
300 | format.setRenderableType(QSurfaceFormat::OpenGLES); |
301 | #else |
302 | if (QOpenGLContext::openGLModuleType() == QOpenGLContext::LibGL) { |
303 | format.setVersion(major: 4, minor: 3); |
304 | format.setProfile(QSurfaceFormat::CoreProfile); |
305 | } else |
306 | #endif |
307 | if (!userRequestedApi.isEmpty()) { |
308 | // This is used for RHI |
309 | format.setVersion(major: 1, minor: 0); |
310 | } |
311 | |
312 | format.setDepthBufferSize(24); |
313 | format.setSamples(4); |
314 | format.setStencilBufferSize(8); |
315 | window->setFormat(format); |
316 | QSurfaceFormat::setDefaultFormat(format); |
317 | } |
318 | |
319 | } // Qt3DExtras |
320 | |
321 | QT_END_NAMESPACE |
322 | |