1// Copyright (C) 2016 The Qt Company Ltd.
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 <Qt3DRender/qrendercapture.h>
5#include <Qt3DRender/private/qrendercapture_p.h>
6
7#include <QPointer>
8#include <QMutexLocker>
9
10QT_BEGIN_NAMESPACE
11
12namespace Qt3DRender {
13
14/*!
15 * \class Qt3DRender::QRenderCapture
16 * \inheaderfile Qt3DRender/QRenderCapture
17 * \inmodule Qt3DRender
18 *
19 * \brief Frame graph node for render capture.
20 *
21 * The QRenderCapture is used to capture rendering into an image at any render stage.
22 * Capturing must be initiated by the user and one image is returned per capture request.
23 * User can issue multiple render capture requests simultaniously, but only one request
24 * is served per QRenderCapture instance per frame.
25 *
26 * \since 5.8
27 */
28
29/*!
30 * \qmltype RenderCapture
31 * \instantiates Qt3DRender::QRenderCapture
32 * \inherits FrameGraphNode
33 * \inqmlmodule Qt3D.Render
34 * \since 5.8
35 * \brief Capture rendering.
36 */
37
38/*!
39 * \class Qt3DRender::QRenderCaptureReply
40 * \inheaderfile Qt3DRender/QRenderCaptureReply
41 * \inmodule Qt3DRender
42 *
43 * \brief Receives the result of render capture request.
44 *
45 * An object, which receives the image from QRenderCapture::requestCapture.
46 *
47 * \since 5.8
48 */
49
50/*!
51 * \qmltype RenderCaptureReply
52 * \instantiates Qt3DRender::QRenderCaptureReply
53 * \inherits QObject
54 * \inqmlmodule Qt3D.Render
55 * \since 5.8
56 * \brief Receives render capture result.
57 */
58
59/*!
60 * \qmlproperty variant Qt3D.Render::RenderCaptureReply::image
61 *
62 * Holds the image, which was produced as a result of render capture.
63 */
64
65/*!
66 * \qmlproperty int Qt3D.Render::RenderCaptureReply::captureId
67 *
68 * Holds the captureId, which was passed to the renderCapture.
69 */
70
71/*!
72 * \qmlproperty bool Qt3D.Render::RenderCaptureReply::complete
73 *
74 * Holds the complete state of the render capture.
75 */
76
77/*!
78 * \qmlmethod bool Qt3D.Render::RenderCaptureReply::saveImage(fileName)
79 *
80 * Saves the render capture result as an image to \a fileName.
81 * Returns true if the image was successfully saved; otherwise returns false.
82 *
83 * \since 5.9
84 */
85
86/*!
87 * \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture(int captureId)
88 * \deprecated
89 *
90 * Used to request render capture. User can specify a \a captureId to identify
91 * the request. The requestId does not have to be unique. Only one render capture result
92 * is produced per requestCapture call even if the frame graph has multiple leaf nodes.
93 * The function returns a QRenderCaptureReply object, which receives the captured image
94 * when it is done. The user is responsible for deallocating the returned object.
95 */
96
97/*!
98 * \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture()
99 *
100 * Used to request render capture. Only one render capture result is produced per
101 * requestCapture call even if the frame graph has multiple leaf nodes.
102 * The function returns a QRenderCaptureReply object, which receives the captured image
103 * when it is done. The user is responsible for deallocating the returned object.
104 */
105
106/*!
107 * \qmlmethod RenderCaptureReply Qt3D.Render::RenderCapture::requestCapture(Rect rect)
108 *
109 * Used to request render capture from a specified \a rect. Only one render capture
110 * result is produced per requestCapture call even if the frame graph has multiple leaf nodes.
111 * The function returns a QRenderCaptureReply object, which receives the captured image
112 * when it is done. The user is responsible for deallocating the returned object.
113 */
114
115/*!
116 * \internal
117 */
118QRenderCaptureReplyPrivate::QRenderCaptureReplyPrivate()
119 : QObjectPrivate()
120 , m_captureId(0)
121 , m_complete(false)
122{
123
124}
125
126/*!
127 * The constructor creates an instance with the specified \a parent.
128 */
129QRenderCaptureReply::QRenderCaptureReply(QObject *parent)
130 : QObject(* new QRenderCaptureReplyPrivate, parent)
131{
132
133}
134
135/*!
136 * \property QRenderCaptureReply::image
137 *
138 * Holds the image, which was produced as a result of render capture.
139 */
140QImage QRenderCaptureReply::image() const
141{
142 Q_D(const QRenderCaptureReply);
143 return d->m_image;
144}
145
146/*!
147 * \property QRenderCaptureReply::captureId
148 *
149 * Holds the captureId, which was passed to the renderCapture.
150 */
151int QRenderCaptureReply::captureId() const
152{
153 Q_D(const QRenderCaptureReply);
154 return d->m_captureId;
155}
156
157/*!
158 * \property QRenderCaptureReply::complete
159 *
160 * Holds the complete state of the render capture.
161 */
162bool QRenderCaptureReply::isComplete() const
163{
164 Q_D(const QRenderCaptureReply);
165 return d->m_complete;
166}
167
168/*!
169 * Saves the render capture result as an image to \a fileName.
170 *
171 * Returns true if the image was successfully saved; otherwise returns false.
172 * \since 5.9
173 */
174bool QRenderCaptureReply::saveImage(const QString &fileName) const
175{
176 Q_D(const QRenderCaptureReply);
177 if (d->m_complete)
178 {
179 return d->m_image.save(fileName);
180 }
181 return false;
182}
183
184/*!
185 * \internal
186 */
187QRenderCapturePrivate::QRenderCapturePrivate()
188 : QFrameGraphNodePrivate()
189{
190}
191
192/*!
193 * \internal
194 */
195QRenderCapturePrivate::~QRenderCapturePrivate()
196{
197}
198
199/*!
200 * \internal
201 */
202QRenderCaptureReply *QRenderCapturePrivate::createReply(int captureId)
203{
204 QMutexLocker lock(&m_mutex);
205 QRenderCaptureReply *reply = new QRenderCaptureReply();
206 reply->d_func()->m_captureId = captureId;
207 m_waitingReplies.push_back(t: reply);
208 return reply;
209}
210
211/*!
212 * \internal
213 */
214QRenderCaptureReply *QRenderCapturePrivate::takeReply(int captureId)
215{
216 QRenderCaptureReply *reply = nullptr;
217 QMutexLocker lock(&m_mutex);
218 for (int i = 0; i < m_waitingReplies.size(); ++i) {
219 if (m_waitingReplies[i]->d_func()->m_captureId == captureId) {
220 reply = m_waitingReplies.takeAt(i);
221 break;
222 }
223 }
224 return reply;
225}
226
227/*!
228 * \internal
229 */
230void QRenderCapturePrivate::setImage(QRenderCaptureReply *reply, const QImage &image)
231{
232 reply->d_func()->m_complete = true;
233 reply->d_func()->m_image = image;
234}
235
236/*!
237 * \internal
238 */
239void QRenderCapturePrivate::replyDestroyed(QRenderCaptureReply *reply)
240{
241 QMutexLocker lock(&m_mutex);
242 m_waitingReplies.removeAll(t: reply);
243}
244
245/*!
246 * The constructor creates an instance with the specified \a parent.
247 */
248QRenderCapture::QRenderCapture(Qt3DCore::QNode *parent)
249 : QFrameGraphNode(*new QRenderCapturePrivate, parent)
250{
251}
252
253/*!
254 * \deprecated Used to request render capture. User can specify a \a captureId
255 * to identify the request. The requestId does not have to be unique. Only one
256 * render capture result is produced per requestCapture call even if the frame
257 * graph has multiple leaf nodes. The function returns a QRenderCaptureReply
258 * object, which receives the captured image when it is done. The user is
259 * responsible for deallocating the returned object by calling deleteLater().
260 */
261QRenderCaptureReply *QRenderCapture::requestCapture(int captureId)
262{
263 Q_D(QRenderCapture);
264 QRenderCaptureReply *reply = d->createReply(captureId);
265 reply->setParent(this);
266 QObject::connect(sender: reply, signal: &QObject::destroyed, context: this, slot: [&, reply, d] (QObject *) {
267 d->replyDestroyed(reply);
268 });
269
270 const QRenderCaptureRequest request = { .captureId: captureId, .rect: QRect() };
271 d->m_pendingRequests.push_back(t: request);
272 d->update();
273
274 return reply;
275}
276
277/*!
278 * Used to request render capture from a specified \a rect. Only one render
279 * capture result is produced per requestCapture call even if the frame graph
280 * has multiple leaf nodes. The function returns a QRenderCaptureReply object,
281 * which receives the captured image when it is done. The user is responsible
282 * for deallocating the returned object by calling deleteLater().
283 */
284QRenderCaptureReply *QRenderCapture::requestCapture(const QRect &rect)
285{
286 Q_D(QRenderCapture);
287 static int captureId = 1;
288 QRenderCaptureReply *reply = d->createReply(captureId);
289 reply->setParent(this);
290 QObject::connect(sender: reply, signal: &QObject::destroyed, context: this, slot: [&, reply, d] (QObject *) {
291 d->replyDestroyed(reply);
292 });
293
294 const QRenderCaptureRequest request = { .captureId: captureId, .rect: rect };
295 d->m_pendingRequests.push_back(t: request);
296 d->update();
297
298 captureId++;
299
300 return reply;
301}
302
303/*!
304 * Used to request render capture. Only one render capture result is produced
305 * per requestCapture call even if the frame graph has multiple leaf nodes. The
306 * function returns a QRenderCaptureReply object, which receives the captured
307 * image when it is done. The user is responsible for deallocating the returned
308 * object by calling deleterLater().
309 */
310Qt3DRender::QRenderCaptureReply *QRenderCapture::requestCapture()
311{
312 return requestCapture(rect: QRect());
313}
314
315} // Qt3DRender
316
317QT_END_NAMESPACE
318
319#include "moc_qrendercapture.cpp"
320

source code of qt3d/src/render/framegraph/qrendercapture.cpp