diff options
Diffstat (limited to 'src/particles/qquickimageparticle.cpp')
-rw-r--r-- | src/particles/qquickimageparticle.cpp | 1211 |
1 files changed, 656 insertions, 555 deletions
diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index 0b1de08ea3..855726c20a 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1,47 +1,12 @@ -/**************************************************************************** -** -** Copyright (C) 2016 The Qt Company Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the QtQuick 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$ -** -****************************************************************************/ +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#undef QT_NO_FOREACH // this file contains unported legacy Q_FOREACH uses #include <QtQuick/private/qsgcontext_p.h> #include <private/qsgadaptationlayer_p.h> #include <private/qquickitem_p.h> #include <QtQuick/qsgnode.h> -#include <QtQuick/qsgtexturematerial.h> #include <QtQuick/qsgtexture.h> #include <QFile> #include <QRandomGenerator> @@ -49,20 +14,20 @@ #include "qquickparticleemitter_p.h" #include <private/qquicksprite_p.h> #include <private/qquickspriteengine_p.h> -#include <QOpenGLFunctions> #include <QSGRendererInterface> -#include <QtQuick/private/qsgshadersourcebuilder_p.h> -#include <QtQuick/private/qsgtexture_p.h> +#include <QtQuick/private/qsgplaintexture_p.h> #include <private/qqmlglobal_p.h> #include <QtQml/qqmlinfo.h> +#include <QtCore/QtMath> +#include <rhi/qrhi.h> + #include <cmath> QT_BEGIN_NAMESPACE -//TODO: Make it larger on desktop? Requires fixing up shader code with the same define +// Must match the shader code #define UNIFORM_ARRAY_SIZE 64 -const qreal CONV = 0.017453292519943295; class ImageMaterialData { public: @@ -80,380 +45,415 @@ class ImageMaterialData float sizeTable[UNIFORM_ARRAY_SIZE]; float opacityTable[UNIFORM_ARRAY_SIZE]; + qreal dpr; qreal timestamp; qreal entry; QSizeF animSheetSize; }; -class TabledMaterialData : public ImageMaterialData {}; -class TabledMaterial : public QSGSimpleMaterialShader<TabledMaterialData> +class TabledMaterialRhiShader : public QSGMaterialShader { - QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData) - public: - TabledMaterial() + TabledMaterialRhiShader(int viewCount) { - QSGShaderSourceBuilder builder; - const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.vert.qsb"), viewCount); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.frag.qsb"), viewCount); + } - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert")); - builder.addDefinition(QByteArrayLiteral("TABLE")); - builder.addDefinition(QByteArrayLiteral("DEFORM")); - builder.addDefinition(QByteArrayLiteral("COLOR")); - if (isES) - builder.removeVersion(); + bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + const int shaderMatrixCount = newMaterial->viewCount(); + const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount); + + for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) { + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(viewIndex); + memcpy(buf->data() + 64 * viewIndex, m.constData(), 64); + } + } - m_vertex_code = builder.source(); - builder.clear(); + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4); + } - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag")); - builder.addDefinition(QByteArrayLiteral("TABLE")); - builder.addDefinition(QByteArrayLiteral("DEFORM")); - builder.addDefinition(QByteArrayLiteral("COLOR")); - if (isES) - builder.removeVersion(); + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); - m_fragment_code = builder.source(); + float entry = float(state->entry); + memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4); - Q_ASSERT(!m_vertex_code.isNull()); - Q_ASSERT(!m_fragment_code.isNull()); - } + float timestamp = float(state->timestamp); + memcpy(buf->data() + 64 * shaderMatrixCount + 8, ×tamp, 4); - const char *vertexShader() const override { return m_vertex_code.constData(); } - const char *fragmentShader() const override { return m_fragment_code.constData(); } + float *p = reinterpret_cast<float *>(buf->data() + 64 * shaderMatrixCount + 16); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->sizeTable[i]; + p += 4; + } + p = reinterpret_cast<float *>(buf->data() + 64 * shaderMatrixCount + 16 + (UNIFORM_ARRAY_SIZE * 4 * 4)); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->opacityTable[i]; + p += 4; + } - QList<QByteArray> attributes() const override { - return QList<QByteArray>() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation"; - }; + return true; + } - void initialize() override { - QSGSimpleMaterialShader<TabledMaterialData>::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - program()->setUniformValue("colortable", 1); - glFuncs = QOpenGLContext::currentContext()->functions(); - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); - m_sizetable_id = program()->uniformLocation("sizetable"); - m_opacitytable_id = program()->uniformLocation("opacitytable"); - } - - void updateState(const TabledMaterialData* d, const TabledMaterialData*) override { - glFuncs->glActiveTexture(GL_TEXTURE1); - d->colorTable->bind(); - - glFuncs->glActiveTexture(GL_TEXTURE0); - d->texture->bind(); - - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); - program()->setUniformValueArray(m_sizetable_id, (const float*) d->sizeTable, UNIFORM_ARRAY_SIZE, 1); - program()->setUniformValueArray(m_opacitytable_id, (const float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1); - } - - int m_entry_id; - int m_timestamp_id; - int m_sizetable_id; - int m_opacitytable_id; - QByteArray m_vertex_code; - QByteArray m_fragment_code; - QOpenGLFunctions* glFuncs; + void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); + if (binding == 2) { + state->colorTable->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->colorTable; + } else if (binding == 1) { + state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } }; -class DeformableMaterialData : public ImageMaterialData {}; -class DeformableMaterial : public QSGSimpleMaterialShader<DeformableMaterialData> +class TabledMaterial : public ImageMaterial { - QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData) - public: - DeformableMaterial() - { - QSGShaderSourceBuilder builder; - const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); - - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert")); - builder.addDefinition(QByteArrayLiteral("DEFORM")); - builder.addDefinition(QByteArrayLiteral("COLOR")); - if (isES) - builder.removeVersion(); + QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override { + Q_UNUSED(renderMode); + return new TabledMaterialRhiShader(viewCount()); + } + QSGMaterialType *type() const override { return &m_type; } - m_vertex_code = builder.source(); - builder.clear(); + ImageMaterialData *state() override { return &m_state; } - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag")); - builder.addDefinition(QByteArrayLiteral("DEFORM")); - builder.addDefinition(QByteArrayLiteral("COLOR")); - if (isES) - builder.removeVersion(); +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; - m_fragment_code = builder.source(); +QSGMaterialType TabledMaterial::m_type; - Q_ASSERT(!m_vertex_code.isNull()); - Q_ASSERT(!m_fragment_code.isNull()); +class DeformableMaterialRhiShader : public QSGMaterialShader +{ +public: + DeformableMaterialRhiShader(int viewCount) + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.vert.qsb"), viewCount); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.frag.qsb"), viewCount); } - const char *vertexShader() const override { return m_vertex_code.constData(); } - const char *fragmentShader() const override { return m_fragment_code.constData(); } + bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + const int shaderMatrixCount = newMaterial->viewCount(); + const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount); + + for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) { + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(viewIndex); + memcpy(buf->data() + 64 * viewIndex, m.constData(), 64); + } + } - QList<QByteArray> attributes() const override { - return QList<QByteArray>() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation"; - }; + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4); + } - void initialize() override { - QSGSimpleMaterialShader<DeformableMaterialData>::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - glFuncs = QOpenGLContext::currentContext()->functions(); - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); - } + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4); - void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) override { - d->texture->bind(); + float timestamp = float(state->timestamp); + memcpy(buf->data() + 64 * shaderMatrixCount + 8, ×tamp, 4); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); + return true; } - int m_entry_id; - int m_timestamp_id; - QByteArray m_vertex_code; - QByteArray m_fragment_code; - QOpenGLFunctions* glFuncs; + void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); + if (binding == 1) { + state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } }; -class SpriteMaterialData : public ImageMaterialData {}; -class SpriteMaterial : public QSGSimpleMaterialShader<SpriteMaterialData> +class DeformableMaterial : public ImageMaterial { - QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData) - public: - SpriteMaterial() - { - QSGShaderSourceBuilder builder; - const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); - - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert")); - builder.addDefinition(QByteArrayLiteral("SPRITE")); - builder.addDefinition(QByteArrayLiteral("TABLE")); - builder.addDefinition(QByteArrayLiteral("DEFORM")); - builder.addDefinition(QByteArrayLiteral("COLOR")); - if (isES) - builder.removeVersion(); - - m_vertex_code = builder.source(); - builder.clear(); - - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag")); - builder.addDefinition(QByteArrayLiteral("SPRITE")); - builder.addDefinition(QByteArrayLiteral("TABLE")); - builder.addDefinition(QByteArrayLiteral("DEFORM")); - builder.addDefinition(QByteArrayLiteral("COLOR")); - if (isES) - builder.removeVersion(); - - m_fragment_code = builder.source(); - - Q_ASSERT(!m_vertex_code.isNull()); - Q_ASSERT(!m_fragment_code.isNull()); - } - - const char *vertexShader() const override { return m_vertex_code.constData(); } - const char *fragmentShader() const override { return m_fragment_code.constData(); } - - QList<QByteArray> attributes() const override { - return QList<QByteArray>() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos"; - } - - void initialize() override { - QSGSimpleMaterialShader<SpriteMaterialData>::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - program()->setUniformValue("colortable", 1); - glFuncs = QOpenGLContext::currentContext()->functions(); - //Don't actually expose the animSheetSize in the shader, it's currently only used for CPU calculations. - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); - m_sizetable_id = program()->uniformLocation("sizetable"); - m_opacitytable_id = program()->uniformLocation("opacitytable"); - } - - void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) override { - glFuncs->glActiveTexture(GL_TEXTURE1); - d->colorTable->bind(); - - // make sure we end by setting GL_TEXTURE0 as active texture - glFuncs->glActiveTexture(GL_TEXTURE0); - d->texture->bind(); - - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); - program()->setUniformValueArray(m_sizetable_id, (const float*) d->sizeTable, 64, 1); - program()->setUniformValueArray(m_opacitytable_id, (const float*) d->opacityTable, UNIFORM_ARRAY_SIZE, 1); - } - - int m_timestamp_id; - int m_entry_id; - int m_sizetable_id; - int m_opacitytable_id; - QByteArray m_vertex_code; - QByteArray m_fragment_code; - QOpenGLFunctions* glFuncs; + QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override { + Q_UNUSED(renderMode); + return new DeformableMaterialRhiShader(viewCount()); + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; }; -class ColoredMaterialData : public ImageMaterialData {}; -class ColoredMaterial : public QSGSimpleMaterialShader<ColoredMaterialData> -{ - QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData) +QSGMaterialType DeformableMaterial::m_type; +class ParticleSpriteMaterialRhiShader : public QSGMaterialShader +{ public: - ColoredMaterial() + ParticleSpriteMaterialRhiShader(int viewCount) { - QSGShaderSourceBuilder builder; - const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.vert.qsb"), viewCount); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.frag.qsb"), viewCount); + } - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert")); - builder.addDefinition(QByteArrayLiteral("COLOR")); - if (isES) - builder.removeVersion(); + bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + const int shaderMatrixCount = newMaterial->viewCount(); + const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount); + + for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) { + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(viewIndex); + memcpy(buf->data() + 64 * viewIndex, m.constData(), 64); + } + } - m_vertex_code = builder.source(); - builder.clear(); + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4); + } - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag")); - builder.addDefinition(QByteArrayLiteral("COLOR")); - if (isES) - builder.removeVersion(); + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); - m_fragment_code = builder.source(); + float entry = float(state->entry); + memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4); - Q_ASSERT(!m_vertex_code.isNull()); - Q_ASSERT(!m_fragment_code.isNull()); - } + float timestamp = float(state->timestamp); + memcpy(buf->data() + 64 * shaderMatrixCount + 8, ×tamp, 4); - const char *vertexShader() const override { return m_vertex_code.constData(); } - const char *fragmentShader() const override { return m_fragment_code.constData(); } + float *p = reinterpret_cast<float *>(buf->data() + 64 * shaderMatrixCount + 16); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->sizeTable[i]; + p += 4; + } + p = reinterpret_cast<float *>(buf->data() + 64 * shaderMatrixCount + 16 + (UNIFORM_ARRAY_SIZE * 4 * 4)); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->opacityTable[i]; + p += 4; + } - void activate() override { - QSGSimpleMaterialShader<ColoredMaterialData>::activate(); -#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) - glEnable(GL_POINT_SPRITE); - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif + return true; } - void deactivate() override { - QSGSimpleMaterialShader<ColoredMaterialData>::deactivate(); -#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) - glDisable(GL_POINT_SPRITE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif + void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); + if (binding == 2) { + state->colorTable->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->colorTable; + } else if (binding == 1) { + state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } } +}; - QList<QByteArray> attributes() const override { - return QList<QByteArray>() << "vPos" << "vData" << "vVec" << "vColor"; +class SpriteMaterial : public ImageMaterial +{ +public: + QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override { + Q_UNUSED(renderMode); + return new ParticleSpriteMaterialRhiShader(viewCount()); } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; - void initialize() override { - QSGSimpleMaterialShader<ColoredMaterialData>::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - glFuncs = QOpenGLContext::currentContext()->functions(); - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); +QSGMaterialType SpriteMaterial::m_type; + +class ColoredPointMaterialRhiShader : public QSGMaterialShader +{ +public: + ColoredPointMaterialRhiShader(int viewCount) + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_coloredpoint.vert.qsb"), viewCount); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_coloredpoint.frag.qsb"), viewCount); } - void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) override { - d->texture->bind(); + bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + const int shaderMatrixCount = newMaterial->viewCount(); + const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount); + + for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) { + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(viewIndex); + memcpy(buf->data() + 64 * viewIndex, m.constData(), 64); + } + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4); + } + + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 64 * shaderMatrixCount + 8, ×tamp, 4); + + float dpr = float(state->dpr); + memcpy(buf->data() + 64 * shaderMatrixCount + 12, &dpr, 4); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); + return true; } - int m_timestamp_id; - int m_entry_id; - QByteArray m_vertex_code; - QByteArray m_fragment_code; - QOpenGLFunctions* glFuncs; + void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); + if (binding == 1) { + state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } }; -class SimpleMaterialData : public ImageMaterialData {}; -class SimpleMaterial : public QSGSimpleMaterialShader<SimpleMaterialData> +class ColoredPointMaterial : public ImageMaterial { - QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData) +public: + QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override { + Q_UNUSED(renderMode); + return new ColoredPointMaterialRhiShader(viewCount()); + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType ColoredPointMaterial::m_type; +class ColoredMaterialRhiShader : public ColoredPointMaterialRhiShader +{ public: - SimpleMaterial() + ColoredMaterialRhiShader(int viewCount) + : ColoredPointMaterialRhiShader(viewCount) { - QSGShaderSourceBuilder builder; - const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.vert.qsb"), viewCount); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.frag.qsb"), viewCount); + } +}; - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.vert")); - if (isES) - builder.removeVersion(); +class ColoredMaterial : public ImageMaterial +{ +public: + QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override { + Q_UNUSED(renderMode); + return new ColoredMaterialRhiShader(viewCount()); + } + QSGMaterialType *type() const override { return &m_type; } - m_vertex_code = builder.source(); - builder.clear(); + ImageMaterialData *state() override { return &m_state; } - builder.appendSourceFile(QStringLiteral(":/particles/shaders/imageparticle.frag")); - if (isES) - builder.removeVersion(); +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; - m_fragment_code = builder.source(); +QSGMaterialType ColoredMaterial::m_type; - Q_ASSERT(!m_vertex_code.isNull()); - Q_ASSERT(!m_fragment_code.isNull()); +class SimplePointMaterialRhiShader : public QSGMaterialShader +{ +public: + SimplePointMaterialRhiShader(int viewCount) + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simplepoint.vert.qsb"), viewCount); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simplepoint.frag.qsb"), viewCount); } - const char *vertexShader() const override { return m_vertex_code.constData(); } - const char *fragmentShader() const override { return m_fragment_code.constData(); } + bool updateUniformData(RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + const int shaderMatrixCount = newMaterial->viewCount(); + const int matrixCount = qMin(renderState.projectionMatrixCount(), shaderMatrixCount); + + for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) { + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(viewIndex); + memcpy(buf->data() + 64 * viewIndex, m.constData(), 64); + } + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64 * shaderMatrixCount, &opacity, 4); + } - void activate() override { - QSGSimpleMaterialShader<SimpleMaterialData>::activate(); -#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) - glEnable(GL_POINT_SPRITE); - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif - } + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); - void deactivate() override { - QSGSimpleMaterialShader<SimpleMaterialData>::deactivate(); -#if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) - glDisable(GL_POINT_SPRITE); - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); -#endif - } + float entry = float(state->entry); + memcpy(buf->data() + 64 * shaderMatrixCount + 4, &entry, 4); - QList<QByteArray> attributes() const override { - return QList<QByteArray>() << "vPos" << "vData" << "vVec"; - } + float timestamp = float(state->timestamp); + memcpy(buf->data() + 64 * shaderMatrixCount + 8, ×tamp, 4); + + float dpr = float(state->dpr); + memcpy(buf->data() + 64 * shaderMatrixCount + 12, &dpr, 4); - void initialize() override { - QSGSimpleMaterialShader<SimpleMaterialData>::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - glFuncs = QOpenGLContext::currentContext()->functions(); - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); + return true; } - void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) override { - d->texture->bind(); + void updateSampledImage(RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast<ImageMaterial *>(newMaterial)->state(); + if (binding == 1) { + state->texture->commitTextureOperations(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); +class SimplePointMaterial : public ImageMaterial +{ +public: + QSGMaterialShader *createShader(QSGRendererInterface::RenderMode renderMode) const override { + Q_UNUSED(renderMode); + return new SimplePointMaterialRhiShader(viewCount()); } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } - int m_timestamp_id; - int m_entry_id; - QByteArray m_vertex_code; - QByteArray m_fragment_code; - QOpenGLFunctions* glFuncs; +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; }; +QSGMaterialType SimplePointMaterial::m_type; + void fillUniformArrayFromImage(float* array, const QImage& img, int size) { if (img.isNull()){ @@ -674,13 +674,12 @@ void fillUniformArrayFromImage(float* array, const QImage& img, int size) For fine-grained control, see sizeTable and opacityTable. Acceptable values are - \list - \li ImageParticle.None: Particles just appear and disappear. - \li ImageParticle.Fade: Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end. - \li ImageParticle.Scale: Particles scale in from 0 size at the start of their life, and scale back to 0 at the end. - \endlist - Default value is Fade. + \value ImageParticle.None Particles just appear and disappear. + \value ImageParticle.Fade Particles fade in from 0 opacity at the start of their life, and fade out to 0 at the end. + \value ImageParticle.Scale Particles scale in from 0 size at the start of their life, and scale back to 0 at the end. + + The default value is \c ImageParticle.Fade. */ /*! \qmlproperty bool QtQuick.Particles::ImageParticle::spritesInterpolate @@ -701,6 +700,7 @@ void fillUniformArrayFromImage(float* array, const QImage& img, int size) QQuickImageParticle::QQuickImageParticle(QQuickItem* parent) : QQuickParticlePainter(parent) , m_color_variation(0.0) + , m_outgoingNode(nullptr) , m_material(nullptr) , m_alphaVariation(0.0) , m_alpha(1.0) @@ -722,10 +722,14 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent) , m_explicitAnimation(false) , m_bypassOptimizations(false) , perfLevel(Unknown) - , m_lastLevel(Unknown) + , m_targetPerfLevel(Unknown) , m_debugMode(false) , m_entryEffect(Fade) , m_startedImageLoading(0) + , m_rhi(nullptr) + , m_apiChecked(false) + , m_dpr(1.0) + , m_previousActive(false) { setFlag(ItemHasContents); } @@ -737,13 +741,18 @@ QQuickImageParticle::~QQuickImageParticle() QQmlListProperty<QQuickSprite> QQuickImageParticle::sprites() { - return QQmlListProperty<QQuickSprite>(this, &m_sprites, spriteAppend, spriteCount, spriteAt, spriteClear); + return QQmlListProperty<QQuickSprite>(this, &m_sprites, + spriteAppend, spriteCount, spriteAt, + spriteClear, spriteReplace, spriteRemoveLast); } void QQuickImageParticle::sceneGraphInvalidated() { m_nodes.clear(); m_material = nullptr; + delete m_outgoingNode; + m_outgoingNode = nullptr; + m_apiChecked = false; } void QQuickImageParticle::setImage(const QUrl &image) @@ -830,8 +839,7 @@ void QQuickImageParticle::setColor(const QColor &color) m_color = color; emit colorChanged(); m_explicitColor = true; - if (perfLevel < Colored) - reset(); + checkPerfLevel(ColoredPoint); } void QQuickImageParticle::setColorVariation(qreal var) @@ -841,8 +849,7 @@ void QQuickImageParticle::setColorVariation(qreal var) m_color_variation = var; emit colorVariationChanged(); m_explicitColor = true; - if (perfLevel < Colored) - reset(); + checkPerfLevel(ColoredPoint); } void QQuickImageParticle::setAlphaVariation(qreal arg) @@ -852,8 +859,7 @@ void QQuickImageParticle::setAlphaVariation(qreal arg) emit alphaVariationChanged(arg); } m_explicitColor = true; - if (perfLevel < Colored) - reset(); + checkPerfLevel(ColoredPoint); } void QQuickImageParticle::setAlpha(qreal arg) @@ -863,8 +869,7 @@ void QQuickImageParticle::setAlpha(qreal arg) emit alphaChanged(arg); } m_explicitColor = true; - if (perfLevel < Colored) - reset(); + checkPerfLevel(ColoredPoint); } void QQuickImageParticle::setRedVariation(qreal arg) @@ -874,8 +879,7 @@ void QQuickImageParticle::setRedVariation(qreal arg) emit redVariationChanged(arg); } m_explicitColor = true; - if (perfLevel < Colored) - reset(); + checkPerfLevel(ColoredPoint); } void QQuickImageParticle::setGreenVariation(qreal arg) @@ -885,8 +889,7 @@ void QQuickImageParticle::setGreenVariation(qreal arg) emit greenVariationChanged(arg); } m_explicitColor = true; - if (perfLevel < Colored) - reset(); + checkPerfLevel(ColoredPoint); } void QQuickImageParticle::setBlueVariation(qreal arg) @@ -896,8 +899,7 @@ void QQuickImageParticle::setBlueVariation(qreal arg) emit blueVariationChanged(arg); } m_explicitColor = true; - if (perfLevel < Colored) - reset(); + checkPerfLevel(ColoredPoint); } void QQuickImageParticle::setRotation(qreal arg) @@ -907,8 +909,7 @@ void QQuickImageParticle::setRotation(qreal arg) emit rotationChanged(arg); } m_explicitRotation = true; - if (perfLevel < Deformable) - reset(); + checkPerfLevel(Deformable); } void QQuickImageParticle::setRotationVariation(qreal arg) @@ -918,8 +919,7 @@ void QQuickImageParticle::setRotationVariation(qreal arg) emit rotationVariationChanged(arg); } m_explicitRotation = true; - if (perfLevel < Deformable) - reset(); + checkPerfLevel(Deformable); } void QQuickImageParticle::setRotationVelocity(qreal arg) @@ -929,8 +929,7 @@ void QQuickImageParticle::setRotationVelocity(qreal arg) emit rotationVelocityChanged(arg); } m_explicitRotation = true; - if (perfLevel < Deformable) - reset(); + checkPerfLevel(Deformable); } void QQuickImageParticle::setRotationVelocityVariation(qreal arg) @@ -940,8 +939,7 @@ void QQuickImageParticle::setRotationVelocityVariation(qreal arg) emit rotationVelocityVariationChanged(arg); } m_explicitRotation = true; - if (perfLevel < Deformable) - reset(); + checkPerfLevel(Deformable); } void QQuickImageParticle::setAutoRotation(bool arg) @@ -951,8 +949,7 @@ void QQuickImageParticle::setAutoRotation(bool arg) emit autoRotationChanged(arg); } m_explicitRotation = true; - if (perfLevel < Deformable) - reset(); + checkPerfLevel(Deformable); } void QQuickImageParticle::setXVector(QQuickDirection* arg) @@ -962,8 +959,7 @@ void QQuickImageParticle::setXVector(QQuickDirection* arg) emit xVectorChanged(arg); } m_explicitDeformation = true; - if (perfLevel < Deformable) - reset(); + checkPerfLevel(Deformable); } void QQuickImageParticle::setYVector(QQuickDirection* arg) @@ -973,8 +969,7 @@ void QQuickImageParticle::setYVector(QQuickDirection* arg) emit yVectorChanged(arg); } m_explicitDeformation = true; - if (perfLevel < Deformable) - reset(); + checkPerfLevel(Deformable); } void QQuickImageParticle::setSpritesInterpolate(bool arg) @@ -1000,7 +995,7 @@ void QQuickImageParticle::setEntryEffect(EntryEffect arg) if (m_entryEffect != arg) { m_entryEffect = arg; if (m_material) - getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect; + getState(m_material)->entry = (qreal) m_entryEffect; emit entryEffectChanged(arg); } } @@ -1009,7 +1004,7 @@ void QQuickImageParticle::resetColor() { m_explicitColor = false; for (auto groupId : groupIds()) { - for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) { if (d->colorOwner == this) { d->colorOwner = nullptr; } @@ -1028,7 +1023,7 @@ void QQuickImageParticle::resetRotation() { m_explicitRotation = false; for (auto groupId : groupIds()) { - for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) { if (d->rotationOwner == this) { d->rotationOwner = nullptr; } @@ -1045,7 +1040,7 @@ void QQuickImageParticle::resetDeformation() { m_explicitDeformation = false; for (auto groupId : groupIds()) { - for (QQuickParticleData* d : qAsConst(m_system->groupData[groupId]->data)) { + for (QQuickParticleData* d : std::as_const(m_system->groupData[groupId]->data)) { if (d->deformationOwner == this) { d->deformationOwner = nullptr; } @@ -1066,14 +1061,20 @@ void QQuickImageParticle::reset() update(); } + +void QQuickImageParticle::invalidateSceneGraph() +{ + reset(); +} + void QQuickImageParticle::createEngine() { if (m_spriteEngine) delete m_spriteEngine; - if (m_sprites.count()) { + if (m_sprites.size()) { m_spriteEngine = new QQuickSpriteEngine(m_sprites, this); - connect(m_spriteEngine, SIGNAL(stateChanged(int)), - this, SLOT(spriteAdvance(int)), Qt::DirectConnection); + connect(m_spriteEngine, &QQuickStochasticEngine::stateChanged, + this, &QQuickImageParticle::spriteAdvance, Qt::DirectConnection); m_explicitAnimation = true; } else { m_spriteEngine = nullptr; @@ -1082,64 +1083,79 @@ void QQuickImageParticle::createEngine() reset(); } -static QSGGeometry::Attribute SimpleParticle_Attributes[] = { - QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position - QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data - QSGGeometry::Attribute::create(2, 4, GL_FLOAT) // Vectors +static QSGGeometry::Attribute SimplePointParticle_Attributes[] = { + QSGGeometry::Attribute::create(0, 2, QSGGeometry::FloatType, true), // Position + QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data + QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType) // Vectors }; -static QSGGeometry::AttributeSet SimpleParticle_AttributeSet = +static QSGGeometry::AttributeSet SimplePointParticle_AttributeSet = { 3, // Attribute Count ( 2 + 4 + 4 ) * sizeof(float), - SimpleParticle_Attributes + SimplePointParticle_Attributes }; -static QSGGeometry::Attribute ColoredParticle_Attributes[] = { - QSGGeometry::Attribute::create(0, 2, GL_FLOAT, true), // Position - QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data - QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors - QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors +static QSGGeometry::Attribute ColoredPointParticle_Attributes[] = { + QSGGeometry::Attribute::create(0, 2, QSGGeometry::FloatType, true), // Position + QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data + QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors + QSGGeometry::Attribute::create(3, 4, QSGGeometry::UnsignedByteType), // Colors }; -static QSGGeometry::AttributeSet ColoredParticle_AttributeSet = +static QSGGeometry::AttributeSet ColoredPointParticle_AttributeSet = { 4, // Attribute Count ( 2 + 4 + 4 ) * sizeof(float) + 4 * sizeof(uchar), + ColoredPointParticle_Attributes +}; + +static QSGGeometry::Attribute ColoredParticle_Attributes[] = { + QSGGeometry::Attribute::create(0, 2, QSGGeometry::FloatType, true), // Position + QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data + QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors + QSGGeometry::Attribute::create(3, 4, QSGGeometry::UnsignedByteType), // Colors + QSGGeometry::Attribute::create(4, 4, QSGGeometry::UnsignedByteType), // TexCoord +}; + +static QSGGeometry::AttributeSet ColoredParticle_AttributeSet = +{ + 5, // Attribute Count + ( 2 + 4 + 4 ) * sizeof(float) + (4 + 4) * sizeof(uchar), ColoredParticle_Attributes }; static QSGGeometry::Attribute DeformableParticle_Attributes[] = { - QSGGeometry::Attribute::create(0, 4, GL_FLOAT), // Position & TexCoord - QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data - QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors - QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors - QSGGeometry::Attribute::create(4, 4, GL_FLOAT), // DeformationVectors - QSGGeometry::Attribute::create(5, 3, GL_FLOAT), // Rotation + QSGGeometry::Attribute::create(0, 4, QSGGeometry::FloatType), // Position & Rotation + QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data + QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors + QSGGeometry::Attribute::create(3, 4, QSGGeometry::UnsignedByteType), // Colors + QSGGeometry::Attribute::create(4, 4, QSGGeometry::FloatType), // DeformationVectors + QSGGeometry::Attribute::create(5, 4, QSGGeometry::UnsignedByteType), // TexCoord & autoRotate }; static QSGGeometry::AttributeSet DeformableParticle_AttributeSet = { 6, // Attribute Count - (4 + 4 + 4 + 4 + 3) * sizeof(float) + 4 * sizeof(uchar), + (4 + 4 + 4 + 4) * sizeof(float) + (4 + 4) * sizeof(uchar), DeformableParticle_Attributes }; static QSGGeometry::Attribute SpriteParticle_Attributes[] = { - QSGGeometry::Attribute::create(0, 4, GL_FLOAT), // Position & TexCoord - QSGGeometry::Attribute::create(1, 4, GL_FLOAT), // Data - QSGGeometry::Attribute::create(2, 4, GL_FLOAT), // Vectors - QSGGeometry::Attribute::create(3, 4, GL_UNSIGNED_BYTE), // Colors - QSGGeometry::Attribute::create(4, 4, GL_FLOAT), // DeformationVectors - QSGGeometry::Attribute::create(5, 3, GL_FLOAT), // Rotation - QSGGeometry::Attribute::create(6, 3, GL_FLOAT), // Anim Data - QSGGeometry::Attribute::create(7, 4, GL_FLOAT) // Anim Pos + QSGGeometry::Attribute::create(0, 4, QSGGeometry::FloatType), // Position & Rotation + QSGGeometry::Attribute::create(1, 4, QSGGeometry::FloatType), // Data + QSGGeometry::Attribute::create(2, 4, QSGGeometry::FloatType), // Vectors + QSGGeometry::Attribute::create(3, 4, QSGGeometry::UnsignedByteType), // Colors + QSGGeometry::Attribute::create(4, 4, QSGGeometry::FloatType), // DeformationVectors + QSGGeometry::Attribute::create(5, 4, QSGGeometry::UnsignedByteType), // TexCoord & autoRotate + QSGGeometry::Attribute::create(6, 3, QSGGeometry::FloatType), // Anim Data + QSGGeometry::Attribute::create(7, 3, QSGGeometry::FloatType) // Anim Pos }; static QSGGeometry::AttributeSet SpriteParticle_AttributeSet = { 8, // Attribute Count - (4 + 4 + 4 + 4 + 3 + 3 + 4) * sizeof(float) + 4 * sizeof(uchar), + (4 + 4 + 4 + 4 + 3 + 3) * sizeof(float) + (4 + 4) * sizeof(uchar), SpriteParticle_Attributes }; @@ -1156,8 +1172,8 @@ QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datu //Will return datum if the datum is a sentinel or uninitialized, to centralize that one check if (datum->systemIndex == -1) return datum; - QQuickParticleGroupData* gd = m_system->groupData[datum->groupId]; if (!m_shadowData.contains(datum->groupId)) { + QQuickParticleGroupData* gd = m_system->groupData[datum->groupId]; QVector<QQuickParticleData*> data; const int gdSize = gd->size(); data.reserve(gdSize); @@ -1173,6 +1189,14 @@ QQuickParticleData* QQuickImageParticle::getShadowDatum(QQuickParticleData* datu return m_shadowData[datum->groupId][datum->index]; } +void QQuickImageParticle::checkPerfLevel(PerformanceLevel level) +{ + if (m_targetPerfLevel < level) { + m_targetPerfLevel = level; + reset(); + } +} + bool QQuickImageParticle::loadingSomething() { return (m_image && m_image->pix.isLoading()) @@ -1184,22 +1208,33 @@ bool QQuickImageParticle::loadingSomething() void QQuickImageParticle::mainThreadFetchImageData() { + const QQmlContext *context = nullptr; + QQmlEngine *engine = nullptr; + const auto loadPix = [&](ImageData *image) { + if (!engine) { + context = qmlContext(this); + engine = context->engine(); + } + image->pix.load(engine, context->resolvedUrl(image->source)); + }; + + if (m_image) {//ImageData created on setSource m_image->pix.clear(this); - m_image->pix.load(qmlEngine(this), m_image->source); + loadPix(m_image.get()); } if (m_spriteEngine) m_spriteEngine->startAssemblingImage(); if (m_colorTable) - m_colorTable->pix.load(qmlEngine(this), m_colorTable->source); + loadPix(m_colorTable.get()); if (m_sizeTable) - m_sizeTable->pix.load(qmlEngine(this), m_sizeTable->source); + loadPix(m_sizeTable.get()); if (m_opacityTable) - m_opacityTable->pix.load(qmlEngine(this), m_opacityTable->source); + loadPix(m_opacityTable.get()); m_startedImageLoading = 2; } @@ -1224,7 +1259,7 @@ void QQuickImageParticle::buildParticleNodes(QSGNode** passThrough) void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) { - if (!QOpenGLContext::currentContext()) + if (!m_rhi) return; if (m_count * 4 > 0xffff) { @@ -1233,12 +1268,12 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) return; } - if (count() <= 0) + if (m_count <= 0) return; m_debugMode = m_system->m_debugMode; - if (m_sprites.count() || m_bypassOptimizations) { + if (m_sprites.size() || m_bypassOptimizations) { perfLevel = Sprites; } else if (m_colorTable || m_sizeTable || m_opacityTable) { perfLevel = Tabled; @@ -1248,14 +1283,14 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) perfLevel = Deformable; } else if (m_alphaVariation || m_alpha != 1.0 || m_color.isValid() || m_color_variation || m_redVariation || m_blueVariation || m_greenVariation) { - perfLevel = Colored; + perfLevel = ColoredPoint; } else { - perfLevel = Simple; + perfLevel = SimplePoint; } for (auto groupId : groupIds()) { //For sharing higher levels, need to have highest used so it renders - for (QQuickParticlePainter* p : qAsConst(m_system->groupData[groupId]->painters)) { + for (QQuickParticlePainter* p : std::as_const(m_system->groupData[groupId]->painters)) { QQuickImageParticle* other = qobject_cast<QQuickImageParticle*>(p); if (other){ if (other->perfLevel > perfLevel) { @@ -1271,31 +1306,18 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) } } } -#ifdef Q_OS_WIN - if (perfLevel < Deformable) //QTBUG-24540 , point sprite 'extension' isn't working on windows. - perfLevel = Deformable; -#endif - -#ifdef Q_OS_MAC - // OS X 10.8.3 introduced a bug in the AMD drivers, for at least the 2011 macbook pros, - // causing point sprites who read gl_PointCoord in the frag shader to come out as - // green-red blobs. - const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR); - if (perfLevel < Deformable && glVendor && strstr((char *) glVendor, "ATI")) { - perfLevel = Deformable; - } -#endif -#ifdef Q_OS_LINUX - // Nouveau drivers can potentially freeze a machine entirely when taking the point-sprite path. - const GLubyte *glVendor = QOpenGLContext::currentContext()->functions()->glGetString(GL_VENDOR); - if (perfLevel < Deformable && glVendor && strstr((const char *) glVendor, "nouveau")) - perfLevel = Deformable; -#endif + // Points with a size other than 1 are an optional feature with QRhi + // because some of the underlying APIs have no support for this. + // Therefore, avoid the point sprite path with APIs like Direct3D. + if (perfLevel < Colored && !m_rhi->isFeatureSupported(QRhi::VertexShaderPointSize)) + perfLevel = Colored; - if (perfLevel >= Colored && !m_color.isValid()) + if (perfLevel >= ColoredPoint && !m_color.isValid()) m_color = QColor(Qt::white);//Hidden default, but different from unset + m_targetPerfLevel = perfLevel; + clearShadows(); if (m_material) m_material = nullptr; @@ -1308,6 +1330,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) bool imageLoaded = false; switch (perfLevel) {//Fallthrough intended case Sprites: + { if (!m_spriteEngine) { qWarning() << "ImageParticle: No sprite engine..."; //Sprite performance mode with static image is supported, but not advised @@ -1318,16 +1341,19 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) return; imageLoaded = true; } - m_material = SpriteMaterial::createMaterial(); + m_material = new SpriteMaterial; + ImageMaterialData *state = getState(m_material); if (imageLoaded) - getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(image); - getState<ImageMaterialData>(m_material)->animSheetSize = QSizeF(image.size() / image.devicePixelRatioF()); + state->texture = QSGPlainTexture::fromImage(image); + state->animSheetSize = QSizeF(image.size() / image.devicePixelRatio()); if (m_spriteEngine) m_spriteEngine->setCount(m_count); + } Q_FALLTHROUGH(); case Tabled: + { if (!m_material) - m_material = TabledMaterial::createMaterial(); + m_material = new TabledMaterial; if (m_colorTable) { if (m_colorTable->pix.isReady()) @@ -1354,21 +1380,35 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) colortable = QImage(1,1,QImage::Format_ARGB32_Premultiplied); colortable.fill(Qt::white); } - getState<ImageMaterialData>(m_material)->colorTable = QSGPlainTexture::fromImage(colortable); - fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE); - fillUniformArrayFromImage(getState<ImageMaterialData>(m_material)->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE); + ImageMaterialData *state = getState(m_material); + state->colorTable = QSGPlainTexture::fromImage(colortable); + fillUniformArrayFromImage(state->sizeTable, sizetable, UNIFORM_ARRAY_SIZE); + fillUniformArrayFromImage(state->opacityTable, opacitytable, UNIFORM_ARRAY_SIZE); + } Q_FALLTHROUGH(); case Deformable: + { if (!m_material) - m_material = DeformableMaterial::createMaterial(); + m_material = new DeformableMaterial; + } Q_FALLTHROUGH(); case Colored: + { if (!m_material) - m_material = ColoredMaterial::createMaterial(); + m_material = new ColoredMaterial; + } + Q_FALLTHROUGH(); + case ColoredPoint: + { + if (!m_material) + m_material = new ColoredPointMaterial; + } Q_FALLTHROUGH(); default://Also Simple + { if (!m_material) - m_material = SimpleMaterial::createMaterial(); + m_material = new SimplePointMaterial; + ImageMaterialData *state = getState(m_material); if (!imageLoaded) { if (!m_image || !m_image->pix.isReady()) { if (m_image) @@ -1376,14 +1416,17 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) delete m_material; return; } - //getState<ImageMaterialData>(m_material)->texture //TODO: Shouldn't this be better? But not crash? + //state->texture //TODO: Shouldn't this be better? But not crash? // = QQuickItemPrivate::get(this)->sceneGraphContext()->textureForFactory(m_imagePix.textureFactory()); - getState<ImageMaterialData>(m_material)->texture = QSGPlainTexture::fromImage(m_image->pix.image()); + state->texture = QSGPlainTexture::fromImage(m_image->pix.image()); } - getState<ImageMaterialData>(m_material)->texture->setFiltering(QSGTexture::Linear); - getState<ImageMaterialData>(m_material)->entry = (qreal) m_entryEffect; + state->texture->setFiltering(QSGTexture::Linear); + state->entry = (qreal) m_entryEffect; + state->dpr = m_dpr; + m_material->setFlag(QSGMaterial::Blending | QSGMaterial::RequiresFullMatrix); } + } m_nodes.clear(); for (auto groupId : groupIds()) { @@ -1394,7 +1437,7 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) m_nodes.insert(groupId, node); m_idxStarts.insert(groupId, m_lastIdxStart); - m_startsIdx.append(qMakePair<int,int>(m_lastIdxStart, groupId)); + m_startsIdx.append(qMakePair(m_lastIdxStart, groupId)); m_lastIdxStart += count; //Create Particle Geometry @@ -1409,21 +1452,21 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) else if (perfLevel == Deformable) g = new QSGGeometry(DeformableParticle_AttributeSet, vCount, iCount); else if (perfLevel == Colored) - g = new QSGGeometry(ColoredParticle_AttributeSet, count, 0); + g = new QSGGeometry(ColoredParticle_AttributeSet, vCount, iCount); + else if (perfLevel == ColoredPoint) + g = new QSGGeometry(ColoredPointParticle_AttributeSet, count, 0); else //Simple - g = new QSGGeometry(SimpleParticle_AttributeSet, count, 0); + g = new QSGGeometry(SimplePointParticle_AttributeSet, count, 0); node->setFlag(QSGNode::OwnsGeometry); node->setGeometry(g); - if (perfLevel <= Colored){ - g->setDrawingMode(GL_POINTS); - if (m_debugMode){ - GLfloat pointSizeRange[2]; - QOpenGLContext::currentContext()->functions()->glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange); - qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <<pointSizeRange[0] << ":" << pointSizeRange[1]; - } - }else - g->setDrawingMode(GL_TRIANGLES); + if (perfLevel <= ColoredPoint){ + g->setDrawingMode(QSGGeometry::DrawPoints); + if (m_debugMode) + qDebug("Using point sprites"); + } else { + g->setDrawingMode(QSGGeometry::DrawTriangles); + } for (int p=0; p < count; ++p) commit(groupId, p);//commit sets geometry for the node, has its own perfLevel switch @@ -1434,8 +1477,10 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount); else if (perfLevel == Deformable) initTexCoords<DeformableVertex>((DeformableVertex*)g->vertexData(), vCount); + else if (perfLevel == Colored) + initTexCoords<ColoredVertex>((ColoredVertex*)g->vertexData(), vCount); - if (perfLevel > Colored){ + if (perfLevel > ColoredPoint){ quint16 *indices = g->indexDataAsUShort(); for (int i=0; i < count; ++i) { int o = i * 4; @@ -1464,23 +1509,44 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) update(); } -static inline bool isOpenGL(QSGRenderContext *rc) -{ - QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc); - return !rif || rif->graphicsApi() == QSGRendererInterface::OpenGL; -} - QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData *) { - if (!node && !isOpenGL(QQuickItemPrivate::get(this)->sceneGraphRenderContext())) - return nullptr; + if (!m_apiChecked || m_windowChanged) { + m_apiChecked = true; + m_windowChanged = false; + + QSGRenderContext *rc = QQuickItemPrivate::get(this)->sceneGraphRenderContext(); + QSGRendererInterface *rif = rc->sceneGraphContext()->rendererInterface(rc); + if (!rif) + return nullptr; + + QSGRendererInterface::GraphicsApi api = rif->graphicsApi(); + const bool isRhi = QSGRendererInterface::isApiRhiBased(api); + + if (!node && !isRhi) + return nullptr; + + if (isRhi) + m_rhi = static_cast<QRhi *>(rif->getResource(m_window, QSGRendererInterface::RhiResource)); + else + m_rhi = nullptr; + + if (isRhi && !m_rhi) { + qWarning("Failed to query QRhi, particles disabled"); + return nullptr; + } + // Get the pixel ratio of the window, used for pointsize scaling + m_dpr = m_window ? m_window->devicePixelRatio() : 1.0; + } if (m_pleaseReset){ - if (node) - delete node; + // Cannot just destroy the node and then return null (in case image + // loading is still in progress). Rather, keep track of the old node + // until we have a new one. + delete m_outgoingNode; + m_outgoingNode = node; node = nullptr; - m_lastLevel = perfLevel; m_nodes.clear(); m_idxStarts.clear(); @@ -1491,23 +1557,33 @@ QSGNode *QQuickImageParticle::updatePaintNode(QSGNode *node, UpdatePaintNodeData m_pleaseReset = false; m_startedImageLoading = 0;//Cancel a part-way build (may still have a pending load) + } else if (!m_material) { + delete node; + node = nullptr; } if (m_system && m_system->isRunning() && !m_system->isPaused()){ - prepareNextFrame(&node); + bool dirty = prepareNextFrame(&node); if (node) { update(); - foreach (QSGGeometryNode* n, m_nodes) - n->markDirty(QSGNode::DirtyGeometry); + if (dirty) { + foreach (QSGGeometryNode* n, m_nodes) + n->markDirty(QSGNode::DirtyGeometry); + } } else if (m_startedImageLoading < 2) { update();//To call prepareNextFrame() again from the renderThread } } + if (!node) { + node = m_outgoingNode; + m_outgoingNode = nullptr; + } + return node; } -void QQuickImageParticle::prepareNextFrame(QSGNode **node) +bool QQuickImageParticle::prepareNextFrame(QSGNode **node) { if (*node == nullptr){//TODO: Staggered loading (as emitted) buildParticleNodes(node); @@ -1523,7 +1599,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) qDebug() << "Total count: " << count; } if (*node == nullptr) - return; + return false; } qint64 timeStamp = m_system->systemSync(this); @@ -1539,20 +1615,37 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) case Tabled: case Deformable: case Colored: - case Simple: + case ColoredPoint: + case SimplePoint: default: //Also Simple - getState<ImageMaterialData>(m_material)->timestamp = time; + getState(m_material)->timestamp = time; break; } - foreach (QSGGeometryNode* node, m_nodes) - node->markDirty(QSGNode::DirtyMaterial); + + bool active = false; + for (auto groupId : groupIds()) { + if (m_system->groupData[groupId]->isActive()) { + active = true; + break; + } + } + + const bool dirty = active || m_previousActive; + if (dirty) { + foreach (QSGGeometryNode* node, m_nodes) + node->markDirty(QSGNode::DirtyMaterial); + } + + m_previousActive = active; + return dirty; } void QQuickImageParticle::spritesUpdate(qreal time) { + ImageMaterialData *state = getState(m_material); // Sprite progression handled CPU side, so as to have per-frame control. for (auto groupId : groupIds()) { - for (QQuickParticleData* mainDatum : qAsConst(m_system->groupData[groupId]->data)) { + for (QQuickParticleData* mainDatum : std::as_const(m_system->groupData[groupId]->data)) { QSGGeometryNode *node = m_nodes[groupId]; if (!node) continue; @@ -1560,7 +1653,7 @@ void QQuickImageParticle::spritesUpdate(qreal time) // This is particularly important for cut-up sprites. QQuickParticleData* datum = (mainDatum->animationOwner == this ? mainDatum : getShadowDatum(mainDatum)); int spriteIdx = 0; - for (int i = 0; i<m_startsIdx.count(); i++) { + for (int i = 0; i<m_startsIdx.size(); i++) { if (m_startsIdx[i].second == groupId){ spriteIdx = m_startsIdx[i].first + datum->index; break; @@ -1587,7 +1680,7 @@ void QQuickImageParticle::spritesUpdate(qreal time) } if (m_spriteEngine->sprite(spriteIdx)->reverse())//### Store this in datum too? frameAt = (datum->frameCount - 1) - frameAt; - QSizeF sheetSize = getState<ImageMaterialData>(m_material)->animSheetSize; + QSizeF sheetSize = state->animSheetSize; qreal y = datum->animY / sheetSize.height(); qreal w = datum->animWidth / sheetSize.width(); qreal h = datum->animHeight / sheetSize.height(); @@ -1603,7 +1696,6 @@ void QQuickImageParticle::spritesUpdate(qreal time) spriteVertices[i].animX1 = x1; spriteVertices[i].animY1 = y; spriteVertices[i].animX2 = x2; - spriteVertices[i].animY2 = y; spriteVertices[i].animW = w; spriteVertices[i].animH = h; spriteVertices[i].animProgress = progress; @@ -1614,12 +1706,12 @@ void QQuickImageParticle::spritesUpdate(qreal time) void QQuickImageParticle::spriteAdvance(int spriteIdx) { - if (!m_startsIdx.count())//Probably overly defensive + if (!m_startsIdx.size())//Probably overly defensive return; int gIdx = -1; int i; - for (i = 0; i<m_startsIdx.count(); i++) { + for (i = 0; i<m_startsIdx.size(); i++) { if (spriteIdx < m_startsIdx[i].first) { gIdx = m_startsIdx[i-1].second; break; @@ -1642,12 +1734,6 @@ void QQuickImageParticle::spriteAdvance(int spriteIdx) datum->animHeight = m_spriteEngine->spriteHeight(spriteIdx); } -void QQuickImageParticle::reloadColor(const Color4ub &c, QQuickParticleData* d) -{ - d->color = c; - //TODO: get index for reload - or make function take an index -} - void QQuickImageParticle::initialize(int gIdx, int pIdx) { Color4ub color; @@ -1664,7 +1750,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) float rotation; float rotationVelocity; - float autoRotate; + uchar autoRotate; switch (perfLevel){//Fall-through is intended on all of them case Sprites: // Initial Sprite State @@ -1686,6 +1772,7 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) writeTo->animHeight = m_spriteEngine->spriteHeight(spriteIdx); } } else { + ImageMaterialData *state = getState(m_material); QQuickParticleData* writeTo = getShadowDatum(datum); writeTo->animT = datum->t; writeTo->frameCount = 1; @@ -1694,8 +1781,8 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) writeTo->animIdx = 0; writeTo->animT = 0; writeTo->animX = writeTo->animY = 0; - writeTo->animWidth = getState<ImageMaterialData>(m_material)->animSheetSize.width(); - writeTo->animHeight = getState<ImageMaterialData>(m_material)->animSheetSize.height(); + writeTo->animWidth = state->animSheetSize.width(); + writeTo->animHeight = state->animSheetSize.height(); } Q_FALLTHROUGH(); case Tabled: @@ -1710,8 +1797,9 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) datum->xx = ret.x(); datum->xy = ret.y(); } else { - getShadowDatum(datum)->xx = ret.x(); - getShadowDatum(datum)->xy = ret.y(); + QQuickParticleData* shadow = getShadowDatum(datum); + shadow->xx = ret.x(); + shadow->xy = ret.y(); } } if (m_yVector){ @@ -1720,8 +1808,9 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) datum->yx = ret.x(); datum->yy = ret.y(); } else { - getShadowDatum(datum)->yx = ret.x(); - getShadowDatum(datum)->yy = ret.y(); + QQuickParticleData* shadow = getShadowDatum(datum); + shadow->yx = ret.x(); + shadow->yy = ret.y(); } } } @@ -1729,37 +1818,45 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) if (m_explicitRotation){ if (!datum->rotationOwner) datum->rotationOwner = this; - rotation = - (m_rotation + (m_rotationVariation - 2*QRandomGenerator::global()->bounded(m_rotationVariation)) ) * CONV; - rotationVelocity = - (m_rotationVelocity + (m_rotationVelocityVariation - 2*QRandomGenerator::global()->bounded(m_rotationVelocityVariation)) ) * CONV; - autoRotate = m_autoRotation?1.0:0.0; + rotation = qDegreesToRadians( + m_rotation + (m_rotationVariation + - 2 * QRandomGenerator::global()->bounded(m_rotationVariation))); + rotationVelocity = qDegreesToRadians( + m_rotationVelocity + + (m_rotationVelocityVariation + - 2 * QRandomGenerator::global()->bounded(m_rotationVelocityVariation))); + autoRotate = m_autoRotation ? 1 : 0; if (datum->rotationOwner == this) { datum->rotation = rotation; datum->rotationVelocity = rotationVelocity; datum->autoRotate = autoRotate; } else { - getShadowDatum(datum)->rotation = rotation; - getShadowDatum(datum)->rotationVelocity = rotationVelocity; - getShadowDatum(datum)->autoRotate = autoRotate; + QQuickParticleData* shadow = getShadowDatum(datum); + shadow->rotation = rotation; + shadow->rotationVelocity = rotationVelocity; + shadow->autoRotate = autoRotate; } } Q_FALLTHROUGH(); case Colored: + Q_FALLTHROUGH(); + case ColoredPoint: //Color initialization // Particle color if (m_explicitColor) { if (!datum->colorOwner) datum->colorOwner = this; - color.r = m_color.red() * (1 - redVariation) + QRandomGenerator::global()->bounded(256) * redVariation; - color.g = m_color.green() * (1 - greenVariation) + QRandomGenerator::global()->bounded(256) * greenVariation; - color.b = m_color.blue() * (1 - blueVariation) + QRandomGenerator::global()->bounded(256) * blueVariation; - color.a = m_alpha * m_color.alpha() * (1 - m_alphaVariation) + QRandomGenerator::global()->bounded(256) * m_alphaVariation; + const auto rgbColor = m_color.toRgb(); + color.r = rgbColor.red() * (1 - redVariation) + QRandomGenerator::global()->bounded(256) * redVariation; + color.g = rgbColor.green() * (1 - greenVariation) + QRandomGenerator::global()->bounded(256) * greenVariation; + color.b = rgbColor.blue() * (1 - blueVariation) + QRandomGenerator::global()->bounded(256) * blueVariation; + color.a = m_alpha * rgbColor.alpha() * (1 - m_alphaVariation) + QRandomGenerator::global()->bounded(256) * m_alphaVariation; if (datum->colorOwner == this) datum->color = color; else getShadowDatum(datum)->color = color; } + break; default: break; } @@ -1776,7 +1873,8 @@ void QQuickImageParticle::commit(int gIdx, int pIdx) SpriteVertex *spriteVertices = (SpriteVertex *) node->geometry()->vertexData(); DeformableVertex *deformableVertices = (DeformableVertex *) node->geometry()->vertexData(); ColoredVertex *coloredVertices = (ColoredVertex *) node->geometry()->vertexData(); - SimpleVertex *simpleVertices = (SimpleVertex *) node->geometry()->vertexData(); + ColoredPointVertex *coloredPointVertices = (ColoredPointVertex *) node->geometry()->vertexData(); + SimplePointVertex *simplePointVertices = (SimplePointVertex *) node->geometry()->vertexData(); switch (perfLevel){//No automatic fall through intended on this one case Sprites: spriteVertices += pIdx*4; @@ -1816,15 +1914,9 @@ void QQuickImageParticle::commit(int gIdx, int pIdx) //Sprite-related vertices updated per-frame in spritesUpdate(), not on demand if (m_explicitColor && datum->colorOwner != this) { QQuickParticleData* shadow = getShadowDatum(datum); - spriteVertices[i].color.r = shadow->color.r; - spriteVertices[i].color.g = shadow->color.g; - spriteVertices[i].color.b = shadow->color.b; - spriteVertices[i].color.a = shadow->color.a; + spriteVertices[i].color = shadow->color; } else { - spriteVertices[i].color.r = datum->color.r; - spriteVertices[i].color.g = datum->color.g; - spriteVertices[i].color.b = datum->color.b; - spriteVertices[i].color.a = datum->color.a; + spriteVertices[i].color = datum->color; } } break; @@ -1866,21 +1958,15 @@ void QQuickImageParticle::commit(int gIdx, int pIdx) } if (m_explicitColor && datum->colorOwner != this) { QQuickParticleData* shadow = getShadowDatum(datum); - deformableVertices[i].color.r = shadow->color.r; - deformableVertices[i].color.g = shadow->color.g; - deformableVertices[i].color.b = shadow->color.b; - deformableVertices[i].color.a = shadow->color.a; + deformableVertices[i].color = shadow->color; } else { - deformableVertices[i].color.r = datum->color.r; - deformableVertices[i].color.g = datum->color.g; - deformableVertices[i].color.b = datum->color.b; - deformableVertices[i].color.a = datum->color.a; + deformableVertices[i].color = datum->color; } } break; case Colored: - coloredVertices += pIdx*1; - for (int i=0; i<1; i++){ + coloredVertices += pIdx*4; + for (int i=0; i<4; i++){ coloredVertices[i].x = datum->x - m_systemOffset.x(); coloredVertices[i].y = datum->y - m_systemOffset.y(); coloredVertices[i].t = datum->t; @@ -1893,31 +1979,46 @@ void QQuickImageParticle::commit(int gIdx, int pIdx) coloredVertices[i].ay = datum->ay; if (m_explicitColor && datum->colorOwner != this) { QQuickParticleData* shadow = getShadowDatum(datum); - coloredVertices[i].color.r = shadow->color.r; - coloredVertices[i].color.g = shadow->color.g; - coloredVertices[i].color.b = shadow->color.b; - coloredVertices[i].color.a = shadow->color.a; + coloredVertices[i].color = shadow->color; + } else { + coloredVertices[i].color = datum->color; + } + } + break; + case ColoredPoint: + coloredPointVertices += pIdx*1; + for (int i=0; i<1; i++){ + coloredPointVertices[i].x = datum->x - m_systemOffset.x(); + coloredPointVertices[i].y = datum->y - m_systemOffset.y(); + coloredPointVertices[i].t = datum->t; + coloredPointVertices[i].lifeSpan = datum->lifeSpan; + coloredPointVertices[i].size = datum->size; + coloredPointVertices[i].endSize = datum->endSize; + coloredPointVertices[i].vx = datum->vx; + coloredPointVertices[i].vy = datum->vy; + coloredPointVertices[i].ax = datum->ax; + coloredPointVertices[i].ay = datum->ay; + if (m_explicitColor && datum->colorOwner != this) { + QQuickParticleData* shadow = getShadowDatum(datum); + coloredPointVertices[i].color = shadow->color; } else { - coloredVertices[i].color.r = datum->color.r; - coloredVertices[i].color.g = datum->color.g; - coloredVertices[i].color.b = datum->color.b; - coloredVertices[i].color.a = datum->color.a; + coloredPointVertices[i].color = datum->color; } } break; - case Simple: - simpleVertices += pIdx*1; + case SimplePoint: + simplePointVertices += pIdx*1; for (int i=0; i<1; i++){ - simpleVertices[i].x = datum->x - m_systemOffset.x(); - simpleVertices[i].y = datum->y - m_systemOffset.y(); - simpleVertices[i].t = datum->t; - simpleVertices[i].lifeSpan = datum->lifeSpan; - simpleVertices[i].size = datum->size; - simpleVertices[i].endSize = datum->endSize; - simpleVertices[i].vx = datum->vx; - simpleVertices[i].vy = datum->vy; - simpleVertices[i].ax = datum->ax; - simpleVertices[i].ay = datum->ay; + simplePointVertices[i].x = datum->x - m_systemOffset.x(); + simplePointVertices[i].y = datum->y - m_systemOffset.y(); + simplePointVertices[i].t = datum->t; + simplePointVertices[i].lifeSpan = datum->lifeSpan; + simplePointVertices[i].size = datum->size; + simplePointVertices[i].endSize = datum->endSize; + simplePointVertices[i].vx = datum->vx; + simplePointVertices[i].vy = datum->vy; + simplePointVertices[i].ax = datum->ax; + simplePointVertices[i].ay = datum->ay; } break; default: |