| /**************************************************************************** |
| ** |
| ** Copyright (C) 2014 Klaralvdalens Datakonsult AB (KDAB). |
| ** Contact: https://www.qt.io/licensing/ |
| ** |
| ** This file is part of the Qt3D module of the Qt Toolkit. |
| ** |
| ** $QT_BEGIN_LICENSE:LGPL$ |
| ** Commercial License Usage |
| ** Licensees holding valid commercial Qt licenses may use this file in |
| ** accordance with the commercial license agreement provided with the |
| ** Software or, alternatively, in accordance with the terms contained in |
| ** a written agreement between you and The Qt Company. For licensing terms |
| ** and conditions see https://www.qt.io/terms-conditions. For further |
| ** information use the contact form at https://www.qt.io/contact-us. |
| ** |
| ** GNU Lesser General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU Lesser |
| ** General Public License version 3 as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.LGPL3 included in the |
| ** packaging of this file. Please review the following information to |
| ** ensure the GNU Lesser General Public License version 3 requirements |
| ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. |
| ** |
| ** GNU General Public License Usage |
| ** Alternatively, this file may be used under the terms of the GNU |
| ** General Public License version 2.0 or (at your option) the GNU General |
| ** Public license version 3 or any later version approved by the KDE Free |
| ** Qt Foundation. The licenses are as published by the Free Software |
| ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 |
| ** included in the packaging of this file. Please review the following |
| ** information to ensure the GNU General Public License requirements will |
| ** be met: https://www.gnu.org/licenses/gpl-2.0.html and |
| ** https://www.gnu.org/licenses/gpl-3.0.html. |
| ** |
| ** $QT_END_LICENSE$ |
| ** |
| ****************************************************************************/ |
| |
| #include "qbuffer.h" |
| #include "qbuffer_p.h" |
| #include <Qt3DRender/private/renderlogging_p.h> |
| #include <Qt3DCore/qpropertyupdatedchange.h> |
| |
| |
| QT_BEGIN_NAMESPACE |
| |
| using namespace Qt3DCore; |
| |
| namespace Qt3DRender { |
| |
| const char *QBufferPrivate::UpdateDataPropertyName = "QT3D_updateData"; |
| |
| QBufferPrivate::QBufferPrivate() |
| : QNodePrivate() |
| , m_type(QBuffer::VertexBuffer) |
| , m_usage(QBuffer::StaticDraw) |
| , m_syncData(false) |
| , m_access(QBuffer::Write) |
| { |
| } |
| |
| void QBufferPrivate::setData(const QByteArray &data) |
| { |
| Q_Q(QBuffer); |
| const bool blocked = q->blockNotifications(true); |
| m_data = data; |
| emit q->dataChanged(data); |
| q->blockNotifications(blocked); |
| } |
| |
| /*! |
| * \qmltype Buffer |
| * \instantiates Qt3DRender::QBuffer |
| * \inqmlmodule Qt3D.Render |
| * |
| * \brief Provides a data store for raw data to later be used as vertices or |
| * uniforms. |
| */ |
| |
| /*! |
| * \qmlproperty QBuffer::UsageType Buffer::usage |
| * |
| * Holds the buffer usage. |
| */ |
| |
| /*! |
| * \qmlproperty QBuffer::BufferType Buffer::type |
| * |
| * Holds the buffer type. |
| * |
| * \deprecated |
| */ |
| |
| /*! |
| * \qmlproperty bool Buffer::syncData |
| * |
| * Holds the syncData flag. When syncData is true, this will force data created |
| * by a Qt3DRender::QBufferDataGenerator to also be updated on the frontend |
| * Qt3DRender::QBuffer node. By default syncData is false. |
| * |
| * \note: This has no effect if the buffer's data was set directly using the data |
| * property. |
| */ |
| |
| /*! |
| * \class Qt3DRender::QBuffer |
| * \inheaderfile Qt3DRender/QBuffer |
| * \inmodule Qt3DRender |
| * |
| * \inherits Qt3DCore::QNode |
| * |
| * \brief Provides a data store for raw data to later be used as vertices or |
| * uniforms. |
| * |
| * Data can either be provided directly using QBuffer::setData() or by |
| * specifying a generator with QBuffer::setDataGenerator() and providing a |
| * Qt3DRender::QBufferDataGeneratorPtr. |
| * |
| * When using a generator the data will be loaded asynchronously in a job. The |
| * loaded data can be read back if the QBuffer::syncData flag is set to true. |
| */ |
| |
| /*! |
| * \fn void Qt3DRender::QBuffer::dataChanged(const QByteArray &bytes) |
| * |
| * This signal is emitted with \a bytes when data changes. |
| */ |
| |
| /*! |
| * \fn void Qt3DRender::QBuffer::dataAvailable() |
| * |
| * This signal is emitted when data becomes available. |
| */ |
| |
| /*! |
| \class Qt3DRender::QBufferDataGenerator |
| \inmodule Qt3DRender |
| |
| \inherits Qt3DRender::QAbstractFunctor |
| |
| \brief Provides a mechanism to generate buffer data from a job. |
| |
| The Qt3DRender::QBufferDataGenerator should be subclassed to provide a way |
| to fill the data of a Qt3DRender::QBuffer. Such functors are executed at |
| runtime in a Qt 3D job (likely in parallel with many other jobs). When |
| providing a functor you must implement the operator() which will be called |
| to generate the actual data. You must make sure that you have stored copies |
| of anything you might need for it to execute properly. You should also |
| implement the operator==. It will be used to compare with other functors |
| and based on that allow the renderer to decide if a new functor should be |
| executed or not. |
| |
| \note functors are useful when you can build data from a few set of |
| attributes (e.g: building a sphere from a radius property). If you already |
| have access to the buffer data, using Qt3DRender::QBuffer::setData() is |
| likely more efficient. |
| |
| \code |
| |
| QByteArray createSphereMeshVertexData(float radius, int rings, int slices) |
| { |
| ... |
| } |
| |
| class SphereVertexDataFunctor : public QBufferDataGenerator |
| { |
| public: |
| SphereVertexDataFunctor(int rings, int slices, float radius) |
| : m_rings(rings) |
| , m_slices(slices) |
| , m_radius(radius) |
| {} |
| |
| QByteArray operator ()() override |
| { |
| return createSphereMeshVertexData(m_radius, m_rings, m_slices); |
| } |
| |
| bool operator ==(const QBufferDataGenerator &other) const override |
| { |
| const SphereVertexDataFunctor *otherFunctor = functor_cast<SphereVertexDataFunctor>(&other); |
| if (otherFunctor != nullptr) |
| return (otherFunctor->m_rings == m_rings && |
| otherFunctor->m_slices == m_slices && |
| otherFunctor->m_radius == m_radius); |
| return false; |
| } |
| |
| QT3D_FUNCTOR(SphereVertexDataFunctor) |
| |
| private: |
| int m_rings; |
| int m_slices; |
| float m_radius; |
| }; |
| |
| \endcode |
| |
| The QT3D_FUNCTOR macro should be added when subclassing. This allows you to |
| use functor_cast in your comparison operator to make sure that the other |
| functor is of the same type as the one your are trying to compare against. |
| */ |
| |
| /*! |
| \fn Qt3DRender::QBufferDataGenerator::operator()() |
| |
| Should be implemented to return the buffer data as a QByteArray when called. |
| */ |
| |
| /*! |
| \fn Qt3DRender::QBufferDataGenerator::operator ==(const QBufferDataGenerator &other) const |
| |
| Should be reimplemented to return true when two generators (the one you are |
| comparing against and the \a other generator) are identical, |
| false otherwise. |
| |
| \note The renderer uses this comparison to decide whether data for a buffer |
| needs to be reuploaded or not when the functor on a Qt3DRender::QBuffer |
| changes. |
| */ |
| |
| /*! |
| * \enum QBuffer::BufferType |
| * |
| * The type of the buffer. |
| * |
| * \value VertexBuffer |
| * GL_ARRAY_BUFFER |
| * \value IndexBuffer |
| * GL_ELEMENT_ARRAY_BUFFER |
| * \value PixelPackBuffer |
| * GL_PIXEL_PACK_BUFFER |
| * \value PixelUnpackBuffer |
| * GL_PIXEL_UNPACK_BUFFER |
| * \value UniformBuffer |
| * GL_UNIFORM_BUFFER |
| * \value ShaderStorageBuffer |
| * GL_SHADER_STORAGE_BUFFER |
| * \value DrawIndirectBuffer |
| * GL_DRAW_INDIRECT_BUFFER |
| * |
| * \deprecated |
| */ |
| |
| /*! |
| * \enum QBuffer::UsageType |
| * |
| * The type of the usage. |
| * |
| * \value StreamDraw |
| * GL_STREAM_DRAW |
| * \value StreamRead |
| * GL_STREAM_READ |
| * \value StreamCopy |
| * GL_STREAM_COPY |
| * \value StaticDraw |
| * GL_STATIC_DRAW |
| * \value StaticRead |
| * GL_STATIC_READ |
| * \value StaticCopy |
| * GL_STATIC_COPY |
| * \value DynamicDraw |
| * GL_DYNAMIC_DRAW |
| * \value DynamicRead |
| * GL_DYNAMIC_READ |
| * \value DynamicCopy |
| * GL_DYNAMIC_COPY |
| */ |
| |
| /*! |
| * \enum QBuffer::AccessType |
| * |
| * \value Write |
| * Write access |
| * \value Read |
| * Read access |
| * \value ReadWrite |
| * Write|Read |
| */ |
| |
| /*! |
| * \typedef Qt3DRender::QBufferDataGeneratorPtr |
| * \relates Qt3DRender::QBuffer |
| */ |
| |
| /*! |
| * Constructs a new QBuffer with \a parent. |
| */ |
| QBuffer::QBuffer(QNode *parent) |
| : QNode(*new QBufferPrivate(), parent) |
| { |
| } |
| |
| /*! |
| * Constructs a new QBuffer of buffer type \a ty with \a parent. |
| * |
| * \deprecated |
| */ |
| QBuffer::QBuffer(QBuffer::BufferType ty, QNode *parent) |
| : QNode(*new QBufferPrivate(), parent) |
| { |
| Q_D(QBuffer); |
| d->m_type = ty; |
| } |
| |
| /*! |
| * \internal |
| */ |
| QBuffer::~QBuffer() |
| { |
| } |
| |
| /*! |
| * Sets \a bytes as data. |
| */ |
| void QBuffer::setData(const QByteArray &bytes) |
| { |
| Q_D(QBuffer); |
| if (bytes != d->m_data) { |
| d->setData(bytes); |
| d->update(); |
| } |
| } |
| |
| /*! |
| * Updates the data by replacing it with \a bytes at \a offset. |
| */ |
| void QBuffer::updateData(int offset, const QByteArray &bytes) |
| { |
| Q_D(QBuffer); |
| Q_ASSERT(offset >= 0 && (offset + bytes.size()) <= d->m_data.size()); |
| |
| // Update data |
| d->m_data.replace(offset, bytes.size(), bytes); |
| const bool blocked = blockNotifications(true); |
| emit dataChanged(d->m_data); |
| blockNotifications(blocked); |
| |
| QBufferUpdate updateData; |
| updateData.offset = offset; |
| updateData.data = bytes; |
| |
| QVariantList updateDataList; |
| const QVariant propertyData = property(QBufferPrivate::UpdateDataPropertyName); |
| if (propertyData.isValid()) |
| updateDataList = propertyData.toList(); |
| updateDataList.push_back(QVariant::fromValue(updateData)); |
| |
| setProperty(QBufferPrivate::UpdateDataPropertyName, updateDataList); |
| d->update(); |
| } |
| |
| /*! |
| * \return the data. |
| */ |
| QByteArray QBuffer::data() const |
| { |
| Q_D(const QBuffer); |
| return d->m_data; |
| } |
| |
| /*! |
| * \property QBuffer::usage |
| * |
| * Holds the buffer usage. |
| */ |
| QBuffer::UsageType QBuffer::usage() const |
| { |
| Q_D(const QBuffer); |
| return d->m_usage; |
| } |
| |
| void QBuffer::setUsage(QBuffer::UsageType usage) |
| { |
| Q_D(QBuffer); |
| if (usage != d->m_usage) { |
| d->m_usage = usage; |
| emit usageChanged(usage); |
| } |
| } |
| |
| /*! |
| * \property QBuffer::type |
| * |
| * Holds the buffer type. |
| * |
| * \deprecated |
| */ |
| QBuffer::BufferType QBuffer::type() const |
| { |
| Q_D(const QBuffer); |
| return d->m_type; |
| } |
| |
| /*! |
| * Sets the buffer \a functor. |
| */ |
| void QBuffer::setDataGenerator(const QBufferDataGeneratorPtr &functor) |
| { |
| Q_D(QBuffer); |
| if (functor && d->m_functor && *functor == *d->m_functor) |
| return; |
| d->m_functor = functor; |
| d->update(); |
| } |
| |
| /*! |
| * \return the buffer functor. |
| */ |
| QBufferDataGeneratorPtr QBuffer::dataGenerator() const |
| { |
| Q_D(const QBuffer); |
| return d->m_functor; |
| } |
| |
| /*! |
| * \property QBuffer::syncData |
| * |
| * Holds the syncData flag. When syncData is true, this will force data created |
| * by a Qt3DRender::QBufferDataGenerator to also be updated on the frontend |
| * Qt3DRender::QBuffer node. By default syncData is false. |
| * |
| * \note: This has no effect if the buffer's data was set directly using the data |
| * property. |
| */ |
| void QBuffer::setSyncData(bool syncData) |
| { |
| Q_D(QBuffer); |
| if (d->m_syncData != syncData) { |
| d->m_syncData = syncData; |
| emit syncDataChanged(syncData); |
| } |
| } |
| |
| void QBuffer::setAccessType(QBuffer::AccessType access) |
| { |
| Q_D(QBuffer); |
| if (d->m_access != access) { |
| d->m_access = access; |
| Q_EMIT accessTypeChanged(access); |
| } |
| } |
| |
| /*! \internal */ |
| void QBuffer::sceneChangeEvent(const QSceneChangePtr &change) |
| { |
| // TODO Unused remove in Qt6 |
| Q_UNUSED(change) |
| } |
| |
| bool QBuffer::isSyncData() const |
| { |
| Q_D(const QBuffer); |
| return d->m_syncData; |
| } |
| |
| /*! |
| * \property Qt3DRender::QBuffer::accessType |
| * |
| * Returns the \l {QBuffer::}{AccessType} of the buffer. |
| * |
| * \sa QBuffer::AccessType |
| */ |
| QBuffer::AccessType QBuffer::accessType() const |
| { |
| Q_D(const QBuffer); |
| return d->m_access; |
| } |
| |
| void QBuffer::setType(QBuffer::BufferType type) |
| { |
| Q_D(QBuffer); |
| if (type != d->m_type) { |
| d->m_type = type; |
| emit typeChanged(type); |
| } |
| } |
| |
| Qt3DCore::QNodeCreatedChangeBasePtr QBuffer::createNodeCreationChange() const |
| { |
| auto creationChange = Qt3DCore::QNodeCreatedChangePtr<QBufferData>::create(this); |
| auto &data = creationChange->data; |
| Q_D(const QBuffer); |
| data.data = d->m_data; |
| data.usage = d->m_usage; |
| data.functor = d->m_functor; |
| data.syncData = d->m_syncData; |
| data.access = d->m_access; |
| return creationChange; |
| } |
| |
| } // namespace Qt3DRender |
| |
| QT_END_NAMESPACE |