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

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