1 | // Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "qrendersurfaceselector.h" |
5 | #include "qrendersurfaceselector_p.h" |
6 | |
7 | #include <QtGui/QWindow> |
8 | #include <QtGui/QScreen> |
9 | #include <QtGui/QOffscreenSurface> |
10 | #include <Qt3DCore/qentity.h> |
11 | #include <Qt3DRender/qrendersettings.h> |
12 | |
13 | QT_BEGIN_NAMESPACE |
14 | |
15 | namespace Qt3DRender { |
16 | |
17 | /*! |
18 | \class Qt3DRender::QRenderSurfaceSelector |
19 | \inmodule Qt3DRender |
20 | \brief Provides a way of specifying the render surface. |
21 | \since 5.7 |
22 | |
23 | The Qt3DRender::QRenderSurfaceSelector can be used to select the surface, where |
24 | Qt3D renders the content. The surface can either be window surface or offscreen |
25 | surface. The externalRenderTargetSize is used to specify the actual size of the |
26 | surface when offscreen surface is used. |
27 | |
28 | When DPI scaling is used by the system, the logical surface size, which is used |
29 | by mouse events, and the actual 'physical' size of the surface can differ. |
30 | The surfacePixelRatio is the factor to convert the logical size to the physical |
31 | size. |
32 | |
33 | \sa QWindow, QOffscreenSurface, QSurface |
34 | */ |
35 | |
36 | /*! |
37 | \qmltype RenderSurfaceSelector |
38 | \inqmlmodule Qt3D.Render |
39 | \since 5.7 |
40 | \instantiates Qt3DRender::QRenderSurfaceSelector |
41 | \inherits FrameGraphNode |
42 | \brief Provides a way of specifying the render surface. |
43 | |
44 | The RenderSurfaceSelector can be used to select the surface, where |
45 | Qt3D renders the content. The surface can either be window surface or offscreen |
46 | surface. The externalRenderTargetSize is used to specify the actual size of the |
47 | render target when offscreen surface is used. |
48 | |
49 | When DPI scaling is used by the system, the logical surface size, which is used |
50 | by mouse events, and the actual 'physical' size of the surface can differ. |
51 | The surfacePixelRatio is the factor to convert the logical size to the physical |
52 | size. |
53 | */ |
54 | |
55 | /*! \qmlproperty QSurface Qt3D.Render::RenderSurfaceSelector::surface |
56 | Holds the surface. |
57 | */ |
58 | |
59 | /*! \qmlproperty size Qt3D.Render::RenderSurfaceSelector::externalRenderTargetSize |
60 | |
61 | Holds the size of the external render target. |
62 | */ |
63 | |
64 | /*! \qmlproperty real Qt3D.Render::RenderSurfaceSelector::surfacePixelRatio |
65 | |
66 | Holds the surfacePixelRatio of the surface. |
67 | */ |
68 | |
69 | /*! |
70 | \property QRenderSurfaceSelector::surface |
71 | Holds the surface |
72 | */ |
73 | |
74 | /*! |
75 | \property QRenderSurfaceSelector::externalRenderTargetSize |
76 | Holds the size of the external render target. |
77 | */ |
78 | |
79 | /*! \property QRenderSurfaceSelector::surfacePixelRatio |
80 | |
81 | Holds the surfacePixelRatio of the surface. |
82 | */ |
83 | |
84 | QRenderSurfaceSelectorPrivate::QRenderSurfaceSelectorPrivate() |
85 | : Qt3DRender::QFrameGraphNodePrivate() |
86 | , m_surface(nullptr) |
87 | , m_surfaceEventFilter(new Qt3DRender::Render::PlatformSurfaceFilter()) |
88 | , m_surfacePixelRatio(1.0f) |
89 | { |
90 | } |
91 | |
92 | QRenderSurfaceSelectorPrivate::~QRenderSurfaceSelectorPrivate() |
93 | { |
94 | QObject::disconnect(m_heightConn); |
95 | QObject::disconnect(m_widthConn); |
96 | QObject::disconnect(m_screenConn); |
97 | } |
98 | |
99 | QRenderSurfaceSelector *QRenderSurfaceSelectorPrivate::find(QObject *rootObject) |
100 | { |
101 | QFrameGraphNode *frameGraphRoot = qobject_cast<QFrameGraphNode *>(object: rootObject); |
102 | |
103 | if (!frameGraphRoot) { |
104 | auto rendererSettings = rootObject->findChild<Qt3DRender::QRenderSettings *>(); |
105 | if (!rendererSettings) { |
106 | qWarning() << "No renderer settings component found" ; |
107 | return nullptr; |
108 | } |
109 | |
110 | frameGraphRoot = rendererSettings->activeFrameGraph(); |
111 | if (!frameGraphRoot) { |
112 | qWarning() << "No active frame graph found" ; |
113 | return nullptr; |
114 | } |
115 | } |
116 | |
117 | auto surfaceSelector = qobject_cast<Qt3DRender::QRenderSurfaceSelector *>(object: frameGraphRoot); |
118 | if (!surfaceSelector) |
119 | surfaceSelector = frameGraphRoot->findChild<Qt3DRender::QRenderSurfaceSelector *>(); |
120 | |
121 | if (!surfaceSelector) |
122 | qWarning() << "No render surface selector found in frame graph" ; |
123 | |
124 | return surfaceSelector; |
125 | } |
126 | |
127 | void QRenderSurfaceSelectorPrivate::setExternalRenderTargetSize(const QSize &size) |
128 | { |
129 | m_externalRenderTargetSize = size; |
130 | } |
131 | |
132 | /*! |
133 | Constructs QRenderSurfaceSelector with given \a parent. |
134 | */ |
135 | QRenderSurfaceSelector::QRenderSurfaceSelector(Qt3DCore::QNode *parent) |
136 | : Qt3DRender::QFrameGraphNode(*new QRenderSurfaceSelectorPrivate, parent) |
137 | { |
138 | } |
139 | |
140 | /*! |
141 | \internal |
142 | */ |
143 | QRenderSurfaceSelector::~QRenderSurfaceSelector() |
144 | { |
145 | } |
146 | |
147 | /*! |
148 | \internal |
149 | */ |
150 | QRenderSurfaceSelector::QRenderSurfaceSelector(QRenderSurfaceSelectorPrivate &dd, Qt3DCore::QNode *parent) |
151 | : Qt3DRender::QFrameGraphNode(dd, parent) |
152 | { |
153 | } |
154 | |
155 | QObject *QRenderSurfaceSelector::surface() const |
156 | { |
157 | Q_D(const QRenderSurfaceSelector); |
158 | QObject *surfaceObj = nullptr; |
159 | if (!d->m_surface) |
160 | return surfaceObj; |
161 | |
162 | switch (d->m_surface->surfaceClass()) { |
163 | case QSurface::Window: |
164 | surfaceObj = static_cast<QWindow *>(d->m_surface); |
165 | break; |
166 | |
167 | case QSurface::Offscreen: |
168 | surfaceObj = static_cast<QOffscreenSurface *>(d->m_surface); |
169 | break; |
170 | } |
171 | |
172 | return surfaceObj; |
173 | } |
174 | |
175 | /*! |
176 | Sets \a surfaceObject. |
177 | */ |
178 | void QRenderSurfaceSelector::setSurface(QObject *surfaceObject) |
179 | { |
180 | Q_D(QRenderSurfaceSelector); |
181 | QSurface *surface = nullptr; |
182 | if (surfaceObject) { |
183 | QWindow *window = qobject_cast<QWindow *>(o: surfaceObject); |
184 | if (window) { |
185 | surface = static_cast<QSurface *>(window); |
186 | } else { |
187 | QOffscreenSurface *offscreen = qobject_cast<QOffscreenSurface *>(object: surfaceObject); |
188 | if (offscreen) |
189 | surface = static_cast<QSurface *>(offscreen); |
190 | } |
191 | |
192 | Q_ASSERT_X(surface, Q_FUNC_INFO, "surfaceObject is not a valid QSurface object" ); |
193 | } |
194 | |
195 | if (d->m_surface == surface) |
196 | return; |
197 | |
198 | if (d->m_surface && d->m_surface->surfaceClass() == QSurface::Window) { |
199 | QWindow *prevWindow = static_cast<QWindow *>(d->m_surface); |
200 | if (prevWindow) { |
201 | QObject::disconnect(d->m_widthConn); |
202 | QObject::disconnect(d->m_heightConn); |
203 | QObject::disconnect(d->m_screenConn); |
204 | } |
205 | } |
206 | d->m_surface = surface; |
207 | |
208 | // The platform surface filter only deals with QObject |
209 | // We assume therefore that our surface is actually a QObject underneath |
210 | if (d->m_surface) { |
211 | switch (d->m_surface->surfaceClass()) { |
212 | case QSurface::Window: { |
213 | QWindow *window = static_cast<QWindow *>(d->m_surface); |
214 | d->m_surfaceEventFilter->setSurface(window); |
215 | |
216 | if (window) { |
217 | d->m_widthConn = QObject::connect(sender: window, signal: &QWindow::widthChanged, slot: [=] (int) { |
218 | d->update(); |
219 | }); |
220 | d->m_heightConn = QObject::connect(sender: window, signal: &QWindow::heightChanged, slot: [=] (int) { |
221 | d->update(); |
222 | }); |
223 | d->m_screenConn = QObject::connect(sender: window, signal: &QWindow::screenChanged, slot: [this] (QScreen *screen) { |
224 | if (screen && !qFuzzyCompare(p1: surfacePixelRatio(), p2: float(screen->devicePixelRatio()))) |
225 | setSurfacePixelRatio(float(screen->devicePixelRatio())); |
226 | }); |
227 | setSurfacePixelRatio(float(window->devicePixelRatio())); |
228 | } |
229 | |
230 | break; |
231 | } |
232 | case QSurface::Offscreen: { |
233 | d->m_surfaceEventFilter->setSurface(static_cast<QOffscreenSurface *>(d->m_surface)); |
234 | break; |
235 | } |
236 | |
237 | default: |
238 | Q_UNREACHABLE(); |
239 | break; |
240 | } |
241 | } else { |
242 | QWindow *nullWindow = nullptr; |
243 | d->m_surfaceEventFilter->setSurface(nullWindow); |
244 | } |
245 | emit surfaceChanged(surface: surfaceObject); |
246 | } |
247 | |
248 | QSize QRenderSurfaceSelector::externalRenderTargetSize() const |
249 | { |
250 | Q_D(const QRenderSurfaceSelector); |
251 | return d->externalRenderTargetSize(); |
252 | } |
253 | |
254 | void QRenderSurfaceSelector::setSurfacePixelRatio(float ratio) |
255 | { |
256 | Q_D(QRenderSurfaceSelector); |
257 | if (qFuzzyCompare(p1: d->m_surfacePixelRatio, p2: ratio)) |
258 | return; |
259 | d->m_surfacePixelRatio = ratio; |
260 | emit surfacePixelRatioChanged(ratio); |
261 | } |
262 | |
263 | float QRenderSurfaceSelector::surfacePixelRatio() const |
264 | { |
265 | Q_D(const QRenderSurfaceSelector); |
266 | return d->m_surfacePixelRatio; |
267 | } |
268 | /*! |
269 | Sets render target \a size if different than underlying surface size. |
270 | Tells picking the correct size. |
271 | */ |
272 | void QRenderSurfaceSelector::setExternalRenderTargetSize(const QSize &size) |
273 | { |
274 | Q_D(QRenderSurfaceSelector); |
275 | if (size != d->m_externalRenderTargetSize) { |
276 | d->setExternalRenderTargetSize(size); |
277 | emit externalRenderTargetSizeChanged(size); |
278 | } |
279 | } |
280 | |
281 | } // namespace Qt3DRender |
282 | |
283 | QT_END_NAMESPACE |
284 | |
285 | #include "moc_qrendersurfaceselector.cpp" |
286 | |