aboutsummaryrefslogtreecommitdiffstats
path: root/src/particles/qquickimageparticle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/particles/qquickimageparticle.cpp')
-rw-r--r--src/particles/qquickimageparticle.cpp1211
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, &timestamp, 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, &timestamp, 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, &timestamp, 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, &timestamp, 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, &timestamp, 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: