aboutsummaryrefslogtreecommitdiffstats
path: root/src/quick/scenegraph/qsgcurvefillnode_p.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/quick/scenegraph/qsgcurvefillnode_p.cpp')
-rw-r--r--src/quick/scenegraph/qsgcurvefillnode_p.cpp309
1 files changed, 309 insertions, 0 deletions
diff --git a/src/quick/scenegraph/qsgcurvefillnode_p.cpp b/src/quick/scenegraph/qsgcurvefillnode_p.cpp
new file mode 100644
index 0000000000..387f4b3ce6
--- /dev/null
+++ b/src/quick/scenegraph/qsgcurvefillnode_p.cpp
@@ -0,0 +1,309 @@
+// Copyright (C) 2023 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
+
+#include "qsgcurvefillnode_p_p.h"
+#include "qsgcurvefillnode_p.h"
+#include "util/qsggradientcache_p.h"
+
+#include <private/qsgtexture_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+ class QSGCurveFillMaterialShader : public QSGMaterialShader
+ {
+ public:
+ QSGCurveFillMaterialShader(QGradient::Type gradientType,
+ bool useDerivatives,
+ int viewCount);
+
+ bool updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect) override;
+ void updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override;
+ };
+
+ QSGCurveFillMaterialShader::QSGCurveFillMaterialShader(QGradient::Type gradientType,
+ bool useDerivatives,
+ int viewCount)
+ {
+ QString baseName = QStringLiteral(":/qt-project.org/scenegraph/shaders_ng/shapecurve");
+
+ if (gradientType == QGradient::LinearGradient) {
+ baseName += QStringLiteral("_lg");
+ } else if (gradientType == QGradient::RadialGradient) {
+ baseName += QStringLiteral("_rg");
+ } else if (gradientType == QGradient::ConicalGradient) {
+ baseName += QStringLiteral("_cg");
+ }
+
+ if (useDerivatives)
+ baseName += QStringLiteral("_derivatives");
+
+ setShaderFileName(VertexStage, baseName + QStringLiteral(".vert.qsb"), viewCount);
+ setShaderFileName(FragmentStage, baseName + QStringLiteral(".frag.qsb"), viewCount);
+ }
+
+ void QSGCurveFillMaterialShader::updateSampledImage(RenderState &state, int binding, QSGTexture **texture,
+ QSGMaterial *newMaterial, QSGMaterial *oldMaterial)
+ {
+ Q_UNUSED(oldMaterial);
+ const QSGCurveFillMaterial *m = static_cast<QSGCurveFillMaterial *>(newMaterial);
+ const QSGCurveFillNode *node = m->node();
+ if (binding != 1 || node->gradientType() == QGradient::NoGradient)
+ return;
+
+ const QSGGradientCacheKey cacheKey(node->fillGradient()->stops,
+ node->fillGradient()->spread);
+ QSGTexture *t = QSGGradientCache::cacheForRhi(state.rhi())->get(cacheKey);
+ t->commitTextureOperations(state.rhi(), state.resourceUpdateBatch());
+ *texture = t;
+ }
+
+ bool QSGCurveFillMaterialShader::updateUniformData(RenderState &state, QSGMaterial *newEffect, QSGMaterial *oldEffect)
+ {
+ bool changed = false;
+ QByteArray *buf = state.uniformData();
+ Q_ASSERT(buf->size() >= 80);
+ const int matrixCount = qMin(state.projectionMatrixCount(), newEffect->viewCount());
+
+ int offset = 0;
+ float matrixScale = 0.0f;
+ if (state.isMatrixDirty()) {
+ for (int viewIndex = 0; viewIndex < matrixCount; ++viewIndex) {
+ const QMatrix4x4 m = state.combinedMatrix(viewIndex);
+ memcpy(buf->data() + offset + viewIndex * 64, m.constData(), 64);
+ }
+
+ matrixScale = qSqrt(qAbs(state.determinant()));
+ memcpy(buf->data() + offset + matrixCount * 64, &matrixScale, 4);
+
+ changed = true;
+ }
+ offset += matrixCount * 64 + 4;
+
+ if (state.isOpacityDirty()) {
+ const float opacity = state.opacity();
+ memcpy(buf->data() + offset, &opacity, 4);
+ changed = true;
+ }
+ offset += 4;
+
+ QSGCurveFillMaterial *newMaterial = static_cast<QSGCurveFillMaterial *>(newEffect);
+ QSGCurveFillMaterial *oldMaterial = static_cast<QSGCurveFillMaterial *>(oldEffect);
+
+ QSGCurveFillNode *newNode = newMaterial != nullptr ? newMaterial->node() : nullptr;
+ QSGCurveFillNode *oldNode = oldMaterial != nullptr ? oldMaterial->node() : nullptr;
+
+ if (newNode == nullptr)
+ return changed;
+
+ if (oldNode == nullptr || oldNode->debug() != newNode->debug()) {
+ float debug = newNode->debug();
+ memcpy(buf->data() + offset, &debug, 4);
+ changed = true;
+ }
+ offset += 8;
+
+ if (newNode->gradientType() == QGradient::NoGradient) {
+ Q_ASSERT(buf->size() >= offset + 16);
+
+ QVector4D newColor = QVector4D(newNode->color().redF(),
+ newNode->color().greenF(),
+ newNode->color().blueF(),
+ newNode->color().alphaF());
+ QVector4D oldColor = oldNode != nullptr
+ ? QVector4D(oldNode->color().redF(),
+ oldNode->color().greenF(),
+ oldNode->color().blueF(),
+ oldNode->color().alphaF())
+ : QVector4D{};
+
+ if (oldNode == nullptr || oldColor != newColor) {
+ memcpy(buf->data() + offset, &newColor, 16);
+ changed = true;
+ }
+
+ offset += 16;
+ } else if (newNode->gradientType() == QGradient::LinearGradient) {
+ Q_ASSERT(buf->size() >= offset + 8 + 8);
+
+ QVector2D newGradientStart = QVector2D(newNode->fillGradient()->a);
+ QVector2D oldGradientStart = oldNode != nullptr
+ ? QVector2D(oldNode->fillGradient()->a)
+ : QVector2D{};
+
+ if (newGradientStart != oldGradientStart || oldEffect == nullptr) {
+ memcpy(buf->data() + offset, &newGradientStart, 8);
+ changed = true;
+ }
+ offset += 8;
+
+ QVector2D newGradientEnd = QVector2D(newNode->fillGradient()->b);
+ QVector2D oldGradientEnd = oldNode!= nullptr
+ ? QVector2D(oldNode->fillGradient()->b)
+ : QVector2D{};
+
+ if (newGradientEnd != oldGradientEnd || oldEffect == nullptr) {
+ memcpy(buf->data() + offset, &newGradientEnd, 8);
+ changed = true;
+ }
+
+ offset += 8;
+ } else if (newNode->gradientType() == QGradient::RadialGradient) {
+ Q_ASSERT(buf->size() >= offset + 8 + 8 + 4 + 4);
+
+ QVector2D newFocalPoint = QVector2D(newNode->fillGradient()->b);
+ QVector2D oldFocalPoint = oldNode != nullptr
+ ? QVector2D(oldNode->fillGradient()->b)
+ : QVector2D{};
+ if (oldNode == nullptr || newFocalPoint != oldFocalPoint) {
+ memcpy(buf->data() + offset, &newFocalPoint, 8);
+ changed = true;
+ }
+ offset += 8;
+
+ QVector2D newCenterPoint = QVector2D(newNode->fillGradient()->a);
+ QVector2D oldCenterPoint = oldNode != nullptr
+ ? QVector2D(oldNode->fillGradient()->a)
+ : QVector2D{};
+
+ QVector2D newCenterToFocal = newCenterPoint - newFocalPoint;
+ QVector2D oldCenterToFocal = oldCenterPoint - oldFocalPoint;
+ if (oldNode == nullptr || newCenterToFocal != oldCenterToFocal) {
+ memcpy(buf->data() + offset, &newCenterToFocal, 8);
+ changed = true;
+ }
+ offset += 8;
+
+ float newCenterRadius = newNode->fillGradient()->v0;
+ float oldCenterRadius = oldNode != nullptr
+ ? oldNode->fillGradient()->v0
+ : 0.0f;
+ if (oldNode == nullptr || !qFuzzyCompare(newCenterRadius, oldCenterRadius)) {
+ memcpy(buf->data() + offset, &newCenterRadius, 4);
+ changed = true;
+ }
+ offset += 4;
+
+ float newFocalRadius = newNode->fillGradient()->v1;
+ float oldFocalRadius = oldNode != nullptr
+ ? oldNode->fillGradient()->v1
+ : 0.0f;
+ if (oldNode == nullptr || !qFuzzyCompare(newFocalRadius, oldFocalRadius)) {
+ memcpy(buf->data() + offset, &newFocalRadius, 4);
+ changed = true;
+ }
+ offset += 4;
+
+ } else if (newNode->gradientType() == QGradient::ConicalGradient) {
+ Q_ASSERT(buf->size() >= offset + 8 + 4);
+
+ QVector2D newFocalPoint = QVector2D(newNode->fillGradient()->a);
+ QVector2D oldFocalPoint = oldNode != nullptr
+ ? QVector2D(oldNode->fillGradient()->a)
+ : QVector2D{};
+ if (oldNode == nullptr || newFocalPoint != oldFocalPoint) {
+ memcpy(buf->data() + offset, &newFocalPoint, 8);
+ changed = true;
+ }
+ offset += 8;
+
+ float newAngle = newNode->fillGradient()->v0;
+ float oldAngle = oldNode != nullptr
+ ? oldNode->fillGradient()->v0
+ : 0.0f;
+ if (oldNode == nullptr || !qFuzzyCompare(newAngle, oldAngle)) {
+ newAngle = -qDegreesToRadians(newAngle);
+ memcpy(buf->data() + offset, &newAngle, 4);
+ changed = true;
+ }
+ offset += 4;
+ }
+
+ return changed;
+ }
+
+}
+
+QSGCurveFillMaterial::QSGCurveFillMaterial(QSGCurveFillNode *node)
+ : m_node(node)
+{
+ setFlag(Blending, true);
+ setFlag(RequiresDeterminant, true);
+}
+
+int QSGCurveFillMaterial::compare(const QSGMaterial *other) const
+{
+ if (other->type() != type())
+ return (type() - other->type());
+
+ const QSGCurveFillMaterial *otherMaterial =
+ static_cast<const QSGCurveFillMaterial *>(other);
+
+ QSGCurveFillNode *a = node();
+ QSGCurveFillNode *b = otherMaterial->node();
+ if (a == b)
+ return 0;
+
+ if (a->gradientType() == QGradient::NoGradient) {
+ if (int d = a->color().red() - b->color().red())
+ return d;
+ if (int d = a->color().green() - b->color().green())
+ return d;
+ if (int d = a->color().blue() - b->color().blue())
+ return d;
+ if (int d = a->color().alpha() - b->color().alpha())
+ return d;
+ } else {
+ const QSGGradientCache::GradientDesc &ga = *a->fillGradient();
+ const QSGGradientCache::GradientDesc &gb = *b->fillGradient();
+
+ if (int d = ga.a.x() - gb.a.x())
+ return d;
+ if (int d = ga.a.y() - gb.a.y())
+ return d;
+ if (int d = ga.b.x() - gb.b.x())
+ return d;
+ if (int d = ga.b.y() - gb.b.y())
+ return d;
+
+ if (int d = ga.v0 - gb.v0)
+ return d;
+ if (int d = ga.v1 - gb.v1)
+ return d;
+
+ if (int d = ga.spread - gb.spread)
+ return d;
+
+ if (int d = ga.stops.size() - gb.stops.size())
+ return d;
+
+ for (int i = 0; i < ga.stops.size(); ++i) {
+ if (int d = ga.stops[i].first - gb.stops[i].first)
+ return d;
+ if (int d = ga.stops[i].second.rgba() - gb.stops[i].second.rgba())
+ return d;
+ }
+ }
+
+ return 0;
+}
+
+QSGMaterialType *QSGCurveFillMaterial::type() const
+{
+ static QSGMaterialType type[4];
+ uint index = node()->gradientType();
+ Q_ASSERT((index & ~3) == 0); // Only two first bits for gradient type
+
+ return &type[index];
+}
+
+QSGMaterialShader *QSGCurveFillMaterial::createShader(QSGRendererInterface::RenderMode renderMode) const
+{
+ return new QSGCurveFillMaterialShader(node()->gradientType(),
+ renderMode == QSGRendererInterface::RenderMode3D,
+ viewCount());
+}
+
+QT_END_NAMESPACE