From 720dd939b4ee9571d847465c83b6431a7bdf0d7e Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Sat, 10 Aug 2019 18:07:07 +0200 Subject: Make ImageParticle functional when rendering via the RHI MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Involves a trivial (albeit time consuming) rework of the existing materials as well since their reliance on QSGSimpleMaterial makes them problematic to live side-by-side with the RHI variants. Change-Id: Ie12b7949904434b3a831588518c8268e917ce92f Reviewed-by: Christian Strømme --- src/particles/particles.qrc | 11 + src/particles/qquickimageparticle.cpp | 735 +++++++++++++++++---- src/particles/qquickimageparticle_p.h | 29 +- src/particles/qquickparticlepainter.cpp | 2 + src/particles/qquickparticlepainter_p.h | 1 + src/particles/shaders_ng/compile.bat | 53 ++ src/particles/shaders_ng/imageparticle.frag | 55 ++ src/particles/shaders_ng/imageparticle.vert | 145 ++++ .../shaders_ng/imageparticle_colored.frag.qsb | Bin 0 -> 1990 bytes .../shaders_ng/imageparticle_colored.vert.qsb | Bin 0 -> 3677 bytes .../shaders_ng/imageparticle_deformed.frag.qsb | Bin 0 -> 2028 bytes .../shaders_ng/imageparticle_deformed.vert.qsb | Bin 0 -> 5044 bytes .../shaders_ng/imageparticle_simple.frag.qsb | Bin 0 -> 2000 bytes .../shaders_ng/imageparticle_simple.vert.qsb | Bin 0 -> 3639 bytes .../shaders_ng/imageparticle_sprite.frag.qsb | Bin 0 -> 2369 bytes .../shaders_ng/imageparticle_sprite.vert.qsb | Bin 0 -> 5964 bytes .../shaders_ng/imageparticle_tabled.frag.qsb | Bin 0 -> 2240 bytes .../shaders_ng/imageparticle_tabled.vert.qsb | Bin 0 -> 5462 bytes 18 files changed, 884 insertions(+), 147 deletions(-) create mode 100755 src/particles/shaders_ng/compile.bat create mode 100644 src/particles/shaders_ng/imageparticle.frag create mode 100644 src/particles/shaders_ng/imageparticle.vert create mode 100644 src/particles/shaders_ng/imageparticle_colored.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_colored.vert.qsb create mode 100644 src/particles/shaders_ng/imageparticle_deformed.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_deformed.vert.qsb create mode 100644 src/particles/shaders_ng/imageparticle_simple.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_simple.vert.qsb create mode 100644 src/particles/shaders_ng/imageparticle_sprite.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_sprite.vert.qsb create mode 100644 src/particles/shaders_ng/imageparticle_tabled.frag.qsb create mode 100644 src/particles/shaders_ng/imageparticle_tabled.vert.qsb (limited to 'src/particles') diff --git a/src/particles/particles.qrc b/src/particles/particles.qrc index ad44cf406e..c7102b9aa5 100644 --- a/src/particles/particles.qrc +++ b/src/particles/particles.qrc @@ -16,5 +16,16 @@ shaders/customparticletemplate_core.vert shaders/imageparticle_core.frag shaders/imageparticle_core.vert + + shaders_ng/imageparticle_simple.vert.qsb + shaders_ng/imageparticle_simple.frag.qsb + shaders_ng/imageparticle_tabled.vert.qsb + shaders_ng/imageparticle_tabled.frag.qsb + shaders_ng/imageparticle_deformed.vert.qsb + shaders_ng/imageparticle_deformed.frag.qsb + shaders_ng/imageparticle_sprite.vert.qsb + shaders_ng/imageparticle_sprite.frag.qsb + shaders_ng/imageparticle_colored.vert.qsb + shaders_ng/imageparticle_colored.frag.qsb diff --git a/src/particles/qquickimageparticle.cpp b/src/particles/qquickimageparticle.cpp index ae1ef80026..649fbb30c2 100644 --- a/src/particles/qquickimageparticle.cpp +++ b/src/particles/qquickimageparticle.cpp @@ -1,6 +1,6 @@ -/**************************************************************************** +/**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -41,7 +41,6 @@ #include #include #include -#include #include #include #include @@ -56,13 +55,15 @@ #include #include #include +#include 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: @@ -85,13 +86,10 @@ class ImageMaterialData QSizeF animSheetSize; }; -class TabledMaterialData : public ImageMaterialData {}; -class TabledMaterial : public QSGSimpleMaterialShader +class TabledMaterialShader : public QSGMaterialShader { - QSG_DECLARE_SIMPLE_SHADER(TabledMaterial, TabledMaterialData) - public: - TabledMaterial() + TabledMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -122,36 +120,47 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList attributes() const override { - return QList() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation"; - }; + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation", nullptr }; + return attr; + } void initialize() override { - QSGSimpleMaterialShader::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); program()->setUniformValue("colortable", 1); glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); 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 { + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); + + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); + glFuncs->glActiveTexture(GL_TEXTURE1); - d->colorTable->bind(); + state->colorTable->bind(); glFuncs->glActiveTexture(GL_TEXTURE0); - d->texture->bind(); + state->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); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); + program()->setUniformValueArray(m_sizetable_id, (const float*) state->sizeTable, UNIFORM_ARRAY_SIZE, 1); + program()->setUniformValueArray(m_opacitytable_id, (const float*) state->opacityTable, UNIFORM_ARRAY_SIZE, 1); } + int m_matrix_id; + int m_opacity_id; int m_entry_id; int m_timestamp_id; int m_sizetable_id; @@ -161,13 +170,91 @@ public: QOpenGLFunctions* glFuncs; }; -class DeformableMaterialData : public ImageMaterialData {}; -class DeformableMaterial : public QSGSimpleMaterialShader +class TabledMaterialRhiShader : public QSGMaterialRhiShader +{ +public: + TabledMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_tabled.frag.qsb")); + } + + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + float *p = reinterpret_cast(buf->data() + 80); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->sizeTable[i]; + p += 4; + } + p = reinterpret_cast(buf->data() + 80 + (UNIFORM_ARRAY_SIZE * 4 * 4)); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->opacityTable[i]; + p += 4; + } + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 2) { + state->colorTable->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->colorTable; + } else if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class TabledMaterial : public ImageMaterial { - QSG_DECLARE_SIMPLE_SHADER(DeformableMaterial, DeformableMaterialData) +public: + TabledMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new TabledMaterialRhiShader; + else + return new TabledMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType TabledMaterial::m_type; + +class DeformableMaterialShader : public QSGMaterialShader +{ public: - DeformableMaterial() + DeformableMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -196,27 +283,38 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList attributes() const override { - return QList() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation"; - }; + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation", nullptr }; + return attr; + } void initialize() override { - QSGSimpleMaterialShader::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); m_timestamp_id = program()->uniformLocation("timestamp"); m_entry_id = program()->uniformLocation("entry"); } - void updateState(const DeformableMaterialData* d, const DeformableMaterialData*) override { - d->texture->bind(); + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); + + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); + + state->texture->bind(); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); } + int m_matrix_id; + int m_opacity_id; int m_entry_id; int m_timestamp_id; QByteArray m_vertex_code; @@ -224,13 +322,77 @@ public: QOpenGLFunctions* glFuncs; }; -class SpriteMaterialData : public ImageMaterialData {}; -class SpriteMaterial : public QSGSimpleMaterialShader +class DeformableMaterialRhiShader : public QSGMaterialRhiShader { - QSG_DECLARE_SIMPLE_SHADER(SpriteMaterial, SpriteMaterialData) +public: + DeformableMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_deformed.frag.qsb")); + } + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class DeformableMaterial : public ImageMaterial +{ public: - SpriteMaterial() + DeformableMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new DeformableMaterialRhiShader; + else + return new DeformableMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType DeformableMaterial::m_type; + +class SpriteMaterialShader : public QSGMaterialShader +{ +public: + SpriteMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -263,17 +425,20 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } - QList attributes() const override { - return QList() << "vPosTex" << "vData" << "vVec" - << "vColor" << "vDeformVec" << "vRotation" << "vAnimData" << "vAnimPos"; + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPosTex", "vData", "vVec", "vColor", "vDeformVec", "vRotation", + "vAnimData", "vAnimPos", nullptr }; + return attr; } void initialize() override { - QSGSimpleMaterialShader::initialize(); program()->bind(); program()->setUniformValue("_qt_texture", 0); program()->setUniformValue("colortable", 1); glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); //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"); @@ -281,20 +446,29 @@ public: m_opacitytable_id = program()->uniformLocation("opacitytable"); } - void updateState(const SpriteMaterialData* d, const SpriteMaterialData*) override { + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); + + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); + glFuncs->glActiveTexture(GL_TEXTURE1); - d->colorTable->bind(); + state->colorTable->bind(); // make sure we end by setting GL_TEXTURE0 as active texture glFuncs->glActiveTexture(GL_TEXTURE0); - d->texture->bind(); + state->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); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); + program()->setUniformValueArray(m_sizetable_id, (const float*) state->sizeTable, 64, 1); + program()->setUniformValueArray(m_opacitytable_id, (const float*) state->opacityTable, UNIFORM_ARRAY_SIZE, 1); } + int m_matrix_id; + int m_opacity_id; int m_timestamp_id; int m_entry_id; int m_sizetable_id; @@ -304,13 +478,91 @@ public: QOpenGLFunctions* glFuncs; }; -class ColoredMaterialData : public ImageMaterialData {}; -class ColoredMaterial : public QSGSimpleMaterialShader +class SpriteMaterialRhiShader : public QSGMaterialRhiShader { - QSG_DECLARE_SIMPLE_SHADER(ColoredMaterial, ColoredMaterialData) +public: + SpriteMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_sprite.frag.qsb")); + } + + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + float *p = reinterpret_cast(buf->data() + 80); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->sizeTable[i]; + p += 4; + } + p = reinterpret_cast(buf->data() + 80 + (UNIFORM_ARRAY_SIZE * 4 * 4)); + for (int i = 0; i < UNIFORM_ARRAY_SIZE; ++i) { + *p = state->opacityTable[i]; + p += 4; + } + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 2) { + state->colorTable->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->colorTable; + } else if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class SpriteMaterial : public ImageMaterial +{ public: - ColoredMaterial() + SpriteMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new SpriteMaterialRhiShader; + else + return new SpriteMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType SpriteMaterial::m_type; + +class ColoredMaterialShader : public QSGMaterialShader +{ +public: + ColoredMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -337,8 +589,23 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPos", "vData", "vVec", "vColor", nullptr }; + return attr; + } + + void initialize() override { + program()->bind(); + program()->setUniformValue("_qt_texture", 0); + glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + m_timestamp_id = program()->uniformLocation("timestamp"); + m_entry_id = program()->uniformLocation("entry"); + } + void activate() override { - QSGSimpleMaterialShader::activate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glEnable(GL_POINT_SPRITE); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); @@ -346,33 +613,28 @@ public: } void deactivate() override { - QSGSimpleMaterialShader::deactivate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glDisable(GL_POINT_SPRITE); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif } - QList attributes() const override { - return QList() << "vPos" << "vData" << "vVec" << "vColor"; - } + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); - void initialize() override { - QSGSimpleMaterialShader::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - glFuncs = QOpenGLContext::currentContext()->functions(); - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); - } + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); - void updateState(const ColoredMaterialData* d, const ColoredMaterialData*) override { - d->texture->bind(); + state->texture->bind(); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); } + int m_matrix_id; + int m_opacity_id; int m_timestamp_id; int m_entry_id; QByteArray m_vertex_code; @@ -380,13 +642,77 @@ public: QOpenGLFunctions* glFuncs; }; -class SimpleMaterialData : public ImageMaterialData {}; -class SimpleMaterial : public QSGSimpleMaterialShader +class ColoredMaterialRhiShader : public QSGMaterialRhiShader +{ +public: + ColoredMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_colored.frag.qsb")); + } + + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class ColoredMaterial : public ImageMaterial { - QSG_DECLARE_SIMPLE_SHADER(SimpleMaterial, SimpleMaterialData) +public: + ColoredMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new ColoredMaterialRhiShader; + else + return new ColoredMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType ColoredMaterial::m_type; + +class SimpleMaterialShader : public QSGMaterialShader +{ public: - SimpleMaterial() + SimpleMaterialShader() { QSGShaderSourceBuilder builder; const bool isES = QOpenGLContext::currentContext()->isOpenGLES(); @@ -411,8 +737,23 @@ public: const char *vertexShader() const override { return m_vertex_code.constData(); } const char *fragmentShader() const override { return m_fragment_code.constData(); } + char const *const *attributeNames() const override + { + static const char *const attr[] = { "vPos", "vData", "vVec", nullptr }; + return attr; + } + + void initialize() override { + program()->bind(); + program()->setUniformValue("_qt_texture", 0); + glFuncs = QOpenGLContext::currentContext()->functions(); + m_matrix_id = program()->uniformLocation("qt_Matrix"); + m_opacity_id = program()->uniformLocation("qt_Opacity"); + m_timestamp_id = program()->uniformLocation("timestamp"); + m_entry_id = program()->uniformLocation("entry"); + } + void activate() override { - QSGSimpleMaterialShader::activate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glEnable(GL_POINT_SPRITE); glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); @@ -420,33 +761,28 @@ public: } void deactivate() override { - QSGSimpleMaterialShader::deactivate(); #if !defined(QT_OPENGL_ES_2) && !defined(Q_OS_WIN) glDisable(GL_POINT_SPRITE); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif } - QList attributes() const override { - return QList() << "vPos" << "vData" << "vVec"; - } + void updateState(const RenderState &renderState, QSGMaterial *mat, QSGMaterial *) override { + ImageMaterialData *state = static_cast(mat)->state(); - void initialize() override { - QSGSimpleMaterialShader::initialize(); - program()->bind(); - program()->setUniformValue("_qt_texture", 0); - glFuncs = QOpenGLContext::currentContext()->functions(); - m_timestamp_id = program()->uniformLocation("timestamp"); - m_entry_id = program()->uniformLocation("entry"); - } + if (renderState.isMatrixDirty()) + program()->setUniformValue(m_matrix_id, renderState.combinedMatrix()); + if (renderState.isOpacityDirty() && m_opacity_id >= 0) + program()->setUniformValue(m_opacity_id, renderState.opacity()); - void updateState(const SimpleMaterialData* d, const SimpleMaterialData*) override { - d->texture->bind(); + state->texture->bind(); - program()->setUniformValue(m_timestamp_id, (float) d->timestamp); - program()->setUniformValue(m_entry_id, (float) d->entry); + program()->setUniformValue(m_timestamp_id, (float) state->timestamp); + program()->setUniformValue(m_entry_id, (float) state->entry); } + int m_matrix_id; + int m_opacity_id; int m_timestamp_id; int m_entry_id; QByteArray m_vertex_code; @@ -454,6 +790,73 @@ public: QOpenGLFunctions* glFuncs; }; +class SimpleMaterialRhiShader : public QSGMaterialRhiShader +{ +public: + SimpleMaterialRhiShader() + { + setShaderFileName(VertexStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simple.vert.qsb")); + setShaderFileName(FragmentStage, QStringLiteral(":/particles/shaders_ng/imageparticle_simple.frag.qsb")); + } + + bool updateUniformData(const RenderState &renderState, QSGMaterial *newMaterial, QSGMaterial *) override + { + QByteArray *buf = renderState.uniformData(); + Q_ASSERT(buf->size() >= 80 + 2 * (UNIFORM_ARRAY_SIZE * 4 * 4)); + + if (renderState.isMatrixDirty()) { + const QMatrix4x4 m = renderState.combinedMatrix(); + memcpy(buf->data(), m.constData(), 64); + } + + if (renderState.isOpacityDirty()) { + const float opacity = renderState.opacity(); + memcpy(buf->data() + 64, &opacity, 4); + } + + ImageMaterialData *state = static_cast(newMaterial)->state(); + + float entry = float(state->entry); + memcpy(buf->data() + 68, &entry, 4); + + float timestamp = float(state->timestamp); + memcpy(buf->data() + 72, ×tamp, 4); + + return true; + } + + void updateSampledImage(const RenderState &renderState, int binding, QSGTexture **texture, + QSGMaterial *newMaterial, QSGMaterial *) override + { + ImageMaterialData *state = static_cast(newMaterial)->state(); + if (binding == 1) { + state->texture->updateRhiTexture(renderState.rhi(), renderState.resourceUpdateBatch()); + *texture = state->texture; + } + } +}; + +class SimpleMaterial : public ImageMaterial +{ +public: + SimpleMaterial() { setFlag(SupportsRhiShader, true); } + QSGMaterialShader *createShader() const override { + if (flags().testFlag(RhiShaderWanted)) + return new SimpleMaterialRhiShader; + else + return new SimpleMaterialShader; + } + QSGMaterialType *type() const override { return &m_type; } + + ImageMaterialData *state() override { return &m_state; } + +private: + static QSGMaterialType m_type; + ImageMaterialData m_state; +}; + +QSGMaterialType SimpleMaterial::m_type; + void fillUniformArrayFromImage(float* array, const QImage& img, int size) { if (img.isNull()){ @@ -726,6 +1129,8 @@ QQuickImageParticle::QQuickImageParticle(QQuickItem* parent) , m_debugMode(false) , m_entryEffect(Fade) , m_startedImageLoading(0) + , m_rhi(nullptr) + , m_apiChecked(false) { setFlag(ItemHasContents); } @@ -1000,7 +1405,7 @@ void QQuickImageParticle::setEntryEffect(EntryEffect arg) if (m_entryEffect != arg) { m_entryEffect = arg; if (m_material) - getState(m_material)->entry = (qreal) m_entryEffect; + getState(m_material)->entry = (qreal) m_entryEffect; emit entryEffectChanged(arg); } } @@ -1224,7 +1629,7 @@ void QQuickImageParticle::buildParticleNodes(QSGNode** passThrough) void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) { - if (!QOpenGLContext::currentContext()) + if (!m_rhi && !QOpenGLContext::currentContext()) return; if (m_count * 4 > 0xffff) { @@ -1271,28 +1676,38 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) } } } + + if (!m_rhi) { // the RHI may be backed by GL but these checks should be obsolete in any case #ifdef Q_OS_WIN - if (perfLevel < Deformable) //QTBUG-24540 , point sprite 'extension' isn't working on windows. - perfLevel = Deformable; + 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; - } + // macOS 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; + // 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 + } else { + // 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 < Deformable && !m_rhi->isFeatureSupported(QRhi::VertexShaderPointSize)) + perfLevel = Deformable; + } + if (perfLevel >= Colored && !m_color.isValid()) m_color = QColor(Qt::white);//Hidden default, but different from unset @@ -1308,6 +1723,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 +1734,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(m_material)->texture = QSGPlainTexture::fromImage(image); - getState(m_material)->animSheetSize = QSizeF(image.size() / image.devicePixelRatioF()); + state->texture = QSGPlainTexture::fromImage(image); + state->animSheetSize = QSizeF(image.size() / image.devicePixelRatioF()); 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 +1773,29 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) colortable = QImage(1,1,QImage::Format_ARGB32_Premultiplied); colortable.fill(Qt::white); } - getState(m_material)->colorTable = QSGPlainTexture::fromImage(colortable); - fillUniformArrayFromImage(getState(m_material)->sizeTable, sizetable, UNIFORM_ARRAY_SIZE); - fillUniformArrayFromImage(getState(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(); default://Also Simple + { if (!m_material) - m_material = SimpleMaterial::createMaterial(); + m_material = new SimpleMaterial; + ImageMaterialData *state = getState(m_material); if (!imageLoaded) { if (!m_image || !m_image->pix.isReady()) { if (m_image) @@ -1376,14 +1803,15 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) delete m_material; return; } - //getState(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(m_material)->texture = QSGPlainTexture::fromImage(m_image->pix.image()); + state->texture = QSGPlainTexture::fromImage(m_image->pix.image()); } - getState(m_material)->texture->setFiltering(QSGTexture::Linear); - getState(m_material)->entry = (qreal) m_entryEffect; + state->texture->setFiltering(QSGTexture::Linear); + state->entry = (qreal) m_entryEffect; m_material->setFlag(QSGMaterial::Blending | QSGMaterial::RequiresFullMatrix); } + } m_nodes.clear(); for (auto groupId : groupIds()) { @@ -1416,14 +1844,23 @@ void QQuickImageParticle::finishBuildParticleNodes(QSGNode** node) 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 " <setDrawingMode(QSGGeometry::DrawPoints); + if (m_debugMode) { + if (m_rhi) { + qDebug("Using point sprites"); + } else { +#if QT_CONFIG(opengl) + GLfloat pointSizeRange[2]; + QOpenGLContext::currentContext()->functions()->glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, pointSizeRange); + qDebug() << "Using point sprites, GL_ALIASED_POINT_SIZE_RANGE " <setDrawingMode(GL_TRIANGLES); + } 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 @@ -1464,16 +1901,34 @@ 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 isDirectOpenGL = api == QSGRendererInterface::OpenGL; + const bool isRhi = QSGRendererInterface::isApiRhiBased(api); + + if (!node && !isDirectOpenGL && !isRhi) + return nullptr; + + if (isRhi) + m_rhi = static_cast(rif->getResource(m_window, QSGRendererInterface::RhiResource)); + else + m_rhi = nullptr; + + if (isRhi && !m_rhi) { + qWarning("Failed to query QRhi, particles disabled"); + return nullptr; + } + } if (m_pleaseReset){ if (node) @@ -1541,7 +1996,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) case Colored: case Simple: default: //Also Simple - getState(m_material)->timestamp = time; + getState(m_material)->timestamp = time; break; } foreach (QSGGeometryNode* node, m_nodes) @@ -1550,6 +2005,7 @@ void QQuickImageParticle::prepareNextFrame(QSGNode **node) 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)) { @@ -1587,7 +2043,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(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(); @@ -1686,6 +2142,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 +2151,8 @@ void QQuickImageParticle::initialize(int gIdx, int pIdx) writeTo->animIdx = 0; writeTo->animT = 0; writeTo->animX = writeTo->animY = 0; - writeTo->animWidth = getState(m_material)->animSheetSize.width(); - writeTo->animHeight = getState(m_material)->animSheetSize.height(); + writeTo->animWidth = state->animSheetSize.width(); + writeTo->animHeight = state->animSheetSize.height(); } Q_FALLTHROUGH(); case Tabled: diff --git a/src/particles/qquickimageparticle_p.h b/src/particles/qquickimageparticle_p.h index 95323c25a6..059cf67019 100644 --- a/src/particles/qquickimageparticle_p.h +++ b/src/particles/qquickimageparticle_p.h @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2016 The Qt Company Ltd. +** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the QtQuick module of the Qt Toolkit. @@ -37,8 +37,8 @@ ** ****************************************************************************/ -#ifndef ULTRAPARTICLE_H -#define ULTRAPARTICLE_H +#ifndef QQUICKIMAGEPARTICLE_P_H +#define QQUICKIMAGEPARTICLE_P_H // // W A R N I N G @@ -50,21 +50,25 @@ // // We mean it. // + #include "qquickparticlepainter_p.h" #include "qquickdirection_p.h" #include #include -#include #include +#include QT_BEGIN_NAMESPACE class ImageMaterialData; class QSGGeometryNode; +class QSGMaterial; class QQuickSprite; class QQuickStochasticEngine; +class QRhi; + struct SimpleVertex { float x; float y; @@ -153,6 +157,12 @@ struct Vertices { Vertex v4; }; +class ImageMaterial : public QSGMaterial +{ +public: + virtual ImageMaterialData *state() = 0; +}; + class QQuickImageParticle : public QQuickParticlePainter { Q_OBJECT @@ -439,14 +449,17 @@ private: } } - template - static MaterialData* getState(QSGMaterial* m) { - return static_cast *>(m)->state(); + ImageMaterialData *getState(QSGMaterial *m) { + return static_cast(m)->state(); } + EntryEffect m_entryEffect; Status m_status; int m_startedImageLoading; + QRhi *m_rhi; + bool m_apiChecked; }; QT_END_NAMESPACE -#endif // ULTRAPARTICLE_H + +#endif // QQUICKIMAGEPARTICLE_P_H diff --git a/src/particles/qquickparticlepainter.cpp b/src/particles/qquickparticlepainter.cpp index e762b3ae1d..78e11fafcf 100644 --- a/src/particles/qquickparticlepainter.cpp +++ b/src/particles/qquickparticlepainter.cpp @@ -70,6 +70,7 @@ QQuickParticlePainter::QQuickParticlePainter(QQuickItem *parent) , m_count(0) , m_pleaseReset(true) , m_window(nullptr) + , m_windowChanged(false) , m_groupIdsNeedRecalculation(false) { } @@ -80,6 +81,7 @@ void QQuickParticlePainter::itemChange(ItemChange change, const ItemChangeData & if (m_window) disconnect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(sceneGraphInvalidated())); m_window = data.window; + m_windowChanged = true; if (m_window) connect(m_window, SIGNAL(sceneGraphInvalidated()), this, SLOT(sceneGraphInvalidated()), Qt::DirectConnection); } diff --git a/src/particles/qquickparticlepainter_p.h b/src/particles/qquickparticlepainter_p.h index ac14a18103..16fc6b6f45 100644 --- a/src/particles/qquickparticlepainter_p.h +++ b/src/particles/qquickparticlepainter_p.h @@ -141,6 +141,7 @@ protected: QPointF m_systemOffset; QQuickWindow *m_window; + bool m_windowChanged; private: // methods void recalculateGroupIds() const; diff --git a/src/particles/shaders_ng/compile.bat b/src/particles/shaders_ng/compile.bat new file mode 100755 index 0000000000..2376d5bf6d --- /dev/null +++ b/src/particles/shaders_ng/compile.bat @@ -0,0 +1,53 @@ +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: +:: +:: Copyright (C) 2019 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$ +:: +::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: + +qsb -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_simple.vert.qsb imageparticle.vert +qsb --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_simple.frag.qsb imageparticle.frag + +qsb -DTABLE -DDEFORM -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_tabled.vert.qsb imageparticle.vert +qsb -DTABLE -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_tabled.frag.qsb imageparticle.frag + +qsb -DDEFORM -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_deformed.vert.qsb imageparticle.vert +qsb -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_deformed.frag.qsb imageparticle.frag + +qsb -DSPRITE -DTABLE -DDEFORM -DCOLOR -b --zorder-loc 8 --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_sprite.vert.qsb imageparticle.vert +qsb -DSPRITE -DTABLE -DDEFORM -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_sprite.frag.qsb imageparticle.frag + +qsb -DCOLOR -b --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_colored.vert.qsb imageparticle.vert +qsb -DCOLOR --glsl "150,120,100 es" --hlsl 50 --msl 12 -o imageparticle_colored.frag.qsb imageparticle.frag diff --git a/src/particles/shaders_ng/imageparticle.frag b/src/particles/shaders_ng/imageparticle.frag new file mode 100644 index 0000000000..cefb7d2d75 --- /dev/null +++ b/src/particles/shaders_ng/imageparticle.frag @@ -0,0 +1,55 @@ +#version 440 + +#if defined(TABLE) +layout(location = 0) in vec2 tt; +#endif + +#if defined(SPRITE) +layout(location = 1) in vec4 fTexS; +#elif defined(DEFORM) +layout(location = 1) in vec2 fTex; +#endif + +#if defined(COLOR) +layout(location = 2) in vec4 fColor; +#else +layout(location = 2) in float fFade; +#endif + +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; + float entry; + float timestamp; + float sizetable[64]; + float opacitytable[64]; +} ubuf; + +layout(binding = 1) uniform sampler2D _qt_texture; + +#if defined(TABLE) || defined(SPRITE) +layout(binding = 2) uniform sampler2D colortable; +#endif + +void main() +{ +#if defined(SPRITE) + fragColor = mix(texture(_qt_texture, fTexS.xy), texture(_qt_texture, fTexS.zw), tt.y) + * fColor + * texture(colortable, tt) + * ubuf.opacity; +#elif defined(TABLE) + fragColor = texture(_qt_texture, fTex) + * fColor + * texture(colortable, tt) + * ubuf.opacity; +#elif defined(DEFORM) + fragColor = texture(_qt_texture, fTex) * fColor * ubuf.opacity; +#elif defined(COLOR) + fragColor = texture(_qt_texture, gl_PointCoord) * fColor * ubuf.opacity; +#else + fragColor = texture(_qt_texture, gl_PointCoord) * fFade * ubuf.opacity; +#endif +} diff --git a/src/particles/shaders_ng/imageparticle.vert b/src/particles/shaders_ng/imageparticle.vert new file mode 100644 index 0000000000..870139452b --- /dev/null +++ b/src/particles/shaders_ng/imageparticle.vert @@ -0,0 +1,145 @@ +#version 440 + +layout(location = 1) in vec4 vData; // x = time, y = lifeSpan, z = size, w = endSize +layout(location = 2) in vec4 vVec; // x,y = constant velocity, z,w = acceleration + +#if defined(DEFORM) +layout(location = 0) in vec4 vPosTex; +#else +layout(location = 0) in vec2 vPos; +#endif + +#if defined(COLOR) +layout(location = 3) in vec4 vColor; +#endif + +#if defined(DEFORM) +layout(location = 4) in vec4 vDeformVec; // x,y x unit vector; z,w = y unit vector +layout(location = 5) in vec3 vRotation; // x = radians of rotation, y = rotation velocity, z = bool autoRotate +#endif + +#if defined(SPRITE) +layout(location = 6) in vec3 vAnimData; // w,h(premultiplied of anim), interpolation progress +layout(location = 7) in vec4 vAnimPos; // x,y, x,y (two frames for interpolation) +#endif + +#if defined(TABLE) +layout(location = 0) out vec2 tt; //y is progress if Sprite mode +#endif + +#if defined(SPRITE) +layout(location = 1) out vec4 fTexS; +#elif defined(DEFORM) +layout(location = 1) out vec2 fTex; +#endif + +#if defined(COLOR) +layout(location = 2) out vec4 fColor; +#else +layout(location = 2) out float fFade; +#endif + +layout(std140, binding = 0) uniform buf { + mat4 matrix; + float opacity; + float entry; + float timestamp; + float sizetable[64]; + float opacitytable[64]; +} ubuf; + +out gl_PerVertex { vec4 gl_Position; float gl_PointSize; }; + +void main() +{ + float t = (ubuf.timestamp - vData.x) / vData.y; + if (t < 0. || t > 1.) { +#if defined(DEFORM) + gl_Position = ubuf.matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.); +#else + gl_PointSize = 0.; +#endif + } else { +#if defined(SPRITE) + tt.y = vAnimData.z; + + // Calculate frame location in texture + fTexS.xy = vAnimPos.xy + vPosTex.zw * vAnimData.xy; + + // Next frame is also passed, for interpolation + fTexS.zw = vAnimPos.zw + vPosTex.zw * vAnimData.xy; + +#elif defined(DEFORM) + fTex = vPosTex.zw; +#endif + float currentSize = mix(vData.z, vData.w, t * t); + float fade = 1.; + float fadeIn = min(t * 10., 1.); + float fadeOut = 1. - clamp((t - 0.75) * 4.,0., 1.); + +#if defined(TABLE) + currentSize = currentSize * ubuf.sizetable[int(floor(t*64.))]; + fade = fade * ubuf.opacitytable[int(floor(t*64.))]; +#endif + + if (ubuf.entry == 1.) + fade = fade * fadeIn * fadeOut; + else if (ubuf.entry == 2.) + currentSize = currentSize * fadeIn * fadeOut; + + if (currentSize <= 0.) { +#if defined(DEFORM) + gl_Position = ubuf.matrix * vec4(vPosTex.x, vPosTex.y, 0., 1.); +#else + gl_PointSize = 0.; +#endif + } else { + if (currentSize < 3.) // Sizes too small look jittery as they move + currentSize = 3.; + + vec2 pos; +#if defined(DEFORM) + float rotation = vRotation.x + vRotation.y * t * vData.y; + if (vRotation.z == 1.0) { + vec2 curVel = vVec.zw * t * vData.y + vVec.xy; + if (length(curVel) > 0.) + rotation += atan(curVel.y, curVel.x); + } + vec2 trigCalcs = vec2(cos(rotation), sin(rotation)); + vec4 deform = vDeformVec * currentSize * (vPosTex.zzww - 0.5); + vec4 rotatedDeform = deform.xxzz * trigCalcs.xyxy; + rotatedDeform = rotatedDeform + (deform.yyww * trigCalcs.yxyx * vec4(-1.,1.,-1.,1.)); + /* The readable version: + vec2 xDeform = vDeformVec.xy * currentSize * (vTex.x-0.5); + vec2 yDeform = vDeformVec.zw * currentSize * (vTex.y-0.5); + vec2 xRotatedDeform; + xRotatedDeform.x = trigCalcs.x*xDeform.x - trigCalcs.y*xDeform.y; + xRotatedDeform.y = trigCalcs.y*xDeform.x + trigCalcs.x*xDeform.y; + vec2 yRotatedDeform; + yRotatedDeform.x = trigCalcs.x*yDeform.x - trigCalcs.y*yDeform.y; + yRotatedDeform.y = trigCalcs.y*yDeform.x + trigCalcs.x*yDeform.y; + */ + pos = vPosTex.xy + + rotatedDeform.xy + + rotatedDeform.zw + + vVec.xy * t * vData.y // apply velocity + + 0.5 * vVec.zw * pow(t * vData.y, 2.); // apply acceleration +#else + pos = vPos + + vVec.xy * t * vData.y // apply velocity vector.. + + 0.5 * vVec.zw * pow(t * vData.y, 2.); + gl_PointSize = currentSize; +#endif + gl_Position = ubuf.matrix * vec4(pos.x, pos.y, 0, 1); + +#if defined(COLOR) + fColor = vColor * fade; +#else + fFade = fade; +#endif +#if defined(TABLE) + tt.x = t; +#endif + } + } +} diff --git a/src/particles/shaders_ng/imageparticle_colored.frag.qsb b/src/particles/shaders_ng/imageparticle_colored.frag.qsb new file mode 100644 index 0000000000..7ae640d224 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_colored.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_colored.vert.qsb b/src/particles/shaders_ng/imageparticle_colored.vert.qsb new file mode 100644 index 0000000000..0e2938b72c Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_colored.vert.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_deformed.frag.qsb b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb new file mode 100644 index 0000000000..fa9d9d35bb Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_deformed.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_deformed.vert.qsb b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb new file mode 100644 index 0000000000..65092d5b26 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_deformed.vert.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_simple.frag.qsb b/src/particles/shaders_ng/imageparticle_simple.frag.qsb new file mode 100644 index 0000000000..a5874cba24 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_simple.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_simple.vert.qsb b/src/particles/shaders_ng/imageparticle_simple.vert.qsb new file mode 100644 index 0000000000..da815d7e19 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_simple.vert.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_sprite.frag.qsb b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb new file mode 100644 index 0000000000..778550344b Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_sprite.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_sprite.vert.qsb b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb new file mode 100644 index 0000000000..45b21ace8a Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_sprite.vert.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_tabled.frag.qsb b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb new file mode 100644 index 0000000000..c5dcc2c68f Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_tabled.frag.qsb differ diff --git a/src/particles/shaders_ng/imageparticle_tabled.vert.qsb b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb new file mode 100644 index 0000000000..ea42607570 Binary files /dev/null and b/src/particles/shaders_ng/imageparticle_tabled.vert.qsb differ -- cgit v1.2.3