| 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 |  |