diff --git a/examples/iotdashboard/Box.cpp b/examples/iotdashboard/Box.cpp index b77d7240..7371a343 100644 --- a/examples/iotdashboard/Box.cpp +++ b/examples/iotdashboard/Box.cpp @@ -8,14 +8,9 @@ #include -QSK_SUBCONTROL( Box, Panel ) - Box::Box( const QString& title, QQuickItem* parent ) - : QskLinearBox( Qt::Vertical, parent ) + : ShadowedBox( Qt::Vertical, parent ) { - setPanel( true ); - setSubcontrolProxy( QskBox::Panel, Box::Panel ); - if ( !title.isEmpty() ) { auto label = new QskTextLabel( title, this ); diff --git a/examples/iotdashboard/Box.h b/examples/iotdashboard/Box.h index 42aa5ce1..883917f8 100644 --- a/examples/iotdashboard/Box.h +++ b/examples/iotdashboard/Box.h @@ -5,16 +5,12 @@ #pragma once -#include +#include "ShadowedBox.h" -class QskTextLabel; - -class Box : public QskLinearBox +class Box : public ShadowedBox { Q_OBJECT public: - QSK_SUBCONTROLS( Panel ) - Box( const QString& title, QQuickItem* parent = nullptr ); }; diff --git a/examples/iotdashboard/BoxWithButtons.cpp b/examples/iotdashboard/BoxWithButtons.cpp index 0ea0e9c2..8b5fc5b7 100644 --- a/examples/iotdashboard/BoxWithButtons.cpp +++ b/examples/iotdashboard/BoxWithButtons.cpp @@ -36,7 +36,6 @@ BoxWithButtons::BoxWithButtons( const QString& title, const QString& value, bool isBright, QQuickItem* parent ) : Box( QString(), parent ) { - setPanel( true ); setSubcontrolProxy( QskBox::Panel, Panel ); setSizePolicy( Qt::Vertical, QskSizePolicy::Maximum ); diff --git a/examples/iotdashboard/MainContent.cpp b/examples/iotdashboard/MainContent.cpp index 5580c15f..60df8234 100644 --- a/examples/iotdashboard/MainContent.cpp +++ b/examples/iotdashboard/MainContent.cpp @@ -23,12 +23,8 @@ #include #include -#include "kirigami/shadowedrectangle.h" - #include -QSK_SUBCONTROL( ShadowPositioner, Panel ) - QSK_SUBCONTROL( MainContent, Panel ) QSK_SUBCONTROL( MainContentGridBox, Panel ) @@ -63,59 +59,6 @@ namespace }; } -ShadowPositioner::ShadowPositioner( QQuickItem* parent ) - : QskControl( parent ) -{ - setAutoLayoutChildren( true ); -} - -void ShadowPositioner::setGridBox( QskGridBox* gridBox ) -{ - m_gridBox = gridBox; - m_rectangles.reserve( m_gridBox->elementCount() ); - - for( int i = 0; i < m_gridBox->elementCount(); ++i ) - { - auto r = new ShadowedRectangle( this ); - r->setZ( 5 ); - r->setColor( Qt::transparent ); - r->shadow()->setColor( color( ShadowPositioner::Panel ) ); - - connect( qskSetup, &QskSetup::skinChanged, [this, r]() - { - r->shadow()->setColor( color( ShadowPositioner::Panel ) ); - } ); - - r->shadow()->setSize( metric( ShadowPositioner::Panel | QskAspect::Size ) ); - r->setOpacity( 0.1 ); - - auto shape = boxShapeHint( ShadowPositioner::Panel ); - r->corners()->setTopLeft( shape.radius( Qt::TopLeftCorner ).width() ); - r->corners()->setTopRight( shape.radius( Qt::TopRightCorner ).width() ); - r->corners()->setBottomLeft( shape.radius( Qt::BottomLeftCorner ).width() ); - r->corners()->setBottomRight( shape.radius( Qt::BottomRightCorner ).width() ); - m_rectangles.append( r ); - } -} - -void ShadowPositioner::updateLayout() -{ - auto mainContent = static_cast< QskLinearBox* >( parentItem() ); - - QTimer::singleShot( 0, this, [this, mainContent]() - { - const auto pos0 = mainContent->itemAtIndex( 1 )->position(); - - for( int i = 0; i < m_rectangles.count(); ++i ) - { - const auto item = m_gridBox->itemAtIndex( i ); - - m_rectangles[i]->setPosition( pos0 + item->position() ); - m_rectangles[i]->setSize( qskItemSize( item ) ); - } - } ); -} - MainContent::MainContent( QQuickItem* parent ) : QskLinearBox( Qt::Vertical, parent ) { @@ -146,15 +89,6 @@ MainContent::MainContent( QQuickItem* parent ) addItem( topBar ); addItem( gridBox ); - - m_shadowPositioner = new ShadowPositioner( this ); - m_shadowPositioner->setGridBox( gridBox ); -} - -void MainContent::geometryChangeEvent( QskGeometryChangeEvent* event ) -{ - QskLinearBox::geometryChangeEvent( event ); - m_shadowPositioner->polish(); } #include "moc_MainContent.cpp" diff --git a/examples/iotdashboard/MainContent.h b/examples/iotdashboard/MainContent.h index b1beb753..e4119785 100644 --- a/examples/iotdashboard/MainContent.h +++ b/examples/iotdashboard/MainContent.h @@ -8,25 +8,6 @@ #include #include -class ShadowedRectangle; - -class ShadowPositioner : public QskControl -{ - Q_OBJECT - - public: - QSK_SUBCONTROLS( Panel ) - - ShadowPositioner( QQuickItem* parent ); - - void updateLayout() override; - void setGridBox( QskGridBox* gridBox ); - - private: - QskGridBox* m_gridBox; - QVector< ShadowedRectangle* > m_rectangles; -}; - class MainContentGridBox : public QskGridBox { Q_OBJECT @@ -50,10 +31,6 @@ class MainContent : public QskLinearBox MainContent( QQuickItem* parent ); - protected: - void geometryChangeEvent( QskGeometryChangeEvent* ) override; - private: QList< QskLinearBox* > m_columns; - ShadowPositioner* m_shadowPositioner; }; diff --git a/examples/iotdashboard/ShadowedBox.cpp b/examples/iotdashboard/ShadowedBox.cpp new file mode 100644 index 00000000..1422d087 --- /dev/null +++ b/examples/iotdashboard/ShadowedBox.cpp @@ -0,0 +1,179 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#include "ShadowedBox.h" +#include "nodes/BoxShadowNode.h" + +#include +#include +#include +#include +#include + +namespace +{ + class Skinlet : public QskSkinlet + { + public: + enum NodeRole { ShadowRole, PanelRole }; + + Skinlet() + { + setNodeRoles( { ShadowRole, PanelRole } ); + } + + QRectF subControlRect( const QskSkinnable*, + const QRectF& contentsRect, QskAspect::Subcontrol subControl ) const override + { + if ( subControl == ShadowedBox::Panel ) + { + return contentsRect; + } + + return QRectF(); + } + + QSGNode* updateSubNode( const QskSkinnable* skinnable, + quint8 nodeRole, QSGNode* node ) const override + { + const auto box = static_cast< const ShadowedBox* >( skinnable ); + + const auto r = box->subControlRect( ShadowedBox::Panel ); + if ( r.isEmpty() ) + return nullptr; + + switch ( nodeRole ) + { + case ShadowRole: + { + auto shadowNode = static_cast< BoxShadowNode* >( node ); + if ( shadowNode == nullptr ) + shadowNode = new BoxShadowNode(); + + const auto& shadowMetrics = box->shadow(); + + shadowNode->setRect( shadowMetrics.shadowRect( r ) ); + shadowNode->setShape( box->shape() ); + shadowNode->setBlurRadius( shadowMetrics.blurRadius() ); + shadowNode->setColor( box->shadowColor() ); + shadowNode->setClipRect( r ); + + shadowNode->updateGeometry(); + + return shadowNode; + } + case PanelRole: + { + auto boxNode = static_cast< QskBoxNode* >( node ); + if ( boxNode == nullptr ) + boxNode = new QskBoxNode(); + + const auto r = box->subControlRect( ShadowedBox::Panel ); + + boxNode->setBoxData( r, box->shape(), box->borderWidth(), + box->borderColor(), box->gradient() ); + + return boxNode; + } + } + + return nullptr; + } + }; +} + +QSK_SUBCONTROL( ShadowedBox, Panel ) + +ShadowedBox::ShadowedBox(Qt::Orientation orientation, QQuickItem* parentItem ) + : QskLinearBox( orientation, parentItem ) +{ + setFlag( QQuickItem::ItemHasContents, true ); + setSkinlet( new Skinlet() ); + + // ### move to Skin: + setGradient( Qt::white ); + setShadow( { 0, 10 } ); + setShadowColor( 0xe5e5e5 ); + setShape( 6 ); +} + +ShadowedBox::~ShadowedBox() +{ +} + +void ShadowedBox::setShadow( const QskShadowMetrics& shadow ) +{ + m_shadow = shadow; + update(); +} + +const QskShadowMetrics& ShadowedBox::shadow() const +{ + return m_shadow; +} + +void ShadowedBox::setShadowColor( const QColor& color ) +{ + m_shadowColor = color; + update(); +} + +QColor ShadowedBox::shadowColor() const +{ + return m_shadowColor; +} + +QRectF ShadowedBox::layoutRectForSize( const QSizeF &size ) const +{ + auto padding = paddingHint( Panel ); + return { padding.left() / 2, padding.top() / 2, + size.width() - padding.right(), size.height() - padding.bottom() }; +} + +void ShadowedBox::setGradient( const QskGradient& gradient ) +{ + m_gradient = gradient; + update(); +} + +const QskGradient& ShadowedBox::gradient() const +{ + return m_gradient; +} + +void ShadowedBox::setShape( const QskBoxShapeMetrics& shape ) +{ + m_shape = shape; + update(); +} + +const QskBoxShapeMetrics& ShadowedBox::shape() const +{ + return m_shape; +} + +void ShadowedBox::setBorderWidth( qreal width ) +{ + m_borderWidth = qMax( width, 0.0 ); + update(); +} + +qreal ShadowedBox::borderWidth() const +{ + return m_borderWidth; +} + +void ShadowedBox::setBorderColor( const QColor& color ) +{ + m_borderColor = color; + update(); +} + +QColor ShadowedBox::borderColor() const +{ + return m_borderColor; +} + +#include "moc_ShadowedBox.cpp" diff --git a/examples/iotdashboard/ShadowedBox.h b/examples/iotdashboard/ShadowedBox.h new file mode 100644 index 00000000..e1e243dd --- /dev/null +++ b/examples/iotdashboard/ShadowedBox.h @@ -0,0 +1,53 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#pragma once + +#include +#include +#include + +class QskGradient; + +class ShadowedBox : public QskLinearBox +{ + Q_OBJECT + + public: + QSK_SUBCONTROLS( Panel ) + + ShadowedBox( Qt::Orientation orientation, QQuickItem* parent = nullptr ); + ~ShadowedBox() override; + + void setShadow( const QskShadowMetrics& ); + const QskShadowMetrics& shadow() const; + + void setGradient( const QskGradient& ); + const QskGradient& gradient() const; + + void setShadowColor( const QColor& ); + QColor shadowColor() const; + + QRectF layoutRectForSize( const QSizeF& size ) const override; + + void setShape( const QskBoxShapeMetrics& ); + const QskBoxShapeMetrics& shape() const; + + void setBorderWidth( qreal width ); + qreal borderWidth() const; + + void setBorderColor( const QColor& ); + QColor borderColor() const; + + private: + QskShadowMetrics m_shadow; + QColor m_shadowColor = Qt::black; + + QskGradient m_gradient; + QskBoxShapeMetrics m_shape; + + qreal m_borderWidth = 0.0; + QColor m_borderColor = Qt::black; +}; diff --git a/examples/iotdashboard/Skin.cpp b/examples/iotdashboard/Skin.cpp index 5fda4df0..049a2732 100644 --- a/examples/iotdashboard/Skin.cpp +++ b/examples/iotdashboard/Skin.cpp @@ -16,8 +16,9 @@ #include "MenuBar.h" #include "PieChartPainted.h" #include "RoundedIcon.h" -#include "TopBar.h" #include "RoundButton.h" +#include "ShadowedBox.h" +#include "TopBar.h" #include "UsageBox.h" #include "UsageDiagram.h" @@ -125,13 +126,8 @@ void Skin::initHints( const Palette& palette ) ed.setFontRole( TimeLabel::Text, QskSkin::HugeFont ); ed.setColor( TimeLabel::Text, "#6776FF" ); - // boxes (including shadow): - ed.setPadding( Box::Panel, 15 ); - - ed.setMetric( ShadowPositioner::Panel | QskAspect::Size, 15 ); - ed.setBoxShape( ShadowPositioner::Panel, 6 ); - + ed.setPadding( ShadowedBox::Panel, 15 ); // content in boxes (indoor temperature, humidity etc.): ed.setFontRole( UsageBox::Separator, QskSkin::SmallFont ); @@ -200,6 +196,5 @@ void Skin::initHints( const Palette& palette ) ed.setBoxBorderColors( UsageDiagramBox::DaysBox, palette.weekdayBox ); ed.setColor( QskTextLabel::Text, palette.text ); ed.setColor( UsageDiagramBox::DayText, palette.text ); - ed.setColor( ShadowPositioner::Panel, palette.shadow ); ed.setGradient( CircularProgressBar::Groove, palette.circularProgressBarGroove ); } diff --git a/examples/iotdashboard/Skin.h b/examples/iotdashboard/Skin.h index 88d80aa0..e246d5cb 100644 --- a/examples/iotdashboard/Skin.h +++ b/examples/iotdashboard/Skin.h @@ -60,7 +60,7 @@ class DaytimeSkin : public Skin : Skin( Skin::Palette( {"#6D7BFB"}, {"#fbfbfb"}, {"#ffffff"}, "#ffffff", {"#f7f7f7"}, {"#f4f4f4"}, Qt::black, Qt::black, - { QskGradient::Vertical, { { 0.0, 0xc4c4c4 }, { 0.5, 0xf8f8f8 }, { 1.0, 0xc4c4c4 } } } ) + { QskGradient::Vertical, { { 0.0, 0xffc4c4c4 }, { 0.5, 0xfff8f8f8 }, { 1.0, 0xffc4c4c4 } } } ) , parent ) { } @@ -73,7 +73,7 @@ class NighttimeSkin : public Skin : Skin( Skin::Palette( {"#2937A7"}, {"#040404"}, {"#000000"}, "#000000", {"#0a0a0a"}, {"#0c0c0c"}, Qt::white, Qt::white, - { QskGradient::Vertical, { { 0.0, 0x666666 }, { 0.5, 0x222222 }, { 1.0, 0x333333 } } } ) + { QskGradient::Vertical, { { 0.0, 0xff666666 }, { 0.5, 0xff222222 }, { 1.0, 0xff333333 } } } ) , parent ) { } diff --git a/examples/iotdashboard/iotdashboard.pro b/examples/iotdashboard/iotdashboard.pro index e2ee840e..2064a376 100644 --- a/examples/iotdashboard/iotdashboard.pro +++ b/examples/iotdashboard/iotdashboard.pro @@ -18,6 +18,7 @@ SOURCES += \ PieChartPainted.cpp \ PieChartSkinlet.cpp \ RoundedIcon.cpp \ + ShadowedBox.cpp \ Skin.cpp \ TopBar.cpp \ RoundButton.cpp \ @@ -28,7 +29,8 @@ SOURCES += \ SOURCES += \ nodes/DiagramDataNode.cpp \ - nodes/DiagramSegmentsNode.cpp + nodes/DiagramSegmentsNode.cpp \ + nodes/BoxShadowNode.cpp HEADERS += \ Box.h \ @@ -47,6 +49,7 @@ HEADERS += \ PieChartPainted.h \ PieChartSkinlet.h \ RoundedIcon.h \ + ShadowedBox.h \ Skin.h \ TopBar.h \ RoundButton.h \ @@ -55,23 +58,10 @@ HEADERS += \ HEADERS += \ nodes/DiagramDataNode.h \ - nodes/DiagramSegmentsNode.h - -HEADERS += \ - kirigami/shadowedrectangle.h \ - kirigami/scenegraph/paintedrectangleitem.h \ - kirigami/scenegraph/shadowedborderrectanglematerial.h \ - kirigami/scenegraph/shadowedrectanglematerial.h \ - kirigami/scenegraph/shadowedrectanglenode.h - -SOURCES += \ - kirigami/shadowedrectangle.cpp \ - kirigami/scenegraph/paintedrectangleitem.cpp \ - kirigami/scenegraph/shadowedborderrectanglematerial.cpp \ - kirigami/scenegraph/shadowedrectanglematerial.cpp \ - kirigami/scenegraph/shadowedrectanglenode.cpp + nodes/DiagramSegmentsNode.h \ + nodes/BoxShadowNode.h RESOURCES += \ images.qrc \ fonts.qrc \ - kirigami/scenegraph/shaders/shaders.qrc + shaders.qrc diff --git a/examples/iotdashboard/kirigami/scenegraph/paintedrectangleitem.cpp b/examples/iotdashboard/kirigami/scenegraph/paintedrectangleitem.cpp deleted file mode 100644 index 83eb28cf..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/paintedrectangleitem.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#include "paintedrectangleitem.h" - -#include - -PaintedRectangleItem::PaintedRectangleItem(QQuickItem* parent) - : QQuickPaintedItem(parent) -{ -} - -void PaintedRectangleItem::setColor(const QColor& color) -{ - m_color = color; - update(); -} - -void PaintedRectangleItem::setRadius(qreal radius) -{ - m_radius = radius; - update(); -} - -void PaintedRectangleItem::setBorderColor(const QColor& color) -{ - m_borderColor = color; - update(); -} - -void PaintedRectangleItem::setBorderWidth(qreal width) -{ - m_borderWidth = width; - update(); -} - -void PaintedRectangleItem::paint(QPainter* painter) -{ - painter->setRenderHint(QPainter::Antialiasing, true); - painter->setBrush(m_color); - if (m_borderWidth > 0.0) { - painter->setPen(QPen(m_borderColor, m_borderWidth)); - } else { - painter->setPen(Qt::transparent); - } - painter->drawRoundedRect(m_borderWidth / 2, m_borderWidth / 2, width() - m_borderWidth, height() - m_borderWidth, m_radius, m_radius); -} diff --git a/examples/iotdashboard/kirigami/scenegraph/paintedrectangleitem.h b/examples/iotdashboard/kirigami/scenegraph/paintedrectangleitem.h deleted file mode 100644 index 8036682c..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/paintedrectangleitem.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#ifndef PAINTEDRECTANGLEITEM_H -#define PAINTEDRECTANGLEITEM_H - -#include - -/** - * A rectangle with a border and rounded corners, rendered through QPainter. - * - * This is a helper used by ShadowedRectangle as fallback for when software - * rendering is used, which means our shaders cannot be used. - * - * Since we cannot actually use QSGPaintedNode, we need to do some trickery - * using QQuickPaintedItem as a child of ShadowedRectangle. - * - * \warning This item is **not** intended as a general purpose item. - */ -class PaintedRectangleItem : public QQuickPaintedItem -{ - Q_OBJECT -public: - explicit PaintedRectangleItem(QQuickItem *parent = nullptr); - - void setColor(const QColor &color); - void setRadius(qreal radius); - void setBorderColor(const QColor &color); - void setBorderWidth(qreal width); - - void paint(QPainter *painter) override; - -private: - QColor m_color; - qreal m_radius = 0.0; - QColor m_borderColor; - qreal m_borderWidth = 0.0; -}; - -#endif // PAINTEDRECTANGLEITEM_H diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/header_desktop.glsl b/examples/iotdashboard/kirigami/scenegraph/shaders/header_desktop.glsl deleted file mode 100644 index 53b0dd51..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/header_desktop.glsl +++ /dev/null @@ -1,26 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// This file contains common directives needed for the shaders to work. -// It is included as the very first bit in the shader. -// Important: If a specific GLSL version is needed, it should be set in this -// file. - -// This file is intended for desktop OpenGL version 2.1 or greater. - -#version 120 - -#ifndef lowp - #define lowp -#endif - -#ifndef mediump - #define mediump -#endif - -#ifndef highp - #define highp mediump -#endif diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/header_desktop_core.glsl b/examples/iotdashboard/kirigami/scenegraph/shaders/header_desktop_core.glsl deleted file mode 100644 index fbec34d7..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/header_desktop_core.glsl +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// This file contains common directives needed for the shaders to work. -// It is included as the very first bit in the shader. -// Important: If a specific GLSL version is needed, it should be set in this -// file. - -// This file is intended for desktop OpenGL version 4.5 or greater. - -#version 450 - -#define CORE_PROFILE diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/header_es.glsl b/examples/iotdashboard/kirigami/scenegraph/shaders/header_es.glsl deleted file mode 100644 index 6a58d4cd..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/header_es.glsl +++ /dev/null @@ -1,16 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// This file contains common directives needed for the shaders to work. -// It is included as the very first bit in the shader. -// Important: If a specific GLSL version is needed, it should be set in this -// file. - -// This file is intended for OpenGLES version 2.0 or greater. - -#version 100 -#extension GL_OES_standard_derivatives : enable - diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/sdf.glsl b/examples/iotdashboard/kirigami/scenegraph/shaders/sdf.glsl deleted file mode 100644 index 69402c5c..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/sdf.glsl +++ /dev/null @@ -1,240 +0,0 @@ -// SPDX-FileCopyrightText: 2020 Arjen Hiemstra -// SPDX-FileCopyrightText: 2017 Inigo Quilez -// -// SPDX-License-Identifier: MIT -// -// This file is based on -// https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm - -//if not GLES -// include "desktop_header.glsl" -//else -// include "es_header.glsl" - -// A maximum point count to be used for sdf_polygon input arrays. -// Unfortunately even function inputs require a fixed size at declaration time -// for arrays, unless we were to use OpenGL 4.5. -// Since the polygon is most likely to be defined in a uniform, this should be -// at least less than MAX_FRAGMENT_UNIFORM_COMPONENTS / 2 (since we need vec2). -#define SDF_POLYGON_MAX_POINT_COUNT 400 - -/********************************* - Shapes -*********************************/ - -// Distance field for a circle. -// -// \param point A point on the distance field. -// \param radius The radius of the circle. -// -// \return The signed distance from point to the circle. If negative, point is -// inside the circle. -lowp float sdf_circle(in lowp vec2 point, in lowp float radius) -{ - return length(point) - radius; -} - -// Distance field for a triangle. -// -// \param point A point on the distance field. -// \param p0 The first vertex of the triangle. -// \param p0 The second vertex of the triangle. -// \param p0 The third vertex of the triangle. -// -// \note The ordering of the three vertices does not matter. -// -// \return The signed distance from point to triangle. If negative, point is -// inside the triangle. -lowp float sdf_triangle(in lowp vec2 point, in lowp vec2 p0, in lowp vec2 p1, in lowp vec2 p2) -{ - lowp vec2 e0 = p1 - p0; - lowp vec2 e1 = p2 - p1; - lowp vec2 e2 = p0 - p2; - - lowp vec2 v0 = point - p0; - lowp vec2 v1 = point - p1; - lowp vec2 v2 = point - p2; - - lowp vec2 pq0 = v0 - e0 * clamp( dot(v0, e0) / dot(e0, e0), 0.0, 1.0 ); - lowp vec2 pq1 = v1 - e1 * clamp( dot(v1, e1) / dot(e1, e1), 0.0, 1.0 ); - lowp vec2 pq2 = v2 - e2 * clamp( dot(v2, e2) / dot(e2, e2), 0.0, 1.0 ); - - lowp float s = sign( e0.x*e2.y - e0.y*e2.x ); - lowp vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)), - vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))), - vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x))); - - return -sqrt(d.x)*sign(d.y); -} - -// Distance field for a rectangle. -// -// \param point A point on the distance field. -// \param rect A vec2 with the size of the rectangle. -// -// \return The signed distance from point to rectangle. If negative, point is -// inside the rectangle. -lowp float sdf_rectangle(in lowp vec2 point, in lowp vec2 rect) -{ - lowp vec2 d = abs(point) - rect; - return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); -} - -// Distance field for a rectangle with rounded corners. -// -// \param point The point to calculate the distance of. -// \param rect The rectangle to calculate the distance of. -// \param radius A vec4 with the radius of each corner. Order is top right, bottom right, top left, bottom left. -// -// \return The signed distance from point to rectangle. If negative, point is -// inside the rectangle. -lowp float sdf_rounded_rectangle(in lowp vec2 point, in lowp vec2 rect, 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) - rect + radius.x; - return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius.x; -} - -/********************* - Operators -*********************/ - -// Convert a distance field to an annular (hollow) distance field. -// -// \param sdf The result of an sdf shape to convert. -// \param thickness The thickness of the resulting shape. -// -// \return The value of sdf modified to an annular shape. -lowp float sdf_annular(in lowp float sdf, in lowp float thickness) -{ - return abs(sdf) - thickness; -} - -// Union two sdf shapes together. -// -// \param sdf1 The first sdf shape. -// \param sdf2 The second sdf shape. -// -// \return The union of sdf1 and sdf2, that is, the distance to both sdf1 and -// sdf2. -lowp float sdf_union(in lowp float sdf1, in lowp float sdf2) -{ - return min(sdf1, sdf2); -} - -// Subtract two sdf shapes. -// -// \param sdf1 The first sdf shape. -// \param sdf2 The second sdf shape. -// -// \return sdf1 with sdf2 subtracted from it. -lowp float sdf_subtract(in lowp float sdf1, in lowp float sdf2) -{ - return max(sdf1, -sdf2); -} - -// Intersect two sdf shapes. -// -// \param sdf1 The first sdf shape. -// \param sdf2 The second sdf shape. -// -// \return The intersection between sdf1 and sdf2, that is, the area where both -// sdf1 and sdf2 provide the same distance value. -lowp float sdf_intersect(in lowp float sdf1, in lowp float sdf2) -{ - return max(sdf1, sdf2); -} - -// Smoothly intersect two sdf shapes. -// -// \param sdf1 The first sdf shape. -// \param sdf2 The second sdf shape. -// \param smoothing The amount of smoothing to apply. -// -// \return A smoothed version of the intersect operation. -lowp float sdf_intersect_smooth(in lowp float sdf1, in lowp float sdf2, in lowp float smoothing) -{ - lowp float h = clamp(0.5 - 0.5 * (sdf1 - sdf2) / smoothing, 0.0, 1.0); - return mix(sdf1, sdf2, h) + smoothing * h * (1.0 - h); -} - -// Round an sdf shape. -// -// \param sdf The sdf shape to round. -// \param amount The amount of rounding to apply. -// -// \return The rounded shape of sdf. -// Note that rounding happens by basically selecting an isoline of sdf, -// therefore, the resulting shape may be larger than the input shape. -lowp float sdf_round(in lowp float sdf, in lowp float amount) -{ - return sdf - amount; -} - -// Convert an sdf shape to an outline of its shape. -// -// \param sdf The sdf shape to turn into an outline. -// -// \return The outline of sdf. -lowp float sdf_outline(in lowp float sdf) -{ - return abs(sdf); -} - -/******************** - Convenience -********************/ - -// A constant to represent a "null" value of an sdf. -// -// Since 0 is a point exactly on the outline of an sdf shape, and negative -// values are inside the shape, this uses a very large positive constant to -// indicate a value that is really far away from the actual sdf shape. -const lowp float sdf_null = 99999.0; - -// A constant for a default level of smoothing when rendering an sdf. -// -// This -const lowp float sdf_default_smoothing = 0.625; - -// Render an sdf shape alpha-blended onto an existing color. -// -// This is an overload of sdf_render(float, vec4, vec4) that allows specifying a -// blending amount and a smoothing amount. -// -// \param alpha The alpha to use for blending. -// \param smoothing The amount of smoothing to apply to the sdf. -// -lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float alpha, in lowp float smoothing) -{ - lowp float g = fwidth(sdf); - return mix(sourceColor, sdfColor, alpha * (1.0 - smoothstep(-smoothing * g, smoothing * g, sdf))); -} - -// Render an sdf shape. -// -// This will render the sdf shape on top of whatever source color is input, -// making sure to apply smoothing if desired. -// -// \param sdf The sdf shape to render. -// \param sourceColor The source color to render on top of. -// \param sdfColor The color to use for rendering the sdf shape. -// -// \return sourceColor with the sdf shape rendered on top. -lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor) -{ - return sdf_render(sdf, sourceColor, sdfColor, 1.0, sdf_default_smoothing); -} - -// Render an sdf shape. -// -// This is an overload of sdf_render(float, vec4, vec4) that allows specifying a -// smoothing amount. -// -// \param smoothing The amount of smoothing to apply to the sdf. -// -lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float smoothing) -{ - return sdf_render(sdf, sourceColor, sdfColor, 1.0, smoothing); -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/sdf_lowpower.glsl b/examples/iotdashboard/kirigami/scenegraph/shaders/sdf_lowpower.glsl deleted file mode 100644 index 2344e20b..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/sdf_lowpower.glsl +++ /dev/null @@ -1,239 +0,0 @@ -// SPDX-FileCopyrightText: 2020 Arjen Hiemstra -// SPDX-FileCopyrightText: 2017 Inigo Quilez -// -// SPDX-License-Identifier: MIT -// -// This file is based on -// https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm - -//if not GLES -// include "desktop_header.glsl" -//else -// include "es_header.glsl" - -// A maximum point count to be used for sdf_polygon input arrays. -// Unfortunately even function inputs require a fixed size at declaration time -// for arrays, unless we were to use OpenGL 4.5. -// Since the polygon is most likely to be defined in a uniform, this should be -// at least less than MAX_FRAGMENT_UNIFORM_COMPONENTS / 2 (since we need vec2). -#define SDF_POLYGON_MAX_POINT_COUNT 400 - -/********************************* - Shapes -*********************************/ - -// Distance field for a circle. -// -// \param point A point on the distance field. -// \param radius The radius of the circle. -// -// \return The signed distance from point to the circle. If negative, point is -// inside the circle. -lowp float sdf_circle(in lowp vec2 point, in lowp float radius) -{ - return length(point) - radius; -} - -// Distance field for a triangle. -// -// \param point A point on the distance field. -// \param p0 The first vertex of the triangle. -// \param p0 The second vertex of the triangle. -// \param p0 The third vertex of the triangle. -// -// \note The ordering of the three vertices does not matter. -// -// \return The signed distance from point to triangle. If negative, point is -// inside the triangle. -lowp float sdf_triangle(in lowp vec2 point, in lowp vec2 p0, in lowp vec2 p1, in lowp vec2 p2) -{ - lowp vec2 e0 = p1 - p0; - lowp vec2 e1 = p2 - p1; - lowp vec2 e2 = p0 - p2; - - lowp vec2 v0 = point - p0; - lowp vec2 v1 = point - p1; - lowp vec2 v2 = point - p2; - - lowp vec2 pq0 = v0 - e0 * clamp( dot(v0, e0) / dot(e0, e0), 0.0, 1.0 ); - lowp vec2 pq1 = v1 - e1 * clamp( dot(v1, e1) / dot(e1, e1), 0.0, 1.0 ); - lowp vec2 pq2 = v2 - e2 * clamp( dot(v2, e2) / dot(e2, e2), 0.0, 1.0 ); - - lowp float s = sign( e0.x*e2.y - e0.y*e2.x ); - lowp vec2 d = min(min(vec2(dot(pq0,pq0), s*(v0.x*e0.y-v0.y*e0.x)), - vec2(dot(pq1,pq1), s*(v1.x*e1.y-v1.y*e1.x))), - vec2(dot(pq2,pq2), s*(v2.x*e2.y-v2.y*e2.x))); - - return -sqrt(d.x)*sign(d.y); -} - -// Distance field for a rectangle. -// -// \param point A point on the distance field. -// \param rect A vec2 with the size of the rectangle. -// -// \return The signed distance from point to rectangle. If negative, point is -// inside the rectangle. -lowp float sdf_rectangle(in lowp vec2 point, in lowp vec2 rect) -{ - lowp vec2 d = abs(point) - rect; - return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0); -} - -// Distance field for a rectangle with rounded corners. -// -// \param point The point to calculate the distance of. -// \param rect The rectangle to calculate the distance of. -// \param radius A vec4 with the radius of each corner. Order is top right, bottom right, top left, bottom left. -// -// \return The signed distance from point to rectangle. If negative, point is -// inside the rectangle. -lowp float sdf_rounded_rectangle(in lowp vec2 point, in lowp vec2 rect, 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) - rect + radius.x; - return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - radius.x; -} - -/********************* - Operators -*********************/ - -// Convert a distance field to an annular (hollow) distance field. -// -// \param sdf The result of an sdf shape to convert. -// \param thickness The thickness of the resulting shape. -// -// \return The value of sdf modified to an annular shape. -lowp float sdf_annular(in lowp float sdf, in lowp float thickness) -{ - return abs(sdf) - thickness; -} - -// Union two sdf shapes together. -// -// \param sdf1 The first sdf shape. -// \param sdf2 The second sdf shape. -// -// \return The union of sdf1 and sdf2, that is, the distance to both sdf1 and -// sdf2. -lowp float sdf_union(in lowp float sdf1, in lowp float sdf2) -{ - return min(sdf1, sdf2); -} - -// Subtract two sdf shapes. -// -// \param sdf1 The first sdf shape. -// \param sdf2 The second sdf shape. -// -// \return sdf1 with sdf2 subtracted from it. -lowp float sdf_subtract(in lowp float sdf1, in lowp float sdf2) -{ - return max(sdf1, -sdf2); -} - -// Intersect two sdf shapes. -// -// \param sdf1 The first sdf shape. -// \param sdf2 The second sdf shape. -// -// \return The intersection between sdf1 and sdf2, that is, the area where both -// sdf1 and sdf2 provide the same distance value. -lowp float sdf_intersect(in lowp float sdf1, in lowp float sdf2) -{ - return max(sdf1, sdf2); -} - -// Smoothly intersect two sdf shapes. -// -// \param sdf1 The first sdf shape. -// \param sdf2 The second sdf shape. -// \param smoothing The amount of smoothing to apply. -// -// \return A smoothed version of the intersect operation. -lowp float sdf_intersect_smooth(in lowp float sdf1, in lowp float sdf2, in lowp float smoothing) -{ - lowp float h = clamp(0.5 - 0.5 * (sdf1 - sdf2) / smoothing, 0.0, 1.0); - return mix(sdf1, sdf2, h) + smoothing * h * (1.0 - h); -} - -// Round an sdf shape. -// -// \param sdf The sdf shape to round. -// \param amount The amount of rounding to apply. -// -// \return The rounded shape of sdf. -// Note that rounding happens by basically selecting an isoline of sdf, -// therefore, the resulting shape may be larger than the input shape. -lowp float sdf_round(in lowp float sdf, in lowp float amount) -{ - return sdf - amount; -} - -// Convert an sdf shape to an outline of its shape. -// -// \param sdf The sdf shape to turn into an outline. -// -// \return The outline of sdf. -lowp float sdf_outline(in lowp float sdf) -{ - return abs(sdf); -} - -/******************** - Convenience -********************/ - -// A constant to represent a "null" value of an sdf. -// -// Since 0 is a point exactly on the outline of an sdf shape, and negative -// values are inside the shape, this uses a very large positive constant to -// indicate a value that is really far away from the actual sdf shape. -const lowp float sdf_null = 99999.0; - -// A constant for a default level of smoothing when rendering an sdf. -// -// This -const lowp float sdf_default_smoothing = 0.625; - -// Render an sdf shape alpha-blended onto an existing color. -// -// This is an overload of sdf_render(float, vec4, vec4) that allows specifying a -// blending amount and a smoothing amount. -// -// \param alpha The alpha to use for blending. -// \param smoothing The amount of smoothing to apply to the sdf. -// -lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float alpha, in lowp float smoothing) -{ - return mix(sourceColor, sdfColor, alpha * (1.0 - clamp(sdf * 300.0, 0.0, 1.0))); -} - -// Render an sdf shape. -// -// This will render the sdf shape on top of whatever source color is input, -// making sure to apply smoothing if desired. -// -// \param sdf The sdf shape to render. -// \param sourceColor The source color to render on top of. -// \param sdfColor The color to use for rendering the sdf shape. -// -// \return sourceColor with the sdf shape rendered on top. -lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor) -{ - return sdf_render(sdf, sourceColor, sdfColor, 1.0, sdf_default_smoothing); -} - -// Render an sdf shape. -// -// This is an overload of sdf_render(float, vec4, vec4) that allows specifying a -// smoothing amount. -// -// \param smoothing The amount of smoothing to apply to the sdf. -// -lowp vec4 sdf_render(in lowp float sdf, in lowp vec4 sourceColor, in lowp vec4 sdfColor, in lowp float smoothing) -{ - return sdf_render(sdf, sourceColor, sdfColor, 1.0, smoothing); -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shaders.qrc b/examples/iotdashboard/kirigami/scenegraph/shaders/shaders.qrc deleted file mode 100644 index d2ad90f5..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shaders.qrc +++ /dev/null @@ -1,26 +0,0 @@ - - - - header_es.glsl - header_desktop.glsl - header_desktop_core.glsl - sdf.glsl - sdf_lowpower.glsl - sdf.glsl - shadowedrectangle.vert - shadowedrectangle.vert - shadowedrectangle.frag - shadowedrectangle_lowpower.frag - shadowedrectangle.frag - shadowedborderrectangle.frag - shadowedborderrectangle_lowpower.frag - shadowedborderrectangle.frag - shadowedtexture.frag - shadowedtexture_lowpower.frag - shadowedtexture.frag - shadowedbordertexture.frag - shadowedbordertexture_lowpower.frag - shadowedbordertexture.frag - - - diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedborderrectangle.frag b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedborderrectangle.frag deleted file mode 100644 index c01d83f8..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedborderrectangle.frag +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// See sdf.glsl for the SDF related functions. - -// This shader renders a rectangle with rounded corners and a shadow below it. -// In addition it renders a border around it. - -uniform lowp float opacity; -uniform lowp float size; -uniform lowp vec4 radius; -uniform lowp vec4 color; -uniform lowp vec4 shadowColor; -uniform lowp vec2 offset; -uniform lowp vec2 aspect; -uniform lowp float borderWidth; -uniform lowp vec4 borderColor; - -#ifdef CORE_PROFILE -in lowp vec2 uv; -out lowp vec4 out_color; -#else -varying lowp vec2 uv; -#define out_color gl_FragColor -#endif - -const lowp float minimum_shadow_radius = 0.05; - -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 + size + length(offset) * 2.0); - - // Correction factor to round the corners of a larger shadow. - // 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 vec4 size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius)); - lowp vec4 shadow_radius = radius + size * size_factor; - - lowp vec4 col = vec4(0.0); - - // Calculate the shadow's distance field. - lowp float shadow = sdf_rounded_rectangle(uv - offset * 2.0 * inverse_scale, aspect * inverse_scale, shadow_radius * inverse_scale); - // Render it, interpolating the color over the distance. - col = mix(col, shadowColor * sign(size), 1.0 - smoothstep(-size * 0.5, size * 0.5, shadow)); - - // Scale corrected corner radius - lowp vec4 corner_radius = radius * inverse_scale; - - // Calculate the outer rectangle distance field. - lowp float outer_rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, corner_radius); - - // First, remove anything that was rendered by the shadow if it is inside the rectangle. - // This allows us to use colors with alpha without rendering artifacts. - col = sdf_render(outer_rect, col, vec4(0.0)); - - // Then, render it again but this time with the proper color and properly alpha blended. - col = sdf_render(outer_rect, col, borderColor); - - // The inner rectangle distance field is the outer reduces by twice the border size. - lowp float inner_rect = outer_rect + (borderWidth * inverse_scale) * 2.0; - - // Like above, but this time cut out the inner rectangle. - col = sdf_render(inner_rect, col, vec4(0.0)); - - // Finally, render the inner rectangle. - col = sdf_render(inner_rect, col, color); - - out_color = col * opacity; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedborderrectangle_lowpower.frag b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedborderrectangle_lowpower.frag deleted file mode 100644 index 02bb9d4a..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedborderrectangle_lowpower.frag +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// See sdf.glsl for the SDF related functions. - -// This is a version of shadowedborderrectangle.frag for extremely low powered -// hardware (PinePhone). It does not draw a shadow and also eliminates alpha -// blending. - -uniform lowp float opacity; -uniform lowp float size; -uniform lowp vec4 radius; -uniform lowp vec4 color; -uniform lowp vec4 shadowColor; -uniform lowp vec2 offset; -uniform lowp vec2 aspect; -uniform lowp float borderWidth; -uniform lowp vec4 borderColor; - -#ifdef CORE_PROFILE -in lowp vec2 uv; -out lowp vec4 out_color; -#else -varying lowp vec2 uv; -#define out_color gl_FragColor -#define texture texture2D -#endif - -void main() -{ - lowp vec4 col = vec4(0.0); - - // Calculate the outer rectangle distance field. - lowp float outer_rect = sdf_rounded_rectangle(uv, aspect, radius); - - col = sdf_render(outer_rect, col, vec4(borderColor.rgb, 1.0)); - - // The inner distance field is the outer reduced by border width. - lowp float inner_rect = outer_rect + borderWidth * 2.0; - - col = sdf_render(inner_rect, col, vec4(color.rgb, 1.0)); - - out_color = col * opacity; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedbordertexture.frag b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedbordertexture.frag deleted file mode 100644 index e384b563..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedbordertexture.frag +++ /dev/null @@ -1,83 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// See sdf.glsl for the SDF related functions. - -// This shader renders a rectangle with rounded corners and a shadow below it. -// In addition it renders a border around it. - -uniform lowp float opacity; -uniform lowp float size; -uniform lowp vec4 radius; -uniform lowp vec4 color; -uniform lowp vec4 shadowColor; -uniform lowp vec2 offset; -uniform lowp vec2 aspect; -uniform lowp float borderWidth; -uniform lowp vec4 borderColor; -uniform sampler2D textureSource; - -#ifdef CORE_PROFILE -in lowp vec2 uv; -out lowp vec4 out_color; -#else -varying lowp vec2 uv; -#define out_color gl_FragColor -#define texture texture2D -#endif - -const lowp float minimum_shadow_radius = 0.05; - -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 + size + length(offset) * 2.0); - - // Correction factor to round the corners of a larger shadow. - // 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 vec4 size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius)); - lowp vec4 shadow_radius = radius + size * size_factor; - - lowp vec4 col = vec4(0.0); - - // Calculate the shadow's distance field. - lowp float shadow = sdf_rounded_rectangle(uv - offset * 2.0 * inverse_scale, aspect * inverse_scale, shadow_radius * inverse_scale); - // Render it, interpolating the color over the distance. - col = mix(col, shadowColor * sign(size), 1.0 - smoothstep(-size * 0.5, size * 0.5, shadow)); - - // Scale corrected corner radius - lowp vec4 corner_radius = radius * inverse_scale; - - // Calculate the outer rectangle distance field. - lowp float outer_rect = sdf_rounded_rectangle(uv, aspect * inverse_scale, corner_radius); - - // First, remove anything that was rendered by the shadow if it is inside the rectangle. - // This allows us to use colors with alpha without rendering artifacts. - col = sdf_render(outer_rect, col, vec4(0.0)); - - // Then, render it again but this time with the proper color and properly alpha blended. - col = sdf_render(outer_rect, col, borderColor); - - // The inner rectangle distance field is the outer reduced by twice the border width. - lowp float inner_rect = outer_rect + (borderWidth * inverse_scale) * 2.0; - - // Like above, but this time cut out the inner rectangle. - col = sdf_render(inner_rect, col, vec4(0.0)); - - // Finally, render the inner rectangle. - col = sdf_render(inner_rect, col, color); - - // Slightly increase the size of the inner rectangle, to avoid issues with anti-aliasing. - inner_rect = inner_rect - 0.005; - - // Sample the texture, then blend it on top of the background color. - lowp vec2 texture_uv = ((uv / aspect) + (1.0 * inverse_scale)) / (2.0 * inverse_scale); - lowp vec4 texture_color = texture(textureSource, texture_uv); - col = sdf_render(inner_rect, col, texture_color, texture_color.a, sdf_default_smoothing / 2.0); - - out_color = col * opacity; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedbordertexture_lowpower.frag b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedbordertexture_lowpower.frag deleted file mode 100644 index 29f67620..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedbordertexture_lowpower.frag +++ /dev/null @@ -1,53 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// See sdf.glsl for the SDF related functions. - -// This shader renders a rectangle with rounded corners and a shadow below it. -// In addition it renders a border around it. - -uniform lowp float opacity; -uniform lowp float size; -uniform lowp vec4 radius; -uniform lowp vec4 color; -uniform lowp vec4 shadowColor; -uniform lowp vec2 offset; -uniform lowp vec2 aspect; -uniform lowp float borderWidth; -uniform lowp vec4 borderColor; -uniform sampler2D textureSource; - -#ifdef CORE_PROFILE -in lowp vec2 uv; -out lowp vec4 out_color; -#else -varying lowp vec2 uv; -#define out_color gl_FragColor -#define texture texture2D -#endif - -const lowp float minimum_shadow_radius = 0.05; - -void main() -{ - lowp vec4 col = vec4(0.0); - - // Calculate the outer rectangle distance field. - lowp float outer_rect = sdf_rounded_rectangle(uv, aspect, radius); - - // Render it, cancelling out any alpha components. - col = sdf_render(outer_rect, col, vec4(borderColor.rgb, 1.0)); - - // Inner rectangle distance field equals outer reduced by twice the border width - lowp float inner_rect = outer_rect + borderWidth * 2.0; - - // Sample the texture, then render it on top of the background color. - lowp vec2 texture_uv = ((uv / aspect) + 1.0) / 2.0; - lowp vec4 texture_color = vec4(texture(textureSource, texture_uv).rgb, 1.0); - col = sdf_render(inner_rect, col, texture_color, texture_color.a, sdf_default_smoothing / 2.0); - - out_color = col * opacity; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle.frag b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle.frag deleted file mode 100644 index 2568b14f..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle.frag +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// See sdf.glsl for the SDF related functions. - -// This shader renders a rectangle with rounded corners and a shadow below it. - -uniform lowp float opacity; -uniform lowp float size; -uniform lowp vec4 radius; -uniform lowp vec4 color; -uniform lowp vec4 shadowColor; -uniform lowp vec2 offset; -uniform lowp vec2 aspect; - -#ifdef CORE_PROFILE -in lowp vec2 uv; -out lowp vec4 out_color; -#else -varying lowp vec2 uv; -#define out_color gl_FragColor -#endif - -const lowp float minimum_shadow_radius = 0.05; - -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 + size + length(offset) * 2.0); - - // Correction factor to round the corners of a larger shadow. - // 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 vec4 size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius)); - lowp vec4 shadow_radius = radius + size * size_factor; - - lowp vec4 col = vec4(0.0); - - // Calculate the shadow's distance field. - lowp float shadow = sdf_rounded_rectangle(uv - offset * 2.0 * inverse_scale, aspect * inverse_scale, shadow_radius * inverse_scale); - // Render it, interpolating the color over the distance. - col = mix(col, shadowColor * sign(size), 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, radius * inverse_scale); - - // First, remove anything that was rendered by the shadow if it is inside the rectangle. - // This allows us to use colors with alpha without rendering artifacts. - col = sdf_render(rect, col, vec4(0.0)); - - // Then, render it again but this time with the proper color and properly alpha blended. - col = sdf_render(rect, col, color); - - out_color = col * opacity; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle.vert b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle.vert deleted file mode 100644 index f27244cf..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle.vert +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -uniform highp mat4 matrix; -uniform lowp vec2 aspect; - -#ifdef CORE_PROFILE -in highp vec4 in_vertex; -in mediump vec2 in_uv; -out mediump vec2 uv; -#else -attribute highp vec4 in_vertex; -attribute mediump vec2 in_uv; -varying mediump vec2 uv; -#endif - -void main() { - uv = (-1.0 + 2.0 * in_uv) * aspect; - gl_Position = matrix * in_vertex; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle_lowpower.frag b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle_lowpower.frag deleted file mode 100644 index df7d7b6c..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedrectangle_lowpower.frag +++ /dev/null @@ -1,39 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// See sdf.glsl for the SDF related functions. - -// This is a version of shadowedrectangle.frag meant for very low power hardware -// (PinePhone). It does not render a shadow and does not do alpha blending. - -uniform lowp float opacity; -uniform lowp float size; -uniform lowp vec4 radius; -uniform lowp vec4 color; -uniform lowp vec4 shadowColor; -uniform lowp vec2 offset; -uniform lowp vec2 aspect; - -#ifdef CORE_PROFILE -in lowp vec2 uv; -out lowp vec4 out_color; -#else -varying lowp vec2 uv; -#define out_color gl_FragColor -#endif - -void main() -{ - lowp vec4 col = vec4(0.0); - - // Calculate the main rectangle distance field. - lowp float rect = sdf_rounded_rectangle(uv, aspect, radius); - - // Render it, cancelling out any alpha component. - col = sdf_render(rect, col, vec4(color.rgb, 1.0)); - - out_color = col * opacity; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedtexture.frag b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedtexture.frag deleted file mode 100644 index d161ad8c..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedtexture.frag +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// See sdf.glsl for the SDF related functions. - -// This shader renders a texture on top of a rectangle with rounded corners and -// a shadow below it. - -uniform lowp float opacity; -uniform lowp float size; -uniform lowp vec4 radius; -uniform lowp vec4 color; -uniform lowp vec4 shadowColor; -uniform lowp vec2 offset; -uniform lowp vec2 aspect; -uniform sampler2D textureSource; - -#ifdef CORE_PROFILE -in lowp vec2 uv; -out lowp vec4 out_color; -#else -varying lowp vec2 uv; -#define out_color gl_FragColor -#define texture texture2D -#endif - -const lowp float minimum_shadow_radius = 0.05; - -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 + size + length(offset) * 2.0); - - // Correction factor to round the corners of a larger shadow. - // 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 vec4 size_factor = 0.5 * (minimum_shadow_radius / max(radius, minimum_shadow_radius)); - lowp vec4 shadow_radius = radius + size * size_factor; - - lowp vec4 col = vec4(0.0); - - // Calculate the shadow's distance field. - lowp float shadow = sdf_rounded_rectangle(uv - offset * 2.0 * inverse_scale, aspect * inverse_scale, shadow_radius * inverse_scale); - // Render it, interpolating the color over the distance. - col = mix(col, shadowColor * sign(size), 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, radius * inverse_scale); - - // First, remove anything that was rendered by the shadow if it is inside the rectangle. - // This allows us to use colors with alpha without rendering artifacts. - col = sdf_render(rect, col, vec4(0.0)); - - // Then, render it again but this time with the proper color. - col = sdf_render(rect, col, color); - - // Sample the texture, then blend it on top of the background color. - lowp vec2 texture_uv = ((uv / aspect) + (1.0 * inverse_scale)) / (2.0 * inverse_scale); - lowp vec4 texture_color = texture(textureSource, texture_uv); - col = sdf_render(rect, col, texture_color, texture_color.a, sdf_default_smoothing); - - out_color = col * opacity; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedtexture_lowpower.frag b/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedtexture_lowpower.frag deleted file mode 100644 index 409de06b..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shaders/shadowedtexture_lowpower.frag +++ /dev/null @@ -1,44 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -// See sdf.glsl for the SDF related functions. - -// This shader renders a texture on top of a rectangle with rounded corners and -// a shadow below it. - -uniform lowp float opacity; -uniform lowp float size; -uniform lowp vec4 radius; -uniform lowp vec4 color; -uniform lowp vec4 shadowColor; -uniform lowp vec2 offset; -uniform lowp vec2 aspect; -uniform sampler2D textureSource; - -#ifdef CORE_PROFILE -in lowp vec2 uv; -out lowp vec4 out_color; -#else -varying lowp vec2 uv; -#define out_color gl_FragColor -#define texture texture2D -#endif - -void main() -{ - lowp vec4 col = vec4(0.0); - - // Calculate the main rectangle distance field. - lowp float rect = sdf_rounded_rectangle(uv, aspect, radius); - - // Sample the texture, then render it, without any alpha blending. - lowp vec2 texture_uv = ((uv / aspect) + 1.0) / 2.0; - lowp vec4 texture_color = vec4(texture(textureSource, texture_uv).rgb, 1.0); - - col = sdf_render(rect, col, texture_color); - - out_color = col * opacity; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shadowedborderrectanglematerial.cpp b/examples/iotdashboard/kirigami/scenegraph/shadowedborderrectanglematerial.cpp deleted file mode 100644 index 25bfcd06..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shadowedborderrectanglematerial.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#include "shadowedborderrectanglematerial.h" - -#include - -QSGMaterialType ShadowedBorderRectangleMaterial::staticType; - -ShadowedBorderRectangleMaterial::ShadowedBorderRectangleMaterial() -{ - setFlag(QSGMaterial::Blending, true); -} - -QSGMaterialShader* ShadowedBorderRectangleMaterial::createShader() const -{ - return new ShadowedBorderRectangleShader{shaderType}; -} - -QSGMaterialType* ShadowedBorderRectangleMaterial::type() const -{ - return &staticType; -} - -int ShadowedBorderRectangleMaterial::compare(const QSGMaterial *other) const -{ - auto material = static_cast(other); - - auto result = ShadowedRectangleMaterial::compare(other); - if (result == 0 - && material->borderColor == borderColor - && qFuzzyCompare(material->borderWidth, borderWidth) - ) { - return 0; - } - - return result; -} - -ShadowedBorderRectangleShader::ShadowedBorderRectangleShader(ShadowedRectangleMaterial::ShaderType shaderType) - : ShadowedRectangleShader(shaderType) -{ - setShader(shaderType, QStringLiteral("shadowedborderrectangle")); -} - -void ShadowedBorderRectangleShader::initialize() -{ - ShadowedRectangleShader::initialize(); - m_borderWidthLocation = program()->uniformLocation("borderWidth"); - m_borderColorLocation = program()->uniformLocation("borderColor"); -} - -void ShadowedBorderRectangleShader::updateState(const QSGMaterialShader::RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial) -{ - ShadowedRectangleShader::updateState(state, newMaterial, oldMaterial); - - auto p = program(); - - if (!oldMaterial || newMaterial->compare(oldMaterial) != 0 ) { - auto material = static_cast(newMaterial); - p->setUniformValue(m_borderWidthLocation, material->borderWidth); - p->setUniformValue(m_borderColorLocation, material->borderColor); - } -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shadowedborderrectanglematerial.h b/examples/iotdashboard/kirigami/scenegraph/shadowedborderrectanglematerial.h deleted file mode 100644 index a507809c..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shadowedborderrectanglematerial.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#pragma once - -#include "shadowedrectanglematerial.h" - -/** - * A material rendering a rectangle with a shadow and a border. - * - * This material uses a distance field shader to render a rectangle with a - * shadow below it, optionally with rounded corners and a border. - */ -class ShadowedBorderRectangleMaterial : public ShadowedRectangleMaterial -{ -public: - ShadowedBorderRectangleMaterial(); - - QSGMaterialShader* createShader() const override; - QSGMaterialType* type() const override; - int compare(const QSGMaterial* other) const override; - - float borderWidth = 0.0; - QColor borderColor = Qt::black; - - static QSGMaterialType staticType; -}; - -class ShadowedBorderRectangleShader : public ShadowedRectangleShader -{ -public: - ShadowedBorderRectangleShader(ShadowedRectangleMaterial::ShaderType shaderType); - - void initialize() override; - void updateState(const QSGMaterialShader::RenderState &state, QSGMaterial *newMaterial, QSGMaterial *oldMaterial) override; - -private: - int m_borderWidthLocation = -1; - int m_borderColorLocation = -1; -}; diff --git a/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglematerial.cpp b/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglematerial.cpp deleted file mode 100644 index 42f31b7b..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglematerial.cpp +++ /dev/null @@ -1,114 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#include "shadowedrectanglematerial.h" - -#include - -QSGMaterialType ShadowedRectangleMaterial::staticType; - -ShadowedRectangleMaterial::ShadowedRectangleMaterial() -{ - setFlag(QSGMaterial::Blending, true); -} - -QSGMaterialShader* ShadowedRectangleMaterial::createShader() const -{ - return new ShadowedRectangleShader{shaderType}; -} - -QSGMaterialType* ShadowedRectangleMaterial::type() const -{ - return &staticType; -} - -int ShadowedRectangleMaterial::compare(const QSGMaterial *other) const -{ - auto material = static_cast(other); - - if (material->color == color - && material->shadowColor == shadowColor - && material->offset == offset - && material->aspect == aspect - && qFuzzyCompare(material->size, size) - && qFuzzyCompare(material->radius, radius)) { - return 0; - } - - return QSGMaterial::compare(other); -} - -ShadowedRectangleShader::ShadowedRectangleShader(ShadowedRectangleMaterial::ShaderType shaderType) -{ - setShader(shaderType, QStringLiteral("shadowedrectangle")); -} - -const char *const * ShadowedRectangleShader::attributeNames() const -{ - static char const *const names[] = {"in_vertex", "in_uv", nullptr}; - return names; -} - -void ShadowedRectangleShader::initialize() -{ - QSGMaterialShader::initialize(); - m_matrixLocation = program()->uniformLocation("matrix"); - m_aspectLocation = program()->uniformLocation("aspect"); - m_opacityLocation = program()->uniformLocation("opacity"); - 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 ShadowedRectangleShader::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 ) { - auto material = static_cast(newMaterial); - p->setUniformValue(m_aspectLocation, material->aspect); - 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); - } -} - -void ShadowedRectangleShader::setShader(ShadowedRectangleMaterial::ShaderType shaderType, const QString& shader) -{ - 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("shadowedrectangle.vert") - }); - - QString shaderFile = shader + QStringLiteral(".frag"); - auto sdfFile = QStringLiteral("sdf.glsl"); - if (shaderType == ShadowedRectangleMaterial::ShaderType::LowPower) { - shaderFile = shader + QStringLiteral("_lowpower.frag"); - sdfFile = QStringLiteral("sdf_lowpower.glsl"); - } - - setShaderSourceFiles(QOpenGLShader::Fragment, { - shaderRoot + header, - shaderRoot + sdfFile, - shaderRoot + shaderFile - }); -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglematerial.h b/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglematerial.h deleted file mode 100644 index 0349cfe9..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglematerial.h +++ /dev/null @@ -1,67 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#pragma once - -#include -#include -#include - -/** - * A material rendering a rectangle with a shadow. - * - * This material uses a distance field shader to render a rectangle with a - * shadow below it, optionally with rounded corners. - */ -class ShadowedRectangleMaterial : public QSGMaterial -{ - public: - enum class ShaderType - { - Standard, - LowPower - }; - - ShadowedRectangleMaterial(); - - QSGMaterialShader* createShader() const override; - QSGMaterialType* type() const override; - int compare( const QSGMaterial* other ) const override; - - QVector2D aspect = QVector2D{1.0, 1.0}; - float size = 0.0; - QVector4D radius = QVector4D{0.0, 0.0, 0.0, 0.0}; - QColor color = Qt::white; - QColor shadowColor = Qt::black; - QVector2D offset; - ShaderType shaderType = ShaderType::Standard; - - static QSGMaterialType staticType; -}; - -class ShadowedRectangleShader : public QSGMaterialShader -{ - public: - ShadowedRectangleShader( ShadowedRectangleMaterial::ShaderType shaderType ); - - char const* const* attributeNames() const override; - - void initialize() override; - void updateState( const QSGMaterialShader::RenderState& state, QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) override; - - protected: - void setShader( ShadowedRectangleMaterial::ShaderType shaderType, const QString& shader ); - - private: - int m_matrixLocation = -1; - int m_opacityLocation = -1; - int m_aspectLocation = -1; - int m_sizeLocation = -1; - int m_radiusLocation = -1; - int m_colorLocation = -1; - int m_shadowColorLocation = -1; - int m_offsetLocation = -1; -}; diff --git a/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglenode.cpp b/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglenode.cpp deleted file mode 100644 index 81ad894a..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglenode.cpp +++ /dev/null @@ -1,209 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#include "shadowedrectanglenode.h" -#include "shadowedrectanglematerial.h" -#include "shadowedborderrectanglematerial.h" - -QColor premultiply(const QColor &color) -{ - return QColor::fromRgbF( - color.redF() * color.alphaF(), - color.greenF() * color.alphaF(), - color.blueF() * color.alphaF(), - color.alphaF() - ); -} - -ShadowedRectangleNode::ShadowedRectangleNode() -{ - m_geometry = new QSGGeometry{QSGGeometry::defaultAttributes_TexturedPoint2D(), 4}; - setGeometry(m_geometry); - - setFlags(QSGNode::OwnsGeometry | QSGNode::OwnsMaterial); -} - -void ShadowedRectangleNode::setBorderEnabled(bool enabled) -{ - // We can achieve more performant shaders by splitting the two into separate - // shaders. This requires separating the materials as well. So when - // borderWidth is increased to something where the border should be visible, - // switch to the with-border material. Otherwise use the no-border version. - - if (enabled) { - if (!m_material || m_material->type() == borderlessMaterialType()) { - auto newMaterial = createBorderMaterial(); - newMaterial->shaderType = m_shaderType; - setMaterial(newMaterial); - m_material = newMaterial; - m_rect = QRectF{}; - markDirty(QSGNode::DirtyMaterial); - } - } else { - if (!m_material || m_material->type() == borderMaterialType()) { - auto newMaterial = createBorderlessMaterial(); - newMaterial->shaderType = m_shaderType; - setMaterial(newMaterial); - m_material = newMaterial; - m_rect = QRectF{}; - markDirty(QSGNode::DirtyMaterial); - } - } -} - -void ShadowedRectangleNode::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 ShadowedRectangleNode::setSize(qreal size) -{ - auto minDimension = std::min(m_rect.width(), m_rect.height()); - float uniformSize = (size / minDimension) * 2.0; - - if (!qFuzzyCompare(m_material->size, uniformSize)) { - m_material->size = uniformSize; - markDirty(QSGNode::DirtyMaterial); - m_size = size; - } -} - -void ShadowedRectangleNode::setRadius(const QVector4D &radius) -{ - float minDimension = std::min(m_rect.width(), m_rect.height()); - auto uniformRadius = QVector4D{ - std::min(radius.x() * 2.0f / minDimension, 1.0f), - std::min(radius.y() * 2.0f / minDimension, 1.0f), - std::min(radius.z() * 2.0f / minDimension, 1.0f), - std::min(radius.w() * 2.0f / minDimension, 1.0f) - }; - - if (m_material->radius != uniformRadius) { - m_material->radius = uniformRadius; - markDirty(QSGNode::DirtyMaterial); - m_radius = radius; - } -} - -void ShadowedRectangleNode::setColor(const QColor &color) -{ - auto premultiplied = premultiply(color); - if (m_material->color != premultiplied) { - m_material->color = premultiplied; - markDirty(QSGNode::DirtyMaterial); - } -} - -void ShadowedRectangleNode::setShadowColor(const QColor& color) -{ - auto premultiplied = premultiply(color); - if (m_material->shadowColor != premultiplied) { - m_material->shadowColor = premultiplied; - markDirty(QSGNode::DirtyMaterial); - } -} - -void ShadowedRectangleNode::setOffset(const QVector2D& offset) -{ - auto minDimension = std::min(m_rect.width(), m_rect.height()); - auto uniformOffset = offset / minDimension; - - if (m_material->offset != uniformOffset) { - m_material->offset = uniformOffset; - markDirty(QSGNode::DirtyMaterial); - m_offset = offset; - } -} - -void ShadowedRectangleNode::setBorderWidth(qreal width) -{ - if (m_material->type() != borderMaterialType()) { - return; - } - - auto minDimension = std::min(m_rect.width(), m_rect.height()); - float uniformBorderWidth = width / minDimension; - - auto borderMaterial = static_cast(m_material); - if (!qFuzzyCompare(borderMaterial->borderWidth, uniformBorderWidth)) { - borderMaterial->borderWidth = uniformBorderWidth; - markDirty(QSGNode::DirtyMaterial); - m_borderWidth = width; - } -} - -void ShadowedRectangleNode::setBorderColor(const QColor& color) -{ - if (m_material->type() != borderMaterialType()) { - return; - } - - auto borderMaterial = static_cast(m_material); - auto premultiplied = premultiply(color); - if (borderMaterial->borderColor != premultiplied) { - borderMaterial->borderColor = premultiplied; - markDirty(QSGNode::DirtyMaterial); - } -} - -void ShadowedRectangleNode::setShaderType(ShadowedRectangleMaterial::ShaderType type) -{ - m_shaderType = type; -} - -void ShadowedRectangleNode::updateGeometry() -{ - auto rect = m_rect; - if (m_shaderType == ShadowedRectangleMaterial::ShaderType::Standard) { - rect = 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); -} - -ShadowedRectangleMaterial *ShadowedRectangleNode::createBorderlessMaterial() -{ - return new ShadowedRectangleMaterial{}; -} - -ShadowedBorderRectangleMaterial *ShadowedRectangleNode::createBorderMaterial() -{ - return new ShadowedBorderRectangleMaterial{}; -} - -QSGMaterialType *ShadowedRectangleNode::borderlessMaterialType() -{ - return &ShadowedRectangleMaterial::staticType; -} - -QSGMaterialType *ShadowedRectangleNode::borderMaterialType() -{ - return &ShadowedBorderRectangleMaterial::staticType; -} diff --git a/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglenode.h b/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglenode.h deleted file mode 100644 index 69bb0e12..00000000 --- a/examples/iotdashboard/kirigami/scenegraph/shadowedrectanglenode.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#pragma once - -#include -#include -#include -#include - -#include "shadowedrectanglematerial.h" - -struct QSGMaterialType; -class ShadowedBorderRectangleMaterial; - -/** - * Scene graph node for a shadowed rectangle. - * - * This node will set up the geometry and materials for a shadowed rectangle, - * optionally with rounded corners. - * - * \note You must call updateGeometry() after setting properties of this node, - * otherwise the node's state will not correctly reflect all the properties. - * - * \sa ShadowedRectangle - */ -class ShadowedRectangleNode : public QSGGeometryNode -{ -public: - ShadowedRectangleNode(); - - /** - * Set whether to draw a border. - * - * Note that this will switch between a material with or without border. - * This means this needs to be called before any other setters. - */ - void setBorderEnabled(bool enabled); - - void setRect(const QRectF &rect); - void setSize(qreal size); - void setRadius(const QVector4D &radius); - void setColor(const QColor &color); - void setShadowColor(const QColor &color); - void setOffset(const QVector2D &offset); - void setBorderWidth(qreal width); - void setBorderColor(const QColor &color); - void setShaderType(ShadowedRectangleMaterial::ShaderType type); - - /** - * Update the geometry for this node. - * - * This is done as an explicit step to avoid the geometry being recreated - * multiple times while updating properties. - */ - void updateGeometry(); - -protected: - virtual ShadowedRectangleMaterial *createBorderlessMaterial(); - virtual ShadowedBorderRectangleMaterial *createBorderMaterial(); - virtual QSGMaterialType* borderMaterialType(); - virtual QSGMaterialType* borderlessMaterialType(); - - QSGGeometry *m_geometry; - ShadowedRectangleMaterial *m_material = nullptr; - ShadowedRectangleMaterial::ShaderType m_shaderType = ShadowedRectangleMaterial::ShaderType::Standard; - -private: - QRectF m_rect; - qreal m_size = 0.0; - QVector4D m_radius = QVector4D{0.0, 0.0, 0.0, 0.0}; - QVector2D m_offset = QVector2D{0.0, 0.0}; - QVector2D m_aspect = QVector2D{1.0, 1.0}; - qreal m_borderWidth = 0.0; - QColor m_borderColor; -}; diff --git a/examples/iotdashboard/kirigami/shadowedrectangle.cpp b/examples/iotdashboard/kirigami/shadowedrectangle.cpp deleted file mode 100644 index e2136c4a..00000000 --- a/examples/iotdashboard/kirigami/shadowedrectangle.cpp +++ /dev/null @@ -1,368 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#include "shadowedrectangle.h" - -#include - -#include "scenegraph/shadowedrectanglenode.h" -#include "scenegraph/paintedrectangleitem.h" - -BorderGroup::BorderGroup( QObject* parent ) - : QObject( parent ) -{ -} - -qreal BorderGroup::width() const -{ - return m_width; -} - -void BorderGroup::setWidth( qreal newWidth ) -{ - if( newWidth == m_width ) - { - return; - } - - m_width = newWidth; - Q_EMIT changed(); -} - -QColor BorderGroup::color() const -{ - return m_color; -} - -void BorderGroup::setColor( const QColor& newColor ) -{ - if( newColor == m_color ) - { - return; - } - - m_color = newColor; - Q_EMIT changed(); -} - -ShadowGroup::ShadowGroup( QObject* parent ) - : QObject( parent ) -{ -} - -qreal ShadowGroup::size() const -{ - return m_size; -} - -void ShadowGroup::setSize( qreal newSize ) -{ - if( newSize == m_size ) - { - return; - } - - m_size = newSize; - Q_EMIT changed(); -} - -qreal ShadowGroup::xOffset() const -{ - return m_xOffset; -} - -void ShadowGroup::setXOffset( qreal newXOffset ) -{ - if( newXOffset == m_xOffset ) - { - return; - } - - m_xOffset = newXOffset; - Q_EMIT changed(); -} - -qreal ShadowGroup::yOffset() const -{ - return m_yOffset; -} - -void ShadowGroup::setYOffset( qreal newYOffset ) -{ - if( newYOffset == m_yOffset ) - { - return; - } - - m_yOffset = newYOffset; - Q_EMIT changed(); -} - -QColor ShadowGroup::color() const -{ - return m_color; -} - -void ShadowGroup::setColor( const QColor& newColor ) -{ - if( newColor == m_color ) - { - return; - } - - m_color = newColor; - Q_EMIT changed(); -} - -CornersGroup::CornersGroup( QObject* parent ) - : QObject( parent ) -{ -} - -qreal CornersGroup::topLeft() const -{ - return m_topLeft; -} - -void CornersGroup::setTopLeft( qreal newTopLeft ) -{ - if( newTopLeft == m_topLeft ) - { - return; - } - - m_topLeft = newTopLeft; - Q_EMIT changed(); -} - -qreal CornersGroup::topRight() const -{ - return m_topRight; -} - -void CornersGroup::setTopRight( qreal newTopRight ) -{ - if( newTopRight == m_topRight ) - { - return; - } - - m_topRight = newTopRight; - Q_EMIT changed(); -} - -qreal CornersGroup::bottomLeft() const -{ - return m_bottomLeft; -} - -void CornersGroup::setBottomLeft( qreal newBottomLeft ) -{ - if( newBottomLeft == m_bottomLeft ) - { - return; - } - - m_bottomLeft = newBottomLeft; - Q_EMIT changed(); -} - -qreal CornersGroup::bottomRight() const -{ - return m_bottomRight; -} - -void CornersGroup::setBottomRight( qreal newBottomRight ) -{ - if( newBottomRight == m_bottomRight ) - { - return; - } - - m_bottomRight = newBottomRight; - Q_EMIT changed(); -} - -QVector4D CornersGroup::toVector4D( float all ) const -{ - return QVector4D - { - m_bottomRight < 0.0 ? all : m_bottomRight, - m_topRight < 0.0 ? all : m_topRight, - m_bottomLeft < 0.0 ? all : m_bottomLeft, - m_topLeft < 0.0 ? all : m_topLeft - }; -} - -ShadowedRectangle::ShadowedRectangle( QQuickItem* parentItem ) - : QQuickItem( parentItem ) - , m_border( new BorderGroup ) - , m_shadow( new ShadowGroup ) - , m_corners( new CornersGroup ) -{ - setFlag( QQuickItem::ItemHasContents, true ); - - connect( m_border.get(), &BorderGroup::changed, this, &ShadowedRectangle::update ); - connect( m_shadow.get(), &ShadowGroup::changed, this, &ShadowedRectangle::update ); - connect( m_corners.get(), &CornersGroup::changed, this, &ShadowedRectangle::update ); -} - -ShadowedRectangle::~ShadowedRectangle() -{ -} - -BorderGroup* ShadowedRectangle::border() const -{ - return m_border.get(); -} - -ShadowGroup* ShadowedRectangle::shadow() const -{ - return m_shadow.get(); -} - -CornersGroup* ShadowedRectangle::corners() const -{ - return m_corners.get(); -} - -qreal ShadowedRectangle::radius() const -{ - return m_radius; -} - -void ShadowedRectangle::setRadius( qreal newRadius ) -{ - if( newRadius == m_radius ) - { - return; - } - - m_radius = newRadius; - - if( !isSoftwareRendering() ) - { - update(); - } - - Q_EMIT radiusChanged(); -} - -QColor ShadowedRectangle::color() const -{ - return m_color; -} - -void ShadowedRectangle::setColor( const QColor& newColor ) -{ - if( newColor == m_color ) - { - return; - } - - m_color = newColor; - - if( !isSoftwareRendering() ) - { - update(); - } - - Q_EMIT colorChanged(); -} - -void ShadowedRectangle::componentComplete() -{ - QQuickItem::componentComplete(); - - checkSoftwareItem(); -} - -bool ShadowedRectangle::isSoftwareRendering() const -{ - return false; -} - -PaintedRectangleItem* ShadowedRectangle::softwareItem() const -{ - return m_softwareItem; -} - -void ShadowedRectangle::itemChange( QQuickItem::ItemChange change, const QQuickItem::ItemChangeData& value ) -{ - if( change == QQuickItem::ItemSceneChange && value.window ) - { - checkSoftwareItem(); - //TODO: only conditionally emit? - Q_EMIT softwareRenderingChanged(); - } -} - -QSGNode* ShadowedRectangle::updatePaintNode( QSGNode* node, QQuickItem::UpdatePaintNodeData* data ) -{ - Q_UNUSED( data ); - - auto shadowNode = static_cast( node ); - - if( !shadowNode ) - { - shadowNode = new ShadowedRectangleNode{}; - - // Cache lowPower state so we only execute the full check once. - static bool lowPower = QByteArrayList{"1", "true"}.contains( qgetenv( "KIRIGAMI_LOWPOWER_HARDWARE" ).toLower() ); - - if( lowPower ) - { - shadowNode->setShaderType( ShadowedRectangleMaterial::ShaderType::LowPower ); - } - } - - shadowNode->setBorderEnabled( m_border->isEnabled() ); - shadowNode->setRect( boundingRect() ); - shadowNode->setSize( m_shadow->size() ); - shadowNode->setRadius( m_corners->toVector4D( m_radius ) ); - shadowNode->setOffset( QVector2D{float( m_shadow->xOffset() ), float( m_shadow->yOffset() )} ); - shadowNode->setColor( m_color ); - shadowNode->setShadowColor( m_shadow->color() ); - shadowNode->setBorderWidth( m_border->width() ); - shadowNode->setBorderColor( m_border->color() ); - shadowNode->updateGeometry(); - return shadowNode; -} - -void ShadowedRectangle::checkSoftwareItem() -{ - if( !m_softwareItem && isSoftwareRendering() ) - { - m_softwareItem = new PaintedRectangleItem{this}; - // The software item is added as a "normal" child item, this means it - // will be part of the normal item sort order. Since there is no way to - // control the ordering of children, just make sure to have a very low Z - // value for the child, to force it to be the lowest item. - m_softwareItem->setZ( -99.0 ); - - auto updateItem = [this]() - { - auto borderWidth = m_border->width(); - auto rect = boundingRect().adjusted( -borderWidth / 2, -borderWidth / 2, borderWidth / 2, borderWidth / 2 ); - m_softwareItem->setX( -borderWidth / 2 ); - m_softwareItem->setY( -borderWidth / 2 ); - m_softwareItem->setSize( rect.size() ); - m_softwareItem->setColor( m_color ); - m_softwareItem->setRadius( m_radius ); - m_softwareItem->setBorderWidth( borderWidth ); - m_softwareItem->setBorderColor( m_border->color() ); - }; - - updateItem(); - - connect( this, &ShadowedRectangle::widthChanged, m_softwareItem, updateItem ); - connect( this, &ShadowedRectangle::heightChanged, m_softwareItem, updateItem ); - connect( this, &ShadowedRectangle::colorChanged, m_softwareItem, updateItem ); - connect( this, &ShadowedRectangle::radiusChanged, m_softwareItem, updateItem ); - connect( m_border.get(), &BorderGroup::changed, m_softwareItem, updateItem ); - setFlag( QQuickItem::ItemHasContents, false ); - } -} diff --git a/examples/iotdashboard/kirigami/shadowedrectangle.h b/examples/iotdashboard/kirigami/shadowedrectangle.h deleted file mode 100644 index 4162af52..00000000 --- a/examples/iotdashboard/kirigami/shadowedrectangle.h +++ /dev/null @@ -1,256 +0,0 @@ -/* - * SPDX-FileCopyrightText: 2020 Arjen Hiemstra - * - * SPDX-License-Identifier: LGPL-2.0-or-later - */ - -#pragma once - -#include -#include - -class PaintedRectangleItem; - -/** - * Grouped property for rectangle border. - */ -class BorderGroup : public QObject -{ - Q_OBJECT - /** - * The width of the border in pixels. - * - * Default is 0. - */ - Q_PROPERTY(qreal width READ width WRITE setWidth NOTIFY changed) - /** - * The color of the border. - * - * Full RGBA colors are supported. The default is fully opaque black. - */ - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed) - -public: - explicit BorderGroup(QObject *parent = nullptr); - - qreal width() const; - void setWidth(qreal newWidth); - - QColor color() const; - void setColor(const QColor &newColor); - - Q_SIGNAL void changed(); - - inline bool isEnabled() const - { - return !qFuzzyIsNull(m_width); - } - -private: - qreal m_width = 0.0; - QColor m_color = Qt::black; -}; - -/** - * Grouped property for rectangle shadow. - */ -class ShadowGroup : public QObject -{ - Q_OBJECT - /** - * The size of the shadow. - * - * This is the approximate size of the shadow in pixels. However, due to falloff - * the actual shadow size can differ. The default is 0, which means no shadow will - * be rendered. - */ - Q_PROPERTY(qreal size READ size WRITE setSize NOTIFY changed) - /** - * Offset of the shadow on the X axis. - * - * In pixels. The default is 0. - */ - Q_PROPERTY(qreal xOffset READ xOffset WRITE setXOffset NOTIFY changed) - /** - * Offset of the shadow on the Y axis. - * - * In pixels. The default is 0. - */ - Q_PROPERTY(qreal yOffset READ yOffset WRITE setYOffset NOTIFY changed) - /** - * The color of the shadow. - * - * Full RGBA colors are supported. The default is fully opaque black. - */ - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY changed) - -public: - explicit ShadowGroup(QObject *parent = nullptr); - - qreal size() const; - void setSize(qreal newSize); - - qreal xOffset() const; - void setXOffset(qreal newXOffset); - - qreal yOffset() const; - void setYOffset(qreal newYOffset); - - QColor color() const; - void setColor(const QColor &newShadowColor); - - Q_SIGNAL void changed(); - -private: - qreal m_size = 0.0; - qreal m_xOffset = 0.0; - qreal m_yOffset = 0.0; - QColor m_color = Qt::black; -}; - -/** - * Grouped property for corner radius. - */ -class CornersGroup : public QObject -{ - Q_OBJECT - /** - * The radius of the top-left corner. - * - * In pixels. Defaults to -1, which indicates this value should not be used. - */ - Q_PROPERTY(qreal topLeftRadius READ topLeft WRITE setTopLeft NOTIFY changed) - /** - * The radius of the top-right corner. - * - * In pixels. Defaults to -1, which indicates this value should not be used. - */ - Q_PROPERTY(qreal topRightRadius READ topRight WRITE setTopRight NOTIFY changed) - /** - * The radius of the bottom-left corner. - * - * In pixels. Defaults to -1, which indicates this value should not be used. - */ - Q_PROPERTY(qreal bottomLeftRadius READ bottomLeft WRITE setBottomLeft NOTIFY changed) - /** - * The radius of the bottom-right corner. - * - * In pixels. Defaults to -1, which indicates this value should not be used. - */ - Q_PROPERTY(qreal bottomRightRadius READ bottomRight WRITE setBottomRight NOTIFY changed) - -public: - explicit CornersGroup(QObject *parent = nullptr); - - qreal topLeft() const; - void setTopLeft(qreal newTopLeft); - - qreal topRight() const; - void setTopRight(qreal newTopRight); - - qreal bottomLeft() const; - void setBottomLeft(qreal newBottomLeft); - - qreal bottomRight() const; - void setBottomRight(qreal newBottomRight); - - Q_SIGNAL void changed(); - - QVector4D toVector4D(float all) const; - -private: - float m_topLeft = -1.0; - float m_topRight = -1.0; - float m_bottomLeft = -1.0; - float m_bottomRight = -1.0; -}; - -/** - * A rectangle with a shadow. - * - * This item will render a rectangle, with a shadow below it. The rendering is done - * using distance fields, which provide greatly improved performance. The shadow is - * rendered outside of the item's bounds, so the item's width and height are the - * rectangle's width and height. - * - * @since 5.69 / 2.12 - */ -class ShadowedRectangle : public QQuickItem -{ - Q_OBJECT - /** - * Corner radius of the rectangle. - * - * This is the amount of rounding to apply to all of the rectangle's - * corners, in pixels. Individual corners can have a different radius, see - * \property corners. - * - * The default is 0. - */ - Q_PROPERTY(qreal radius READ radius WRITE setRadius NOTIFY radiusChanged) - /** - * The color of the rectangle. - * - * Full RGBA colors are supported. The default is fully opaque white. - */ - Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) - /** - * Border properties. - * - * \sa BorderGroup - */ - Q_PROPERTY(BorderGroup *border READ border CONSTANT) - /** - * Shadow properties. - * - * \sa ShadowGroup - */ - Q_PROPERTY(ShadowGroup *shadow READ shadow CONSTANT) - /** - * Corner radius. - * - * Note that the values from this group override \property radius for the - * corner they affect. - * - * \sa CornerGroup - */ - Q_PROPERTY(CornersGroup *corners READ corners CONSTANT) - - Q_PROPERTY(bool softwareRendering READ isSoftwareRendering NOTIFY softwareRenderingChanged) -public: - ShadowedRectangle(QQuickItem *parent = nullptr); - ~ShadowedRectangle() override; - - BorderGroup *border() const; - ShadowGroup *shadow() const; - CornersGroup *corners() const; - - qreal radius() const; - void setRadius(qreal newRadius); - Q_SIGNAL void radiusChanged(); - - QColor color() const; - void setColor(const QColor &newColor); - Q_SIGNAL void colorChanged(); - - void componentComplete() override; - - bool isSoftwareRendering() const; - -Q_SIGNALS: - void softwareRenderingChanged(); - -protected: - PaintedRectangleItem *softwareItem() const; - void itemChange(QQuickItem::ItemChange change, const QQuickItem::ItemChangeData &value) override; - QSGNode *updatePaintNode(QSGNode *node, QQuickItem::UpdatePaintNodeData *data) override; - -private: - void checkSoftwareItem(); - const std::unique_ptr m_border; - const std::unique_ptr m_shadow; - const std::unique_ptr m_corners; - qreal m_radius = 0.0; - QColor m_color = Qt::white; - PaintedRectangleItem *m_softwareItem = nullptr; -}; diff --git a/examples/iotdashboard/nodes/BoxShadowNode.cpp b/examples/iotdashboard/nodes/BoxShadowNode.cpp new file mode 100644 index 00000000..b7a0433f --- /dev/null +++ b/examples/iotdashboard/nodes/BoxShadowNode.cpp @@ -0,0 +1,257 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#include "BoxShadowNode.h" +#include "QskBoxShapeMetrics.h" + +#include +#include +#include + +#include + +namespace +{ + class Shader final : public QSGMaterialShader + { + public: + Shader(); + + char const* const* attributeNames() const override; + + void initialize() override; + + void updateState( const QSGMaterialShader::RenderState& state, + QSGMaterial* newMaterial, QSGMaterial* oldMaterial) override; + + private: + int m_matrixId = -1; + int m_opacityId = -1; + int m_aspectId = -1; + int m_blurExtentId = -1; + int m_radiusId = -1; + int m_colorId = -1; + }; + + class Material final : public QSGMaterial + { + public: + Material(); + + QSGMaterialShader* createShader() const override; + + QSGMaterialType* type() const override; + + int compare( const QSGMaterial* other ) const override; + + QVector2D aspect = QVector2D{1.0, 1.0}; + float blurExtent = 0.0; + QVector4D radius = QVector4D{0.0, 0.0, 0.0, 0.0}; + QColor color = Qt::black; + }; + + Shader::Shader() + { + const QString root( ":/iotdashboard/shaders/" ); + + setShaderSourceFile( QOpenGLShader::Vertex, root + "boxshadow.vert" ); + setShaderSourceFile( QOpenGLShader::Fragment, root + "boxshadow.frag" ); + } + + char const* const* Shader::attributeNames() const + { + static char const* const names[] = { "in_vertex", "in_coord", nullptr }; + return names; + } + + void Shader::initialize() + { + QSGMaterialShader::initialize(); + + auto p = program(); + + m_matrixId = p->uniformLocation( "matrix" ); + m_aspectId = p->uniformLocation( "aspect" ); + m_opacityId = p->uniformLocation( "opacity" ); + m_blurExtentId = p->uniformLocation( "blurExtent" ); + m_radiusId = p->uniformLocation( "radius" ); + m_colorId = p->uniformLocation( "color" ); + } + + void Shader::updateState( const QSGMaterialShader::RenderState& state, + QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) + { + auto p = program(); + + if ( state.isMatrixDirty() ) + p->setUniformValue( m_matrixId, state.combinedMatrix() ); + + if ( state.isOpacityDirty() ) + p->setUniformValue( m_opacityId, state.opacity() ); + + if ( oldMaterial == nullptr || newMaterial->compare( oldMaterial ) != 0 + || state.isCachedMaterialDataDirty( )) + { + auto material = static_cast< const Material* >( newMaterial ); + + p->setUniformValue( m_aspectId, material->aspect ); + p->setUniformValue( m_blurExtentId, material->blurExtent); + p->setUniformValue( m_radiusId, material->radius ); + p->setUniformValue( m_colorId, material->color ); + } + } + + Material::Material() + { + setFlag( QSGMaterial::Blending, true ); + } + + QSGMaterialShader* Material::createShader() const + { + return new Shader(); + } + + QSGMaterialType* Material::type() const + { + static QSGMaterialType staticType; + return &staticType; + } + + int Material::compare( const QSGMaterial* other ) const + { + auto material = static_cast< const Material* >( other ); + + if ( material->color == color + && material->aspect == aspect + && qFuzzyCompare(material->blurExtent, blurExtent) + && qFuzzyCompare(material->radius, radius) ) + { + return 0; + } + + return QSGMaterial::compare(other); + } +} + +class BoxShadowNodePrivate final : public QSGGeometryNodePrivate +{ + public: + BoxShadowNodePrivate() + : geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 ) + { + } + + QSGGeometry geometry; + Material material; + + QRectF rect; +}; + +BoxShadowNode::BoxShadowNode() + : QSGGeometryNode( *new BoxShadowNodePrivate ) +{ + Q_D( BoxShadowNode ); + + setGeometry( &d->geometry ); + setMaterial( &d->material ); +} + +BoxShadowNode::~BoxShadowNode() +{ +} + +void BoxShadowNode::setRect( const QRectF& rect ) +{ + Q_D( BoxShadowNode ); + + if ( rect == d->rect ) + return; + + d->rect = rect; + + QVector2D aspect( 1.0, 1.0 ); + + if ( rect.width() >= rect.height() ) + aspect.setX( rect.width() / rect.height() ); + else + aspect.setY( rect.height() / rect.width() ); + + if ( d->material.aspect != aspect ) + { + d->material.aspect = aspect; + markDirty( QSGNode::DirtyMaterial ); + } +} + +void BoxShadowNode::setShape( const QskBoxShapeMetrics& shape ) +{ + Q_D( BoxShadowNode ); + + const float t = std::min( d->rect.width(), d->rect.height() ); + + const float r1 = shape.radius( Qt::BottomRightCorner ).width(); + const float r2 = shape.radius( Qt::TopRightCorner ).width(); + const float r3 = shape.radius( Qt::BottomLeftCorner ).width(); + const float r4 = shape.radius( Qt::TopLeftCorner ).width(); + + const auto uniformRadius = QVector4D( + std::min( r1 / t, 1.0f ), std::min( r2 / t, 1.0f ), + std::min( r3 / t, 1.0f ), std::min( r4 / t, 1.0f ) ); + + if ( d->material.radius != uniformRadius ) + { + d->material.radius = uniformRadius; + + markDirty( QSGNode::DirtyMaterial ); + } +} + +void BoxShadowNode::setColor( const QColor& color ) +{ + Q_D( BoxShadowNode ); + + const auto a = color.alphaF(); + + const auto c = QColor::fromRgbF( + color.redF() * a, color.greenF() * a, color.blueF() * a, a ); + + if ( d->material.color != c ) + { + d->material.color = c; + markDirty( QSGNode::DirtyMaterial ); + } +} + +void BoxShadowNode::setBlurRadius( qreal blurRadius ) +{ + Q_D( BoxShadowNode ); + + if ( blurRadius <= 0.0 ) + blurRadius = 0.0; + + const float t = 0.5 * std::min( d->rect.width(), d->rect.height() ); + const float uniformExtent = blurRadius / t; + + if ( !qFuzzyCompare( d->material.blurExtent, uniformExtent ) ) + { + d->material.blurExtent = uniformExtent; + markDirty( QSGNode::DirtyMaterial ); + } +} + +void BoxShadowNode::setClipRect( const QRectF& rect ) +{ + Q_UNUSED( rect ) +} + +void BoxShadowNode::updateGeometry() +{ + Q_D( BoxShadowNode ); + + QSGGeometry::updateTexturedRectGeometry( + &d->geometry, d->rect, QRectF( -0.5, -0.5, 1.0, 1.0 ) ); + + markDirty( QSGNode::DirtyGeometry ); +} diff --git a/examples/iotdashboard/nodes/BoxShadowNode.h b/examples/iotdashboard/nodes/BoxShadowNode.h new file mode 100644 index 00000000..bd84a5eb --- /dev/null +++ b/examples/iotdashboard/nodes/BoxShadowNode.h @@ -0,0 +1,32 @@ +/****************************************************************************** + * QSkinny - Copyright (C) 2016 Uwe Rathmann + * This file may be used under the terms of the 3-clause BSD License + *****************************************************************************/ + +#pragma once + +#include + +class QColor; +class QskBoxShapeMetrics; + +class BoxShadowNodePrivate; + +class BoxShadowNode : public QSGGeometryNode +{ + public: + BoxShadowNode(); + ~BoxShadowNode() override; + + void setRect( const QRectF& ); + void setShape( const QskBoxShapeMetrics& ); + void setColor( const QColor& ); + void setBlurRadius( qreal ); + + void setClipRect( const QRectF& ); + + void updateGeometry(); + + private: + Q_DECLARE_PRIVATE( BoxShadowNode ) +}; diff --git a/examples/iotdashboard/shaders.qrc b/examples/iotdashboard/shaders.qrc new file mode 100644 index 00000000..fa597692 --- /dev/null +++ b/examples/iotdashboard/shaders.qrc @@ -0,0 +1,7 @@ + + + + shaders/boxshadow.vert + shaders/boxshadow.frag + + diff --git a/examples/iotdashboard/shaders/boxshadow.frag b/examples/iotdashboard/shaders/boxshadow.frag new file mode 100644 index 00000000..b24ff185 --- /dev/null +++ b/examples/iotdashboard/shaders/boxshadow.frag @@ -0,0 +1,42 @@ +uniform lowp float opacity; +uniform lowp float blurExtent; +uniform lowp vec4 radius; +uniform lowp vec4 color; +uniform lowp vec2 aspect; + +varying lowp vec2 coord; + +lowp float effectiveRadius( in lowp vec4 radii, in lowp vec2 point ) +{ + if ( point.x > 0.0 ) + return ( point.y > 0.0) ? radii.x : radii.y; + else + return ( point.y > 0.0) ? radii.z : radii.w; +} + +void main() +{ + lowp vec4 col = vec4(0.0); + + if ( opacity > 0.0 ) + { + const lowp float minRadius = 0.05; + + lowp float e2 = 0.5 * blurExtent; + lowp float r = 2.0 * effectiveRadius( radius, coord ); + + lowp float f = minRadius / max( r, minRadius ); + + r += e2 * f; + + lowp vec2 d = r + blurExtent - aspect * ( 1.0 - abs( 2.0 * coord ) ); + lowp float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) ); + + lowp float shadow = l - r; + + lowp float v = smoothstep( -e2, e2, shadow ); + col = mix( color, vec4(0.0), v ) * opacity; + } + + gl_FragColor = col; +} diff --git a/examples/iotdashboard/shaders/boxshadow.vert b/examples/iotdashboard/shaders/boxshadow.vert new file mode 100644 index 00000000..5a55b751 --- /dev/null +++ b/examples/iotdashboard/shaders/boxshadow.vert @@ -0,0 +1,13 @@ +uniform highp mat4 matrix; +uniform lowp vec2 aspect; + +attribute highp vec4 in_vertex; +attribute mediump vec2 in_coord; + +varying mediump vec2 coord; + +void main() +{ + coord = in_coord; + gl_Position = matrix * in_vertex; +}