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 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | namespace 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 | */ |
117 | QRenderCaptureReplyPrivate::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 | */ |
128 | QRenderCaptureReply::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 | */ |
139 | QImage 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 | */ |
150 | int 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 | */ |
161 | bool 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 | */ |
173 | bool 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 | */ |
186 | QRenderCapturePrivate::QRenderCapturePrivate() |
187 | : QFrameGraphNodePrivate() |
188 | { |
189 | } |
190 | |
191 | /*! |
192 | * \internal |
193 | */ |
194 | QRenderCapturePrivate::~QRenderCapturePrivate() |
195 | { |
196 | } |
197 | |
198 | /*! |
199 | * \internal |
200 | */ |
201 | QRenderCaptureReply *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 | */ |
213 | QRenderCaptureReply *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 | */ |
229 | void 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 | */ |
238 | void 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 | */ |
247 | QRenderCapture::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 | */ |
260 | QRenderCaptureReply *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 | */ |
283 | QRenderCaptureReply *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 | */ |
309 | Qt3DRender::QRenderCaptureReply *QRenderCapture::requestCapture() |
310 | { |
311 | return requestCapture(rect: QRect()); |
312 | } |
313 | |
314 | } // Qt3DRender |
315 | |
316 | QT_END_NAMESPACE |
317 | |
318 | #include "moc_qrendercapture.cpp" |
319 | |