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
46QT_BEGIN_NAMESPACE
47
48using namespace Qt3DCore;
49
50namespace Qt3DRender {
51
52const char *QBufferPrivate::UpdateDataPropertyName = "QT3D_updateData";
53
54QBufferPrivate::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
63void 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 */
290QBuffer::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 */
300QBuffer::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 */
310QBuffer::~QBuffer()
311{
312}
313
314/*!
315 * Sets \a bytes as data.
316 */
317void 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 */
329void 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 */
357QByteArray 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 */
368QBuffer::UsageType QBuffer::usage() const
369{
370 Q_D(const QBuffer);
371 return d->m_usage;
372}
373
374void 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 */
390QBuffer::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 */
399void 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 */
411QBufferDataGeneratorPtr 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 */
427void 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
436void 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 */
446void QBuffer::sceneChangeEvent(const QSceneChangePtr &change)
447{
448 // TODO Unused remove in Qt6
449 Q_UNUSED(change)
450}
451
452bool 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 */
465QBuffer::AccessType QBuffer::accessType() const
466{
467 Q_D(const QBuffer);
468 return d->m_access;
469}
470
471void 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
480Qt3DCore::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
495QT_END_NAMESPACE
496

source code of qt3d/src/render/geometry/qbuffer.cpp