diff --git a/src/elevatedrectangle.cpp b/src/elevatedrectangle.cpp index 8aa4fc7f..5da32145 100644 --- a/src/elevatedrectangle.cpp +++ b/src/elevatedrectangle.cpp @@ -1,160 +1,160 @@ /* * Copyright 2020 Arjen Hiemstra * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #include "elevatedrectangle.h" #include "scenegraph/elevatedrectanglenode.h" class ElevatedRectangle::Private { public: - qreal elevation = 0.0; + qreal size = 0.0; qreal radius = 0.0; qreal xOffset = 0.0; qreal yOffset = 0.0; QColor color = Qt::white; QColor shadowColor = Qt::black; }; ElevatedRectangle::ElevatedRectangle(QQuickItem *parentItem) : QQuickItem(parentItem), d(new Private) { setFlag(QQuickItem::ItemHasContents, true); } ElevatedRectangle::~ElevatedRectangle() { } -qreal ElevatedRectangle::elevation() const +qreal ElevatedRectangle::size() const { - return d->elevation; + return d->size; } -void ElevatedRectangle::setElevation(qreal newElevation) +void ElevatedRectangle::setSize(qreal newSize) { - if (newElevation == d->elevation) { + if (newSize == d->size) { return; } - d->elevation = newElevation; + d->size = newSize; update(); - Q_EMIT elevationChanged(); + Q_EMIT sizeChanged(); } qreal ElevatedRectangle::radius() const { return d->radius; } void ElevatedRectangle::setRadius(qreal newRadius) { if (newRadius == d->radius) { return; } d->radius = newRadius; update(); Q_EMIT radiusChanged(); } qreal ElevatedRectangle::xOffset() const { return d->xOffset; } void ElevatedRectangle::setXOffset(qreal newXOffset) { if (newXOffset == d->xOffset) { return; } d->xOffset = newXOffset; update(); Q_EMIT xOffsetChanged(); } qreal ElevatedRectangle::yOffset() const { return d->yOffset; } void ElevatedRectangle::setYOffset(qreal newYOffset) { if (newYOffset == d->yOffset) { return; } d->yOffset = newYOffset; update(); Q_EMIT yOffsetChanged(); } QColor ElevatedRectangle::color() const { return d->color; } void ElevatedRectangle::setColor(const QColor & newColor) { if (newColor == d->color) { return; } d->color = newColor; update(); Q_EMIT colorChanged(); } QColor ElevatedRectangle::shadowColor() const { return d->shadowColor; } void ElevatedRectangle::setShadowColor(const QColor &newShadowColor) { if (newShadowColor == d->shadowColor) { return; } d->shadowColor = newShadowColor; update(); Q_EMIT shadowColorChanged(); } QSGNode *ElevatedRectangle::updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data) { Q_UNUSED(data); if (!node) { node = new ElevatedRectangleNode; } auto elevatedNode = static_cast(node); elevatedNode->setRect(boundingRect()); - elevatedNode->setElevation(d->elevation); + elevatedNode->setSize(d->size); elevatedNode->setRadius(d->radius); elevatedNode->setOffset(QVector2D{float(d->xOffset), float(d->yOffset)}); elevatedNode->setColor(d->color); elevatedNode->setShadowColor(d->shadowColor); elevatedNode->updateGeometry(); return elevatedNode; } diff --git a/src/elevatedrectangle.h b/src/elevatedrectangle.h index 76d10920..c437d3ef 100644 --- a/src/elevatedrectangle.h +++ b/src/elevatedrectangle.h @@ -1,73 +1,73 @@ /* * Copyright 2020 Arjen Hiemstra * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ #ifndef ELEVATEDRECTANGLE_H #define ELEVATEDRECTANGLE_H #include #include class ElevatedRectangle : public QQuickItem { Q_OBJECT - Q_PROPERTY(qreal elevation READ elevation WRITE setElevation NOTIFY elevationChanged) + Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY sizeChanged) Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged) Q_PROPERTY(qreal xOffset READ xOffset WRITE setXOffset NOTIFY xOffsetChanged) Q_PROPERTY(qreal yOffset READ yOffset WRITE setYOffset NOTIFY yOffsetChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(QColor shadowColor READ shadowColor WRITE setShadowColor NOTIFY shadowColorChanged) public: ElevatedRectangle(QQuickItem *parent = nullptr); ~ElevatedRectangle() override; - qreal elevation() const; - void setElevation(qreal newElevation); - Q_SIGNAL void elevationChanged(); + qreal size() const; + void setSize(qreal newSize); + Q_SIGNAL void sizeChanged(); qreal radius() const; void setRadius(qreal newRadius); Q_SIGNAL void radiusChanged(); qreal xOffset() const; void setXOffset(qreal newXOffset); Q_SIGNAL void xOffsetChanged(); qreal yOffset() const; void setYOffset(qreal newYOffset); Q_SIGNAL void yOffsetChanged(); QColor color() const; void setColor(const QColor &newColor); Q_SIGNAL void colorChanged(); QColor shadowColor() const; void setShadowColor(const QColor &newShadowColor); Q_SIGNAL void shadowColorChanged(); protected: QSGNode *updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data) override; private: class Private; const std::unique_ptr d; }; #endif // ELEVATEDRECTANGLE_H diff --git a/src/scenegraph/elevatedrectangle.frag b/src/scenegraph/elevatedrectangle.frag index 7b82b8a7..764cde99 100644 --- a/src/scenegraph/elevatedrectangle.frag +++ b/src/scenegraph/elevatedrectangle.frag @@ -1,74 +1,74 @@ /* * Copyright 2020 Arjen Hiemstra * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Library General Public License for more details * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ // This is based on the 2D SDF functions provided by Inigo Quilez: // https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm uniform lowp float opacity; -uniform lowp float elevation; +uniform lowp float size; uniform lowp float radius; uniform lowp vec4 color; uniform lowp vec4 shadowColor; uniform lowp vec2 offset; uniform lowp vec2 aspect; varying lowp vec2 uv; const lowp float minimum_shadow_radius = 0.05; // Calculate the distance to a rectangle with rounded corners. // \param point The point to calculate the distance of. // \param rect The rectangle to calculate the distance of. // \param translation The amount of translation to apply to the rectangle. // \param radius A vec4 with the radius of each corner. lowp float sdf_rounded_rectangle(in lowp vec2 point, in lowp vec2 rect, in lowp vec2 translation, in lowp vec4 radius) { radius.xy = (point.x > 0.0) ? radius.xy : radius.zw; radius.x = (point.y > 0.0) ? radius.x : radius.y; lowp vec2 d = abs(point - translation) - rect + radius.x; return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius.x; } void main() { // Scaling factor that is the inverse of the amount of scaling applied to the geometry. - lowp float inverse_scale = 1.0 / (1.0 + elevation + length(offset * 2.0)); + lowp float inverse_scale = 1.0 / (1.0 + size + length(offset * 2.0)); // Correction factor to round the corners of a larger shadow. - // We want to account for elevation in regards to shadow radius, so that a larger shadow is + // We want to account for size in regards to shadow radius, so that a larger shadow is // more rounded, but only if we are not already rounding the corners due to corner radius. - lowp float elevation_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius)); + lowp float size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius)); - lowp float shadowRadius = radius + elevation * elevation_factor; + lowp float shadowRadius = radius + size * size_factor; lowp vec4 col = vec4(0.0); // Calculate the shadow's distance field. lowp float shadow = sdf_rounded_rectangle(uv, aspect * inverse_scale, offset * inverse_scale, vec4(shadowRadius * inverse_scale)); // Render it, interpolating the color over the distance. - col = mix(col, shadowColor * sign(elevation), shadowColor.a * (1.0 - smoothstep(-elevation * 0.5, elevation * 0.5, shadow))); + col = mix(col, shadowColor * sign(size), shadowColor.a * (1.0 - smoothstep(-size * 0.5, size * 0.5, shadow))); // Calculate the main rectangle distance field. lowp float rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, vec2(0.0), vec4(radius * inverse_scale)); // Render it as a normal rectangle. lowp float g = fwidth(rect); col = mix(col, color, color.a * (1.0 - smoothstep(0.001 - g, 0.001 + g, rect))); gl_FragColor = col; } diff --git a/src/scenegraph/elevatedrectanglematerial.cpp b/src/scenegraph/elevatedrectanglematerial.cpp index d5373c74..ec8061b8 100644 --- a/src/scenegraph/elevatedrectanglematerial.cpp +++ b/src/scenegraph/elevatedrectanglematerial.cpp @@ -1,111 +1,114 @@ /* * Copyright 2020 Arjen Hiemstra * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see */ #include "elevatedrectanglematerial.h" #include ElevatedRectangleMaterial::ElevatedRectangleMaterial() { setFlag(QSGMaterial::Blending, true); } QSGMaterialShader* ElevatedRectangleMaterial::createShader() const { return new ElevatedRectangleShader{}; } QSGMaterialType* ElevatedRectangleMaterial::type() const { static QSGMaterialType type; return &type; } int ElevatedRectangleMaterial::compare(const QSGMaterial *other) const { auto material = static_cast(other); if (material->color == color - && qFuzzyCompare(material->elevation, elevation) + && material->shadowColor == shadowColor + && material->offset == offset + && material->aspect == aspect + && qFuzzyCompare(material->size, size) && qFuzzyCompare(material->radius, radius)) { return 0; } return QSGMaterial::compare(other); } ElevatedRectangleShader::ElevatedRectangleShader() { auto header = QOpenGLContext::currentContext()->isOpenGLES() ? QStringLiteral("header_es.glsl") : QStringLiteral("header_desktop.glsl"); auto shaderRoot = QStringLiteral(":/org/kde/kirigami/shaders/"); setShaderSourceFiles(QOpenGLShader::Vertex, { shaderRoot + header, shaderRoot + QStringLiteral("elevatedrectangle.vert") }); setShaderSourceFiles(QOpenGLShader::Fragment, { shaderRoot + header, shaderRoot + QStringLiteral("elevatedrectangle.frag") }); } const char *const * ElevatedRectangleShader::attributeNames() const { static char const *const names[] = {"in_vertex", "in_uv", nullptr}; return names; } void ElevatedRectangleShader::initialize() { QSGMaterialShader::initialize(); m_matrixLocation = program()->uniformLocation("matrix"); m_aspectLocation = program()->uniformLocation("aspect"); m_opacityLocation = program()->uniformLocation("opacity"); - m_elevationLocation = program()->uniformLocation("elevation"); + m_sizeLocation = program()->uniformLocation("size"); m_radiusLocation = program()->uniformLocation("radius"); m_colorLocation = program()->uniformLocation("color"); m_shadowColorLocation = program()->uniformLocation("shadowColor"); m_offsetLocation = program()->uniformLocation("offset"); } void ElevatedRectangleShader::updateState(const QSGMaterialShader::RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial) { auto p = program(); if (state.isMatrixDirty()) { p->setUniformValue(m_matrixLocation, state.combinedMatrix()); } if (state.isOpacityDirty()) { p->setUniformValue(m_opacityLocation, state.opacity()); } if (!oldMaterial || newMaterial->compare(oldMaterial) != 0 || state.isCachedMaterialDataDirty()) { auto material = static_cast(newMaterial); p->setUniformValue(m_aspectLocation, material->aspect); - p->setUniformValue(m_elevationLocation, material->elevation); + p->setUniformValue(m_sizeLocation, material->size); p->setUniformValue(m_radiusLocation, material->radius); p->setUniformValue(m_colorLocation, material->color); p->setUniformValue(m_shadowColorLocation, material->shadowColor); p->setUniformValue(m_offsetLocation, material->offset); } } diff --git a/src/scenegraph/elevatedrectanglematerial.h b/src/scenegraph/elevatedrectanglematerial.h index 1ddffc27..a85adcb0 100644 --- a/src/scenegraph/elevatedrectanglematerial.h +++ b/src/scenegraph/elevatedrectanglematerial.h @@ -1,65 +1,65 @@ /* * Copyright 2020 Arjen Hiemstra * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see */ #ifndef ELEVATEDRECTANGLEMATERIAL_H #define ELEVATEDRECTANGLEMATERIAL_H #include #include class ElevatedRectangleMaterial : public QSGMaterial { public: ElevatedRectangleMaterial(); QSGMaterialShader* createShader() const override; QSGMaterialType* type() const override; int compare(const QSGMaterial* other) const override; QVector2D aspect = QVector2D{1.0, 1.0}; - float elevation = 0.0; + float size = 0.0; float radius = 0.0; QColor color = Qt::white; QColor shadowColor = Qt::black; QVector2D offset; }; class ElevatedRectangleShader : public QSGMaterialShader { public: ElevatedRectangleShader(); char const *const *attributeNames() const override; void initialize() override; void updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; private: int m_matrixLocation = -1; int m_opacityLocation = -1; int m_aspectLocation = -1; - int m_elevationLocation = -1; + int m_sizeLocation = -1; int m_radiusLocation = -1; int m_colorLocation = -1; int m_shadowColorLocation = -1; int m_offsetLocation = -1; }; #endif // ELEVATEDRECTANGLEMATERIAL_H diff --git a/src/scenegraph/elevatedrectanglenode.cpp b/src/scenegraph/elevatedrectanglenode.cpp index 056157bc..6dda5b32 100644 --- a/src/scenegraph/elevatedrectanglenode.cpp +++ b/src/scenegraph/elevatedrectanglenode.cpp @@ -1,126 +1,126 @@ /* * Copyright 2020 Arjen Hiemstra * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see */ #include "elevatedrectanglenode.h" #include "elevatedrectanglematerial.h" #include ElevatedRectangleNode::ElevatedRectangleNode(const QRectF& rect) { m_geometry = new QSGGeometry{QSGGeometry::defaultAttributes_TexturedPoint2D(), 4}; setGeometry(m_geometry); setRect(rect); m_material = new ElevatedRectangleMaterial{}; setMaterial(m_material); setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); } void ElevatedRectangleNode::setRect(const QRectF& rect) { if (rect == m_rect) { return; } m_rect = rect; QVector2D newAspect{1.0, 1.0}; if (m_rect.width() >= m_rect.height()) { newAspect.setX(m_rect.width() / m_rect.height()); } else { newAspect.setY(m_rect.height() / m_rect.width()); } if (m_material->aspect != newAspect) { m_material->aspect = newAspect; markDirty(QSGNode::DirtyMaterial); m_aspect = newAspect; } } -void ElevatedRectangleNode::setElevation(qreal elevation) +void ElevatedRectangleNode::setSize(qreal size) { auto minDimension = std::min(m_rect.width(), m_rect.height()); - float uniformElevation = (elevation / minDimension) * 2.0; + float uniformSize = (size / minDimension) * 2.0; - if (!qFuzzyCompare(m_material->elevation, uniformElevation)) { - m_material->elevation = uniformElevation; + if (!qFuzzyCompare(m_material->size, uniformSize)) { + m_material->size = uniformSize; markDirty(QSGNode::DirtyMaterial); - m_elevation = elevation; + m_size = size; } } void ElevatedRectangleNode::setRadius(qreal radius) { auto minDimension = std::min(m_rect.width(), m_rect.height()); float uniformRadius = radius * 2.0 / minDimension; if (!qFuzzyCompare(m_material->radius, uniformRadius)) { m_material->radius = std::min(uniformRadius, 1.0f); markDirty(QSGNode::DirtyMaterial); m_radius = radius; } } void ElevatedRectangleNode::setColor(const QColor &color) { if (m_material->color != color) { m_material->color = color; markDirty(QSGNode::DirtyMaterial); } } void ElevatedRectangleNode::setShadowColor(const QColor& color) { if (m_material->shadowColor != color) { m_material->shadowColor = color; markDirty(QSGNode::DirtyMaterial); } } void ElevatedRectangleNode::setOffset(const QVector2D& offset) { auto minDimension = std::min(m_rect.width(), m_rect.height()); auto uniformOffset = offset * 2.0 / minDimension; if (m_material->offset != uniformOffset) { m_material->offset = uniformOffset; markDirty(QSGNode::DirtyMaterial); m_offset = offset; } } void ElevatedRectangleNode::updateGeometry() { - auto rect = m_rect.adjusted(-m_elevation * m_aspect.x(), -m_elevation * m_aspect.y(), - m_elevation * m_aspect.x(), m_elevation * m_aspect.y()); + auto rect = m_rect.adjusted(-m_size * m_aspect.x(), -m_size * m_aspect.y(), + m_size * m_aspect.x(), m_size * m_aspect.y()); auto offsetLength = m_offset.length(); rect = rect.adjusted(-offsetLength * m_aspect.x(), -offsetLength * m_aspect.y(), offsetLength * m_aspect.x(), offsetLength * m_aspect.y()); QSGGeometry::updateTexturedRectGeometry(m_geometry, rect, QRectF{0.0, 0.0, 1.0, 1.0}); markDirty(QSGNode::DirtyGeometry); } diff --git a/src/scenegraph/elevatedrectanglenode.h b/src/scenegraph/elevatedrectanglenode.h index e6bdd097..1e880024 100644 --- a/src/scenegraph/elevatedrectanglenode.h +++ b/src/scenegraph/elevatedrectanglenode.h @@ -1,55 +1,55 @@ /* * Copyright 2020 Arjen Hiemstra * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) version 3, or any * later version accepted by the membership of KDE e.V. (or its * successor approved by the membership of KDE e.V.), which shall * act as a proxy defined in Section 6 of version 3 of the license. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see */ #ifndef ELEVATEDRECTANGLENODE_H #define ELEVATEDRECTANGLENODE_H #include #include #include class ElevatedRectangleMaterial; class ElevatedRectangleNode : public QSGGeometryNode { public: ElevatedRectangleNode(const QRectF &rect = QRectF{}); void setRect(const QRectF &rect); - void setElevation(qreal elevation); + void setSize(qreal size); void setRadius(qreal radius); void setColor(const QColor &color); void setShadowColor(const QColor &color); void setOffset(const QVector2D &offset); void updateGeometry(); private: QSGGeometry *m_geometry; ElevatedRectangleMaterial *m_material; QRectF m_rect; - qreal m_elevation = 0.0; + qreal m_size = 0.0; qreal m_radius = 0.0; QVector2D m_offset; QVector2D m_aspect; }; #endif // ELEVATEDRECTANGLENODE_H