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 | * \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 | */ |
118 | QRenderCaptureReplyPrivate::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 | */ |
129 | QRenderCaptureReply::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 | */ |
140 | QImage 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 | */ |
151 | int 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 | */ |
162 | bool 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 | */ |
174 | bool 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 | */ |
187 | QRenderCapturePrivate::QRenderCapturePrivate() |
188 | : QFrameGraphNodePrivate() |
189 | { |
190 | } |
191 | |
192 | /*! |
193 | * \internal |
194 | */ |
195 | QRenderCapturePrivate::~QRenderCapturePrivate() |
196 | { |
197 | } |
198 | |
199 | /*! |
200 | * \internal |
201 | */ |
202 | QRenderCaptureReply *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 | */ |
214 | QRenderCaptureReply *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 | */ |
230 | void 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 | */ |
239 | void 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 | */ |
248 | QRenderCapture::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 | */ |
261 | QRenderCaptureReply *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 | */ |
284 | QRenderCaptureReply *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 | */ |
310 | Qt3DRender::QRenderCaptureReply *QRenderCapture::requestCapture() |
311 | { |
312 | return requestCapture(rect: QRect()); |
313 | } |
314 | |
315 | } // Qt3DRender |
316 | |
317 | QT_END_NAMESPACE |
318 | |
319 | #include "moc_qrendercapture.cpp" |
320 | |