add QskArcShadowNode infrastructure
This commit is contained in:
parent
8d74b08c08
commit
eb18c58830
|
|
@ -287,7 +287,7 @@ namespace
|
||||||
auto sliderStart = new SliderBox( "Angle", 0.0, 360.0, metrics.startAngle() );
|
auto sliderStart = new SliderBox( "Angle", 0.0, 360.0, metrics.startAngle() );
|
||||||
auto sliderSpan = new SliderBox( "Span", -360.0, 360.0, metrics.spanAngle() );
|
auto sliderSpan = new SliderBox( "Span", -360.0, 360.0, metrics.spanAngle() );
|
||||||
auto sliderExtent = new SliderBox( "Extent", 10.0, 100.0, metrics.thickness() );
|
auto sliderExtent = new SliderBox( "Extent", 10.0, 100.0, metrics.thickness() );
|
||||||
auto shadowExtent = new SliderBox( "Shadow Extent", 0.0, 100.0, 50 );
|
auto shadowExtent = new SliderBox( "Shadow Extent", 0.0, 1.0, 0.5 );
|
||||||
auto sliderOffsetX = new SliderBox( "Offset X", -1.0, +1.0, 0 );
|
auto sliderOffsetX = new SliderBox( "Offset X", -1.0, +1.0, 0 );
|
||||||
auto sliderOffsetY = new SliderBox( "Offset Y", -1.0, +1.0, 0 );
|
auto sliderOffsetY = new SliderBox( "Offset Y", -1.0, +1.0, 0 );
|
||||||
auto sliderStrokeWidth = new SliderBox( "Stroke Width", 0, 10, 1 );
|
auto sliderStrokeWidth = new SliderBox( "Stroke Width", 0, 10, 1 );
|
||||||
|
|
@ -421,6 +421,7 @@ ChartView::ChartView( ArcControl* chart, QQuickItem* parent )
|
||||||
// legend->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
|
// legend->setSizePolicy( QskSizePolicy::Fixed, QskSizePolicy::Fixed );
|
||||||
// legend->setSamples( chart->series() );
|
// legend->setSamples( chart->series() );
|
||||||
hBox->addItem(chart);
|
hBox->addItem(chart);
|
||||||
|
hBox->setDefaultAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
auto controlPanel = new ControlPanel( chart->arcMetricsHint(QskControl::Background) );
|
auto controlPanel = new ControlPanel( chart->arcMetricsHint(QskControl::Background) );
|
||||||
controlPanel->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
|
controlPanel->setSizePolicy( Qt::Vertical, QskSizePolicy::Fixed );
|
||||||
|
|
|
||||||
|
|
@ -129,16 +129,16 @@ int main( int argc, char* argv[] )
|
||||||
metrics.setThickness(10);
|
metrics.setThickness(10);
|
||||||
|
|
||||||
QskShadowMetrics shadowMetrics;
|
QskShadowMetrics shadowMetrics;
|
||||||
shadowMetrics.setSpreadRadius(10);
|
shadowMetrics.setSpreadRadius(0.1);
|
||||||
shadowMetrics.setSizeMode(Qt::SizeMode::RelativeSize);
|
shadowMetrics.setSizeMode(Qt::SizeMode::RelativeSize);
|
||||||
|
|
||||||
control->setBackgroundColor(Qt::white);
|
|
||||||
control->setGradientHint(Q::Arc, {Qt::red});
|
control->setGradientHint(Q::Arc, {Qt::red});
|
||||||
control->setArcMetricsHint(Q::Arc, metrics);
|
control->setArcMetricsHint(Q::Arc, metrics);
|
||||||
control->setMetric(Q::Arc | QskAspect::Border, 4);
|
control->setMetric(Q::Arc | QskAspect::Border, 4);
|
||||||
control->setColor(Q::Arc | QskAspect::Border, Qt::blue);
|
control->setColor(Q::Arc | QskAspect::Border, Qt::blue);
|
||||||
control->setShadowColorHint(Q::Arc, Qt::blue);
|
control->setShadowColorHint(Q::Arc, Qt::black);
|
||||||
control->setShadowMetricsHint(Q::Arc, shadowMetrics);
|
control->setShadowMetricsHint(Q::Arc, shadowMetrics);
|
||||||
|
control->setFixedSize( 300, 250 );
|
||||||
|
|
||||||
QskWindow window;
|
QskWindow window;
|
||||||
window.addItem( new ChartView( control ) );
|
window.addItem( new ChartView( control ) );
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ list(APPEND SOURCES
|
||||||
|
|
||||||
list(APPEND HEADERS
|
list(APPEND HEADERS
|
||||||
nodes/QskArcNode.h
|
nodes/QskArcNode.h
|
||||||
|
nodes/QskArcShadowNode.h
|
||||||
nodes/QskBasicLinesNode.h
|
nodes/QskBasicLinesNode.h
|
||||||
nodes/QskBoxNode.h
|
nodes/QskBoxNode.h
|
||||||
nodes/QskBoxClipNode.h
|
nodes/QskBoxClipNode.h
|
||||||
|
|
@ -136,6 +137,7 @@ list(APPEND PRIVATE_HEADERS
|
||||||
|
|
||||||
list(APPEND SOURCES
|
list(APPEND SOURCES
|
||||||
nodes/QskArcNode.cpp
|
nodes/QskArcNode.cpp
|
||||||
|
nodes/QskArcShadowNode.cpp
|
||||||
nodes/QskBasicLinesNode.cpp
|
nodes/QskBasicLinesNode.cpp
|
||||||
nodes/QskBoxNode.cpp
|
nodes/QskBoxNode.cpp
|
||||||
nodes/QskBoxClipNode.cpp
|
nodes/QskBoxClipNode.cpp
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include "QskArcNode.h"
|
#include "QskArcNode.h"
|
||||||
#include "QskArcMetrics.h"
|
#include "QskArcMetrics.h"
|
||||||
|
#include "QskArcShadowNode.h"
|
||||||
#include "QskMargins.h"
|
#include "QskMargins.h"
|
||||||
#include "QskGradient.h"
|
#include "QskGradient.h"
|
||||||
#include "QskShapeNode.h"
|
#include "QskShapeNode.h"
|
||||||
|
|
@ -20,105 +21,6 @@
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <qmath.h>
|
#include <qmath.h>
|
||||||
|
|
||||||
namespace
|
|
||||||
{
|
|
||||||
struct QskArcShadowMaterialProperties
|
|
||||||
{
|
|
||||||
QColor color = Qt::red;
|
|
||||||
QRectF rect;
|
|
||||||
QPointF offset;
|
|
||||||
qreal radius = 1.0; // [0.0,1.0]
|
|
||||||
qreal thickness = 0.2;
|
|
||||||
qreal startAngle = 0.0; //< degree [0.0,360.0]
|
|
||||||
qreal spanAngle = 270.0; //< degree [0.0,360.0]
|
|
||||||
qreal extend = 16.0; //< pixel >= 0.0
|
|
||||||
};
|
|
||||||
|
|
||||||
class QskArcShadowMaterial final : public QSGSimpleMaterialShader<QskArcShadowMaterialProperties>
|
|
||||||
{
|
|
||||||
QSG_DECLARE_SIMPLE_SHADER(QskArcShadowMaterial, QskArcShadowMaterialProperties)
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
QskArcShadowMaterial()
|
|
||||||
{
|
|
||||||
const QString root( ":/qskinny/shaders/" );
|
|
||||||
setShaderSourceFile( QOpenGLShader::Vertex, root + "arcshadow.vert" );
|
|
||||||
setShaderSourceFile( QOpenGLShader::Fragment, root + "arcshadow.frag" );
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<QByteArray> attributes() const override {
|
|
||||||
return QList<QByteArray>() << "vertex";
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateState( const QskArcShadowMaterialProperties* newState,
|
|
||||||
const QskArcShadowMaterialProperties* oldState ) override
|
|
||||||
{
|
|
||||||
std::ignore = oldState;
|
|
||||||
|
|
||||||
const auto& color = newState->color;
|
|
||||||
const auto& rect = newState->rect;
|
|
||||||
const auto& radius = newState->radius;
|
|
||||||
const auto& thickness = newState->thickness;
|
|
||||||
const auto& startAngle = newState->startAngle;
|
|
||||||
const auto& spanAngle = newState->spanAngle;
|
|
||||||
const auto& extend = newState->extend;
|
|
||||||
const auto& offset = newState->offset;
|
|
||||||
|
|
||||||
auto& p = *program();
|
|
||||||
p.setUniformValue( "color", color.redF(), color.greenF(), color.blueF(), 1.0f );
|
|
||||||
p.setUniformValue( "rect", rect.x(), rect.y(), rect.width(), rect.height() );
|
|
||||||
p.setUniformValue( "radius", ( float ) radius );
|
|
||||||
p.setUniformValue( "thickness", ( float ) thickness );
|
|
||||||
p.setUniformValue( "startAngle", ( float ) startAngle - 90.0f );
|
|
||||||
p.setUniformValue( "spanAngle", ( float ) spanAngle );
|
|
||||||
p.setUniformValue( "extend", ( float ) extend );
|
|
||||||
p.setUniformValue( "offset", ( float ) offset.x(), ( float ) offset.y() );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
class QskArcShadowNode : public QSGGeometryNode
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
QskArcShadowNode() : m_geometry(QSGGeometry::defaultAttributes_Point2D(), 4)
|
|
||||||
{
|
|
||||||
setGeometry(&m_geometry);
|
|
||||||
setMaterial(QskArcShadowMaterial::createMaterial());
|
|
||||||
m_geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
|
|
||||||
material()->setFlag(QSGMaterial::Blending);
|
|
||||||
}
|
|
||||||
|
|
||||||
void update(const QRectF& rect, const QskArcMetrics& metrics, const QColor& color, const QskShadowMetrics& shadowMetrics = {}, const qreal borderWidth = 0.0)
|
|
||||||
{
|
|
||||||
auto* const vertices = geometry()->vertexDataAsPoint2D();
|
|
||||||
const auto b = borderWidth / 2;
|
|
||||||
const auto r = rect.adjusted( -b, -b, +b, +b );
|
|
||||||
vertices[0].set(r.left(), r.top());
|
|
||||||
vertices[1].set(r.left(), r.bottom());
|
|
||||||
vertices[2].set(r.right(), r.top());
|
|
||||||
vertices[3].set(r.right(), r.bottom());
|
|
||||||
markDirty( QSGNode::DirtyGeometry );
|
|
||||||
|
|
||||||
const auto size = qMin(r.width(), r.height());
|
|
||||||
auto* const material = static_cast<QSGSimpleMaterial< QskArcShadowMaterialProperties >*>(this->material());
|
|
||||||
auto& state = *material->state();
|
|
||||||
state.color = color;
|
|
||||||
state.rect = r;
|
|
||||||
state.radius = 1.0 - (metrics.thickness() + borderWidth) / size;
|
|
||||||
state.thickness = 2 * metrics.thickness() / size;
|
|
||||||
state.startAngle = metrics.startAngle();
|
|
||||||
state.spanAngle = metrics.spanAngle();
|
|
||||||
state.extend = shadowMetrics.spreadRadius();
|
|
||||||
state.offset = shadowMetrics.offset();
|
|
||||||
markDirty( QSGNode::DirtyMaterial );
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
QSGGeometry m_geometry;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static inline QskGradient qskEffectiveGradient(
|
static inline QskGradient qskEffectiveGradient(
|
||||||
const QskGradient& gradient, const QskArcMetrics& metrics )
|
const QskGradient& gradient, const QskArcMetrics& metrics )
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,371 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "QskArcShadowNode.h"
|
||||||
|
#include "QskArcMetrics.h"
|
||||||
|
#include "QskShadowMetrics.h"
|
||||||
|
|
||||||
|
#include <qcolor.h>
|
||||||
|
#include <qsgmaterial.h>
|
||||||
|
#include <qsgmaterialshader.h>
|
||||||
|
#include <qmath.h>
|
||||||
|
|
||||||
|
QSK_QT_PRIVATE_BEGIN
|
||||||
|
#include <private/qsgnode_p.h>
|
||||||
|
QSK_QT_PRIVATE_END
|
||||||
|
|
||||||
|
// QSGMaterialRhiShader became QSGMaterialShader in Qt6
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
#include <QSGMaterialRhiShader>
|
||||||
|
using RhiShader = QSGMaterialRhiShader;
|
||||||
|
#else
|
||||||
|
using RhiShader = QSGMaterialShader;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
struct MaterialProperties
|
||||||
|
{
|
||||||
|
QVector4D color{ 0, 0, 0, 1 };
|
||||||
|
QVector2D offset;
|
||||||
|
float radius = 1.0f;
|
||||||
|
float thickness = 0.0f;
|
||||||
|
float startAngle = 0.0f;
|
||||||
|
float spanAngle = M_PI;
|
||||||
|
float extend = 0.0f;
|
||||||
|
|
||||||
|
Q_REQUIRED_RESULT inline bool operator==(const MaterialProperties& rhs) const noexcept
|
||||||
|
{
|
||||||
|
return color == rhs.color && offset == rhs.offset &&
|
||||||
|
radius == rhs.radius && thickness == rhs.thickness &&
|
||||||
|
startAngle == rhs.startAngle && spanAngle == rhs.spanAngle &&
|
||||||
|
extend == rhs.extend;
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_REQUIRED_RESULT inline bool operator!=(const MaterialProperties& rhs) const noexcept
|
||||||
|
{
|
||||||
|
return !(*this == rhs);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Material final : public QSGMaterial
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Material();
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
QSGMaterialShader* createShader() const override;
|
||||||
|
#else
|
||||||
|
QSGMaterialShader* createShader( QSGRendererInterface::RenderMode ) const override;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QSGMaterialType* type() const override;
|
||||||
|
int compare( const QSGMaterial* other ) const override;
|
||||||
|
|
||||||
|
MaterialProperties properties;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class ShaderRhi final : public RhiShader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShaderRhi()
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
bool updateUniformData( RenderState& state,
|
||||||
|
QSGMaterial* newMaterial, QSGMaterial* oldMaterial ) override
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// the old type of shader - specific for OpenGL
|
||||||
|
|
||||||
|
class ShaderGL final : public QSGMaterialShader
|
||||||
|
{
|
||||||
|
struct Uniforms
|
||||||
|
{
|
||||||
|
int matrix = -1;
|
||||||
|
int opacity = -1;
|
||||||
|
int color = -1;
|
||||||
|
int offset = -1;
|
||||||
|
int radius = -1;
|
||||||
|
int thickness = -1;
|
||||||
|
int startAngle = -1;
|
||||||
|
int spanAngle = -1;
|
||||||
|
int extend = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
ShaderGL()
|
||||||
|
{
|
||||||
|
const QString root( ":/qskinny/shaders/" );
|
||||||
|
setShaderSourceFile( QOpenGLShader::Vertex, root + "arcshadow.vert" );
|
||||||
|
setShaderSourceFile( QOpenGLShader::Fragment, root + "arcshadow.frag" );
|
||||||
|
}
|
||||||
|
|
||||||
|
char const* const* attributeNames() const override
|
||||||
|
{
|
||||||
|
static char const* const names[] = { "in_vertex", "in_coord", nullptr };
|
||||||
|
return names;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize() override
|
||||||
|
{
|
||||||
|
QSGMaterialShader::initialize();
|
||||||
|
|
||||||
|
const auto* const p = program();
|
||||||
|
id.matrix = p->uniformLocation( "matrix" );
|
||||||
|
id.opacity = p->uniformLocation( "opacity" );
|
||||||
|
id.color = p->uniformLocation( "color" );
|
||||||
|
id.offset = p->uniformLocation( "offset" );
|
||||||
|
id.radius = p->uniformLocation( "radius" );
|
||||||
|
id.thickness = p->uniformLocation( "thickness" );
|
||||||
|
id.startAngle = p->uniformLocation( "startAngle" );
|
||||||
|
id.spanAngle = p->uniformLocation( "spanAngle" );
|
||||||
|
id.extend = p->uniformLocation( "extend" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateState( const QSGMaterialShader::RenderState& state,
|
||||||
|
QSGMaterial* const newMaterial, QSGMaterial* const oldMaterial) override
|
||||||
|
{
|
||||||
|
auto* const p = program();
|
||||||
|
|
||||||
|
if ( state.isMatrixDirty() )
|
||||||
|
{
|
||||||
|
p->setUniformValue( id.matrix, state.combinedMatrix() );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( state.isOpacityDirty() )
|
||||||
|
{
|
||||||
|
p->setUniformValue( id.opacity, state.opacity() );
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto updateMaterial = ( oldMaterial == nullptr ) ||
|
||||||
|
( newMaterial->compare( oldMaterial ) != 0 ) ||
|
||||||
|
( state.isCachedMaterialDataDirty() );
|
||||||
|
|
||||||
|
if ( updateMaterial )
|
||||||
|
{
|
||||||
|
const auto* const material = static_cast< const Material* >( newMaterial );
|
||||||
|
const auto& properties = material->properties;
|
||||||
|
|
||||||
|
p->setUniformValue( id.color, properties.color);
|
||||||
|
p->setUniformValue( id.offset, properties.offset);
|
||||||
|
p->setUniformValue( id.radius, properties.radius);
|
||||||
|
p->setUniformValue( id.thickness, properties.thickness);
|
||||||
|
p->setUniformValue( id.startAngle, properties.startAngle);
|
||||||
|
p->setUniformValue( id.spanAngle, properties.spanAngle);
|
||||||
|
p->setUniformValue( id.extend, properties.extend);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Uniforms id;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
Material::Material()
|
||||||
|
{
|
||||||
|
setFlag( QSGMaterial::Blending, true );
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
setFlag( QSGMaterial::SupportsRhiShader, true );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK( 6, 0, 0 )
|
||||||
|
|
||||||
|
QSGMaterialShader* Material::createShader() const
|
||||||
|
{
|
||||||
|
if ( !( flags() & QSGMaterial::RhiShaderWanted ) )
|
||||||
|
return new ShaderGL();
|
||||||
|
|
||||||
|
return new ShaderRhi();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
QSGMaterialShader* Material::createShader( QSGRendererInterface::RenderMode ) const
|
||||||
|
{
|
||||||
|
return new ShaderRhi();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QSGMaterialType* Material::type() const
|
||||||
|
{
|
||||||
|
static QSGMaterialType staticType;
|
||||||
|
return &staticType;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Material::compare( const QSGMaterial* other ) const
|
||||||
|
{
|
||||||
|
const auto& lhs = *static_cast< const Material* >( this );
|
||||||
|
const auto& rhs = *static_cast< const Material* >( other );
|
||||||
|
return ( lhs.properties == rhs.properties ) ? 0 : QSGMaterial::compare( other );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class QskArcShadowNodePrivate final : public QSGGeometryNodePrivate
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QskArcShadowNodePrivate()
|
||||||
|
: geometry( QSGGeometry::defaultAttributes_TexturedPoint2D(), 4 )
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
QSGGeometry geometry;
|
||||||
|
Material material;
|
||||||
|
QRectF rect;
|
||||||
|
};
|
||||||
|
|
||||||
|
QskArcShadowNode::QskArcShadowNode() : QSGGeometryNode( *new QskArcShadowNodePrivate )
|
||||||
|
{
|
||||||
|
Q_D( QskArcShadowNode );
|
||||||
|
|
||||||
|
setGeometry( &d->geometry );
|
||||||
|
setMaterial( &d->material );
|
||||||
|
|
||||||
|
d->geometry.setDrawingMode( QSGGeometry::DrawTriangleStrip );
|
||||||
|
d->material.setFlag( QSGMaterial::Blending );
|
||||||
|
}
|
||||||
|
|
||||||
|
QskArcShadowNode::~QskArcShadowNode() = default;
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
Q_REQUIRED_RESULT inline bool operator==(const QRectF& lhs, const QVector4D& rhs) noexcept
|
||||||
|
{
|
||||||
|
return lhs.x() == rhs[0] && lhs.y() == rhs[1] && lhs.width() == rhs[2] && lhs.height() == rhs[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_REQUIRED_RESULT inline bool operator!=(const QRectF& lhs, const QVector4D& rhs) noexcept
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
Q_REQUIRED_RESULT inline bool compareExchange(float& dst, const float src)
|
||||||
|
{
|
||||||
|
if ( dst != src )
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void QskArcShadowNode::update( const QRectF& rect, const QskArcMetrics& arcMetrics,
|
||||||
|
const QColor& shadowColor, const QskShadowMetrics& shadowMetrics, const qreal borderWidth )
|
||||||
|
{
|
||||||
|
Q_D( QskArcShadowNode );
|
||||||
|
|
||||||
|
const auto w = qMax(0.0, borderWidth);
|
||||||
|
const auto shadowRect = rect.adjusted(-w, -w, +w, +w);
|
||||||
|
const auto size = qMin( shadowRect.width(), shadowRect.height() );
|
||||||
|
|
||||||
|
const auto color = [](const QColor& color)
|
||||||
|
{
|
||||||
|
return QVector4D
|
||||||
|
{
|
||||||
|
qBound(0.0f, ( float ) color.redF(), 1.0f),
|
||||||
|
qBound(0.0f, ( float ) color.greenF(), 1.0f),
|
||||||
|
qBound(0.0f, ( float ) color.blueF(), 1.0f),
|
||||||
|
qBound(0.0f, ( float ) color.alphaF(), 1.0f)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
(shadowColor);
|
||||||
|
|
||||||
|
const auto offset = [](const QskShadowMetrics& metrics, const QRectF& rect)
|
||||||
|
{
|
||||||
|
QVector2D offset;
|
||||||
|
offset[ 0 ] = ( float ) metrics.offset().x();
|
||||||
|
offset[ 1 ] = ( float ) metrics.offset().y();
|
||||||
|
|
||||||
|
if ( metrics.sizeMode() == Qt::AbsoluteSize )
|
||||||
|
{
|
||||||
|
offset[ 0 ] = ( float ) (metrics.offset().x() / rect.width());
|
||||||
|
offset[ 1 ] = ( float ) (metrics.offset().y() / rect.height());
|
||||||
|
}
|
||||||
|
|
||||||
|
offset[ 0 ] = qBound( -1.0f, offset[ 0 ], +1.0f );
|
||||||
|
offset[ 1 ] = qBound( -1.0f, offset[ 1 ], +1.0f );
|
||||||
|
offset[ 0 ] *= -1.0f; // why must I change directions here?
|
||||||
|
offset[ 1 ] *= -1.0f; // why must I change directions here?
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
(shadowMetrics, shadowRect);
|
||||||
|
|
||||||
|
const auto thickness = [](const QskArcMetrics& metrics, const QRectF& rect)
|
||||||
|
{
|
||||||
|
auto thickness = metrics.thickness();
|
||||||
|
const auto size = qMin( rect.width(), rect.height() );
|
||||||
|
if ( metrics.sizeMode() == Qt::AbsoluteSize )
|
||||||
|
{
|
||||||
|
thickness = thickness / size;
|
||||||
|
}
|
||||||
|
thickness = qBound( 0.0, thickness, 1.0 );
|
||||||
|
return ( float ) thickness;
|
||||||
|
}
|
||||||
|
(arcMetrics, shadowRect);
|
||||||
|
|
||||||
|
const auto spreadRadius = [](const QskShadowMetrics& metrics, const QRectF& rect)
|
||||||
|
{
|
||||||
|
auto spreadRadius = metrics.spreadRadius();
|
||||||
|
const auto size = qMin( rect.width(), rect.height() );
|
||||||
|
if ( metrics.sizeMode() == Qt::AbsoluteSize )
|
||||||
|
{
|
||||||
|
spreadRadius = spreadRadius / size;
|
||||||
|
}
|
||||||
|
spreadRadius = qBound( 0.0, spreadRadius, 1.0 );
|
||||||
|
return (float) spreadRadius;
|
||||||
|
}
|
||||||
|
(shadowMetrics, shadowRect);
|
||||||
|
|
||||||
|
const auto startAngle = (float) qDegreesToRadians(arcMetrics.startAngle() + 90.0); // why +90 ?
|
||||||
|
const auto spanAngle = (float) qDegreesToRadians(arcMetrics.spanAngle());
|
||||||
|
const auto radius = ( float ) ( 1.0 - thickness - 2 * w / size );
|
||||||
|
|
||||||
|
const MaterialProperties properties {
|
||||||
|
color,
|
||||||
|
offset,
|
||||||
|
radius,
|
||||||
|
thickness,
|
||||||
|
startAngle,
|
||||||
|
spanAngle,
|
||||||
|
spreadRadius
|
||||||
|
};
|
||||||
|
|
||||||
|
const auto dirtyGeometry = ( d->rect != shadowRect );
|
||||||
|
const auto dirtyMaterial = ( properties != d->material.properties );
|
||||||
|
|
||||||
|
if ( dirtyGeometry )
|
||||||
|
{
|
||||||
|
d->rect = shadowRect;
|
||||||
|
QSGGeometry::updateTexturedRectGeometry( &d->geometry, d->rect, { -0.5, -0.5, 1.0, 1.0 } );
|
||||||
|
d->geometry.markVertexDataDirty();
|
||||||
|
markDirty( QSGNode::DirtyGeometry );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( dirtyMaterial )
|
||||||
|
{
|
||||||
|
d->material.properties = properties;
|
||||||
|
markDirty( QSGNode::DirtyMaterial );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QSK_ARC_SHADOW_NODE_H
|
||||||
|
#define QSK_ARC_SHADOW_NODE_H
|
||||||
|
|
||||||
|
#include "QskGlobal.h"
|
||||||
|
#include <qsgnode.h>
|
||||||
|
|
||||||
|
class QskArcMetrics;
|
||||||
|
class QskShadowMetrics;
|
||||||
|
|
||||||
|
class QskArcShadowNodePrivate;
|
||||||
|
|
||||||
|
class QskArcShadowNode : public QSGGeometryNode
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
QskArcShadowNode();
|
||||||
|
~QskArcShadowNode() override;
|
||||||
|
|
||||||
|
void update( const QRectF& rect, const QskArcMetrics& metrics, const QColor& color,
|
||||||
|
const QskShadowMetrics& shadowMetrics, qreal borderWidth = 0.0 );
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DECLARE_PRIVATE( QskArcShadowNode )
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -1,14 +1,15 @@
|
||||||
uniform lowp float qt_Opacity;
|
uniform lowp float opacity;
|
||||||
// arc
|
// arc
|
||||||
uniform lowp vec4 rect; // arc's rectangle on screen in pixel x,y,w,h
|
|
||||||
uniform lowp float radius; // arc's radius [0.0, 1.0]
|
uniform lowp float radius; // arc's radius [0.0, 1.0]
|
||||||
uniform lowp float thickness; // arc's thickness
|
uniform lowp float thickness; // arc's thickness [0.0, 1.0]
|
||||||
uniform lowp float startAngle; // arc's start angle
|
uniform lowp float startAngle; // arc's start angle [rad]
|
||||||
uniform lowp float spanAngle; // arc's span angle
|
uniform lowp float spanAngle; // arc's span angle [rad]
|
||||||
// shadow
|
// shadow
|
||||||
uniform lowp vec4 color; // shadow's color
|
uniform lowp vec4 color; // shadow's color
|
||||||
uniform lowp vec2 offset; // shadow's offset (x,y) : [-1.0, +1.0]x[-1.0,+1.0]
|
uniform lowp vec2 offset; // shadow's offset (x,y) : [-1.0, +1.0]x[-1.0,+1.0]
|
||||||
uniform lowp float extend; // shadow length around
|
uniform lowp float extend; // shadow length [0.0, 1.0]
|
||||||
|
// position
|
||||||
|
varying lowp vec2 coord; // [-1.0,+1.0]x[-1.0,+1.0]
|
||||||
|
|
||||||
float sdRing( in vec2 p, in vec2 n, in float r, in float th )
|
float sdRing( in vec2 p, in vec2 n, in float r, in float th )
|
||||||
{
|
{
|
||||||
|
|
@ -21,23 +22,11 @@ float sdRing( in vec2 p, in vec2 n, in float r, in float th )
|
||||||
}
|
}
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
// uniforms
|
|
||||||
float shadowSize = extend; // px >= 0.0
|
|
||||||
vec2 iResolution = rect.zw;
|
|
||||||
|
|
||||||
// normalized pixel coordinates
|
|
||||||
vec2 p = (2.0 * gl_FragCoord.xy - iResolution.xy) / iResolution.xy; // xy for ellipse
|
|
||||||
float shadowSizeUv = shadowSize / min(iResolution.x, iResolution.y);
|
|
||||||
|
|
||||||
float t = radians(abs(spanAngle) / 2.0);
|
|
||||||
vec2 cs = vec2(cos(t),sin(t));
|
|
||||||
|
|
||||||
// rotation
|
// rotation
|
||||||
float ra = radians(startAngle + spanAngle / 2.0);
|
vec2 p = coord + offset;
|
||||||
|
float ra = -startAngle - spanAngle / 2.0;
|
||||||
{
|
{
|
||||||
p = p + offset;
|
|
||||||
|
|
||||||
float sin_ra = sin(ra);
|
float sin_ra = sin(ra);
|
||||||
float cos_ra = cos(ra);
|
float cos_ra = cos(ra);
|
||||||
mat2 transform = mat2
|
mat2 transform = mat2
|
||||||
|
|
@ -45,16 +34,14 @@ void main()
|
||||||
cos_ra, -sin_ra,
|
cos_ra, -sin_ra,
|
||||||
sin_ra, cos_ra
|
sin_ra, cos_ra
|
||||||
);
|
);
|
||||||
|
|
||||||
p = transform * p;
|
p = transform * p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// distance
|
float t = abs(spanAngle) / 2.0; // half span angle
|
||||||
float d = sdRing(p, cs, radius, thickness);
|
vec2 cs = vec2(cos(t),sin(t));
|
||||||
float e = 1.0 / shadowSizeUv;
|
float d = sdRing(p, cs, radius / 2.0, thickness);
|
||||||
|
|
||||||
// coloring
|
float a = 1.0 - smoothstep(0.0, extend, d);
|
||||||
float v = 1.0 - abs(d) * e;
|
gl_FragColor = vec4(color.rgb, 1.0) * a * opacity;
|
||||||
float a = d >= 0.0 && abs(d) < e ? v : 1.0; // alpha
|
|
||||||
gl_FragColor = vec4(color.rgb, 1.0) * a * qt_Opacity;
|
|
||||||
}
|
}
|
||||||
|
|
@ -1,7 +1,12 @@
|
||||||
attribute highp vec4 vertex;
|
uniform highp mat4 matrix;
|
||||||
uniform highp mat4 qt_Matrix;
|
|
||||||
|
attribute highp vec4 in_vertex;
|
||||||
|
attribute mediump vec2 in_coord;
|
||||||
|
|
||||||
|
varying mediump vec2 coord;
|
||||||
|
|
||||||
void main()
|
void main()
|
||||||
{
|
{
|
||||||
gl_Position = qt_Matrix * vertex;
|
coord = in_coord;
|
||||||
}
|
gl_Position = matrix * in_vertex;
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue