1 | /**************************************************************************** |
2 | ** |
3 | ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
4 | ** Contact: https://www.qt.io/licensing/ |
5 | ** |
6 | ** This file is part of the Qt3D module of the Qt Toolkit. |
7 | ** |
8 | ** $QT_BEGIN_LICENSE:LGPL$ |
9 | ** Commercial License Usage |
10 | ** Licensees holding valid commercial Qt licenses may use this file in |
11 | ** accordance with the commercial license agreement provided with the |
12 | ** Software or, alternatively, in accordance with the terms contained in |
13 | ** a written agreement between you and The Qt Company. For licensing terms |
14 | ** and conditions see https://www.qt.io/terms-conditions. For further |
15 | ** information use the contact form at https://www.qt.io/contact-us. |
16 | ** |
17 | ** GNU Lesser General Public License Usage |
18 | ** Alternatively, this file may be used under the terms of the GNU Lesser |
19 | ** General Public License version 3 as published by the Free Software |
20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
21 | ** packaging of this file. Please review the following information to |
22 | ** ensure the GNU Lesser General Public License version 3 requirements |
23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
24 | ** |
25 | ** GNU General Public License Usage |
26 | ** Alternatively, this file may be used under the terms of the GNU |
27 | ** General Public License version 2.0 or (at your option) the GNU General |
28 | ** Public license version 3 or any later version approved by the KDE Free |
29 | ** Qt Foundation. The licenses are as published by the Free Software |
30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
31 | ** included in the packaging of this file. Please review the following |
32 | ** information to ensure the GNU General Public License requirements will |
33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
34 | ** https://www.gnu.org/licenses/gpl-3.0.html. |
35 | ** |
36 | ** $QT_END_LICENSE$ |
37 | ** |
38 | ****************************************************************************/ |
39 | |
40 | #include "qbuffer.h" |
41 | #include "qbuffer_p.h" |
42 | #include <Qt3DRender/private/renderlogging_p.h> |
43 | #include <Qt3DCore/qpropertyupdatedchange.h> |
44 | |
45 | |
46 | QT_BEGIN_NAMESPACE |
47 | |
48 | using namespace Qt3DCore; |
49 | |
50 | namespace Qt3DRender { |
51 | |
52 | const char *QBufferPrivate::UpdateDataPropertyName = "QT3D_updateData" ; |
53 | |
54 | QBufferPrivate::QBufferPrivate() |
55 | : QNodePrivate() |
56 | , m_type(QBuffer::VertexBuffer) |
57 | , m_usage(QBuffer::StaticDraw) |
58 | , m_syncData(false) |
59 | , m_access(QBuffer::Write) |
60 | { |
61 | } |
62 | |
63 | void QBufferPrivate::setData(const QByteArray &data) |
64 | { |
65 | Q_Q(QBuffer); |
66 | const bool blocked = q->blockNotifications(block: true); |
67 | m_data = data; |
68 | emit q->dataChanged(bytes: data); |
69 | q->blockNotifications(block: blocked); |
70 | } |
71 | |
72 | /*! |
73 | * \qmltype Buffer |
74 | * \instantiates Qt3DRender::QBuffer |
75 | * \inqmlmodule Qt3D.Render |
76 | * |
77 | * \brief Provides a data store for raw data to later be used as vertices or |
78 | * uniforms. |
79 | */ |
80 | |
81 | /*! |
82 | * \qmlproperty QBuffer::UsageType Buffer::usage |
83 | * |
84 | * Holds the buffer usage. |
85 | */ |
86 | |
87 | /*! |
88 | * \qmlproperty QBuffer::BufferType Buffer::type |
89 | * |
90 | * Holds the buffer type. |
91 | * |
92 | * \deprecated |
93 | */ |
94 | |
95 | /*! |
96 | * \qmlproperty bool Buffer::syncData |
97 | * |
98 | * Holds the syncData flag. When syncData is true, this will force data created |
99 | * by a Qt3DRender::QBufferDataGenerator to also be updated on the frontend |
100 | * Qt3DRender::QBuffer node. By default syncData is false. |
101 | * |
102 | * \note: This has no effect if the buffer's data was set directly using the data |
103 | * property. |
104 | */ |
105 | |
106 | /*! |
107 | * \class Qt3DRender::QBuffer |
108 | * \inheaderfile Qt3DRender/QBuffer |
109 | * \inmodule Qt3DRender |
110 | * |
111 | * \inherits Qt3DCore::QNode |
112 | * |
113 | * \brief Provides a data store for raw data to later be used as vertices or |
114 | * uniforms. |
115 | * |
116 | * Data can either be provided directly using QBuffer::setData() or by |
117 | * specifying a generator with QBuffer::setDataGenerator() and providing a |
118 | * Qt3DRender::QBufferDataGeneratorPtr. |
119 | * |
120 | * When using a generator the data will be loaded asynchronously in a job. The |
121 | * loaded data can be read back if the QBuffer::syncData flag is set to true. |
122 | */ |
123 | |
124 | /*! |
125 | * \fn void Qt3DRender::QBuffer::dataChanged(const QByteArray &bytes) |
126 | * |
127 | * This signal is emitted with \a bytes when data changes. |
128 | */ |
129 | |
130 | /*! |
131 | * \fn void Qt3DRender::QBuffer::dataAvailable() |
132 | * |
133 | * This signal is emitted when data becomes available. |
134 | */ |
135 | |
136 | /*! |
137 | \class Qt3DRender::QBufferDataGenerator |
138 | \inmodule Qt3DRender |
139 | |
140 | \inherits Qt3DRender::QAbstractFunctor |
141 | |
142 | \brief Provides a mechanism to generate buffer data from a job. |
143 | |
144 | The Qt3DRender::QBufferDataGenerator should be subclassed to provide a way |
145 | to fill the data of a Qt3DRender::QBuffer. Such functors are executed at |
146 | runtime in a Qt 3D job (likely in parallel with many other jobs). When |
147 | providing a functor you must implement the operator() which will be called |
148 | to generate the actual data. You must make sure that you have stored copies |
149 | of anything you might need for it to execute properly. You should also |
150 | implement the operator==. It will be used to compare with other functors |
151 | and based on that allow the renderer to decide if a new functor should be |
152 | executed or not. |
153 | |
154 | \note functors are useful when you can build data from a few set of |
155 | attributes (e.g: building a sphere from a radius property). If you already |
156 | have access to the buffer data, using Qt3DRender::QBuffer::setData() is |
157 | likely more efficient. |
158 | |
159 | \code |
160 | |
161 | QByteArray createSphereMeshVertexData(float radius, int rings, int slices) |
162 | { |
163 | ... |
164 | } |
165 | |
166 | class SphereVertexDataFunctor : public QBufferDataGenerator |
167 | { |
168 | public: |
169 | SphereVertexDataFunctor(int rings, int slices, float radius) |
170 | : m_rings(rings) |
171 | , m_slices(slices) |
172 | , m_radius(radius) |
173 | {} |
174 | |
175 | QByteArray operator ()() override |
176 | { |
177 | return createSphereMeshVertexData(m_radius, m_rings, m_slices); |
178 | } |
179 | |
180 | bool operator ==(const QBufferDataGenerator &other) const override |
181 | { |
182 | const SphereVertexDataFunctor *otherFunctor = functor_cast<SphereVertexDataFunctor>(&other); |
183 | if (otherFunctor != nullptr) |
184 | return (otherFunctor->m_rings == m_rings && |
185 | otherFunctor->m_slices == m_slices && |
186 | otherFunctor->m_radius == m_radius); |
187 | return false; |
188 | } |
189 | |
190 | QT3D_FUNCTOR(SphereVertexDataFunctor) |
191 | |
192 | private: |
193 | int m_rings; |
194 | int m_slices; |
195 | float m_radius; |
196 | }; |
197 | |
198 | \endcode |
199 | |
200 | The QT3D_FUNCTOR macro should be added when subclassing. This allows you to |
201 | use functor_cast in your comparison operator to make sure that the other |
202 | functor is of the same type as the one your are trying to compare against. |
203 | */ |
204 | |
205 | /*! |
206 | \fn Qt3DRender::QBufferDataGenerator::operator()() |
207 | |
208 | Should be implemented to return the buffer data as a QByteArray when called. |
209 | */ |
210 | |
211 | /*! |
212 | \fn Qt3DRender::QBufferDataGenerator::operator ==(const QBufferDataGenerator &other) const |
213 | |
214 | Should be reimplemented to return true when two generators (the one you are |
215 | comparing against and the \a other generator) are identical, |
216 | false otherwise. |
217 | |
218 | \note The renderer uses this comparison to decide whether data for a buffer |
219 | needs to be reuploaded or not when the functor on a Qt3DRender::QBuffer |
220 | changes. |
221 | */ |
222 | |
223 | /*! |
224 | * \enum QBuffer::BufferType |
225 | * |
226 | * The type of the buffer. |
227 | * |
228 | * \value VertexBuffer |
229 | * GL_ARRAY_BUFFER |
230 | * \value IndexBuffer |
231 | * GL_ELEMENT_ARRAY_BUFFER |
232 | * \value PixelPackBuffer |
233 | * GL_PIXEL_PACK_BUFFER |
234 | * \value PixelUnpackBuffer |
235 | * GL_PIXEL_UNPACK_BUFFER |
236 | * \value UniformBuffer |
237 | * GL_UNIFORM_BUFFER |
238 | * \value ShaderStorageBuffer |
239 | * GL_SHADER_STORAGE_BUFFER |
240 | * \value DrawIndirectBuffer |
241 | * GL_DRAW_INDIRECT_BUFFER |
242 | * |
243 | * \deprecated |
244 | */ |
245 | |
246 | /*! |
247 | * \enum QBuffer::UsageType |
248 | * |
249 | * The type of the usage. |
250 | * |
251 | * \value StreamDraw |
252 | * GL_STREAM_DRAW |
253 | * \value StreamRead |
254 | * GL_STREAM_READ |
255 | * \value StreamCopy |
256 | * GL_STREAM_COPY |
257 | * \value StaticDraw |
258 | * GL_STATIC_DRAW |
259 | * \value StaticRead |
260 | * GL_STATIC_READ |
261 | * \value StaticCopy |
262 | * GL_STATIC_COPY |
263 | * \value DynamicDraw |
264 | * GL_DYNAMIC_DRAW |
265 | * \value DynamicRead |
266 | * GL_DYNAMIC_READ |
267 | * \value DynamicCopy |
268 | * GL_DYNAMIC_COPY |
269 | */ |
270 | |
271 | /*! |
272 | * \enum QBuffer::AccessType |
273 | * |
274 | * \value Write |
275 | * Write access |
276 | * \value Read |
277 | * Read access |
278 | * \value ReadWrite |
279 | * Write|Read |
280 | */ |
281 | |
282 | /*! |
283 | * \typedef Qt3DRender::QBufferDataGeneratorPtr |
284 | * \relates Qt3DRender::QBuffer |
285 | */ |
286 | |
287 | /*! |
288 | * Constructs a new QBuffer with \a parent. |
289 | */ |
290 | QBuffer::QBuffer(QNode *parent) |
291 | : QNode(*new QBufferPrivate(), parent) |
292 | { |
293 | } |
294 | |
295 | /*! |
296 | * Constructs a new QBuffer of buffer type \a ty with \a parent. |
297 | * |
298 | * \deprecated |
299 | */ |
300 | QBuffer::QBuffer(QBuffer::BufferType ty, QNode *parent) |
301 | : QNode(*new QBufferPrivate(), parent) |
302 | { |
303 | Q_D(QBuffer); |
304 | d->m_type = ty; |
305 | } |
306 | |
307 | /*! |
308 | * \internal |
309 | */ |
310 | QBuffer::~QBuffer() |
311 | { |
312 | } |
313 | |
314 | /*! |
315 | * Sets \a bytes as data. |
316 | */ |
317 | void QBuffer::setData(const QByteArray &bytes) |
318 | { |
319 | Q_D(QBuffer); |
320 | if (bytes != d->m_data) { |
321 | d->setData(bytes); |
322 | d->update(); |
323 | } |
324 | } |
325 | |
326 | /*! |
327 | * Updates the data by replacing it with \a bytes at \a offset. |
328 | */ |
329 | void QBuffer::updateData(int offset, const QByteArray &bytes) |
330 | { |
331 | Q_D(QBuffer); |
332 | Q_ASSERT(offset >= 0 && (offset + bytes.size()) <= d->m_data.size()); |
333 | |
334 | // Update data |
335 | d->m_data.replace(index: offset, len: bytes.size(), s: bytes); |
336 | const bool blocked = blockNotifications(block: true); |
337 | emit dataChanged(bytes: d->m_data); |
338 | blockNotifications(block: blocked); |
339 | |
340 | QBufferUpdate updateData; |
341 | updateData.offset = offset; |
342 | updateData.data = bytes; |
343 | |
344 | QVariantList updateDataList; |
345 | const QVariant propertyData = property(name: QBufferPrivate::UpdateDataPropertyName); |
346 | if (propertyData.isValid()) |
347 | updateDataList = propertyData.toList(); |
348 | updateDataList.push_back(t: QVariant::fromValue(value: updateData)); |
349 | |
350 | setProperty(name: QBufferPrivate::UpdateDataPropertyName, value: updateDataList); |
351 | d->update(); |
352 | } |
353 | |
354 | /*! |
355 | * \return the data. |
356 | */ |
357 | QByteArray QBuffer::data() const |
358 | { |
359 | Q_D(const QBuffer); |
360 | return d->m_data; |
361 | } |
362 | |
363 | /*! |
364 | * \property QBuffer::usage |
365 | * |
366 | * Holds the buffer usage. |
367 | */ |
368 | QBuffer::UsageType QBuffer::usage() const |
369 | { |
370 | Q_D(const QBuffer); |
371 | return d->m_usage; |
372 | } |
373 | |
374 | void QBuffer::setUsage(QBuffer::UsageType usage) |
375 | { |
376 | Q_D(QBuffer); |
377 | if (usage != d->m_usage) { |
378 | d->m_usage = usage; |
379 | emit usageChanged(usage); |
380 | } |
381 | } |
382 | |
383 | /*! |
384 | * \property QBuffer::type |
385 | * |
386 | * Holds the buffer type. |
387 | * |
388 | * \deprecated |
389 | */ |
390 | QBuffer::BufferType QBuffer::type() const |
391 | { |
392 | Q_D(const QBuffer); |
393 | return d->m_type; |
394 | } |
395 | |
396 | /*! |
397 | * Sets the buffer \a functor. |
398 | */ |
399 | void QBuffer::setDataGenerator(const QBufferDataGeneratorPtr &functor) |
400 | { |
401 | Q_D(QBuffer); |
402 | if (functor && d->m_functor && *functor == *d->m_functor) |
403 | return; |
404 | d->m_functor = functor; |
405 | d->update(); |
406 | } |
407 | |
408 | /*! |
409 | * \return the buffer functor. |
410 | */ |
411 | QBufferDataGeneratorPtr QBuffer::dataGenerator() const |
412 | { |
413 | Q_D(const QBuffer); |
414 | return d->m_functor; |
415 | } |
416 | |
417 | /*! |
418 | * \property QBuffer::syncData |
419 | * |
420 | * Holds the syncData flag. When syncData is true, this will force data created |
421 | * by a Qt3DRender::QBufferDataGenerator to also be updated on the frontend |
422 | * Qt3DRender::QBuffer node. By default syncData is false. |
423 | * |
424 | * \note: This has no effect if the buffer's data was set directly using the data |
425 | * property. |
426 | */ |
427 | void QBuffer::setSyncData(bool syncData) |
428 | { |
429 | Q_D(QBuffer); |
430 | if (d->m_syncData != syncData) { |
431 | d->m_syncData = syncData; |
432 | emit syncDataChanged(syncData); |
433 | } |
434 | } |
435 | |
436 | void QBuffer::setAccessType(QBuffer::AccessType access) |
437 | { |
438 | Q_D(QBuffer); |
439 | if (d->m_access != access) { |
440 | d->m_access = access; |
441 | Q_EMIT accessTypeChanged(access); |
442 | } |
443 | } |
444 | |
445 | /*! \internal */ |
446 | void QBuffer::sceneChangeEvent(const QSceneChangePtr &change) |
447 | { |
448 | // TODO Unused remove in Qt6 |
449 | Q_UNUSED(change) |
450 | } |
451 | |
452 | bool QBuffer::isSyncData() const |
453 | { |
454 | Q_D(const QBuffer); |
455 | return d->m_syncData; |
456 | } |
457 | |
458 | /*! |
459 | * \property Qt3DRender::QBuffer::accessType |
460 | * |
461 | * Returns the \l {QBuffer::}{AccessType} of the buffer. |
462 | * |
463 | * \sa QBuffer::AccessType |
464 | */ |
465 | QBuffer::AccessType QBuffer::accessType() const |
466 | { |
467 | Q_D(const QBuffer); |
468 | return d->m_access; |
469 | } |
470 | |
471 | void QBuffer::setType(QBuffer::BufferType type) |
472 | { |
473 | Q_D(QBuffer); |
474 | if (type != d->m_type) { |
475 | d->m_type = type; |
476 | emit typeChanged(type); |
477 | } |
478 | } |
479 | |
480 | Qt3DCore::QNodeCreatedChangeBasePtr QBuffer::createNodeCreationChange() const |
481 | { |
482 | auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QBufferData>::create(arguments: this); |
483 | auto &data = creationChange->data; |
484 | Q_D(const QBuffer); |
485 | data.data = d->m_data; |
486 | data.usage = d->m_usage; |
487 | data.functor = d->m_functor; |
488 | data.syncData = d->m_syncData; |
489 | data.access = d->m_access; |
490 | return creationChange; |
491 | } |
492 | |
493 | } // namespace Qt3DRender |
494 | |
495 | QT_END_NAMESPACE |
496 | |