initial commit

This commit is contained in:
Vogel, Rick 2023-12-04 17:33:28 +01:00
parent c3c9405b65
commit 9f8bf9deaf
4 changed files with 202 additions and 5 deletions

View File

@ -14,6 +14,98 @@
#include <qpen.h> #include <qpen.h>
#include <qpainterpath.h> #include <qpainterpath.h>
#include <QSGSimpleMaterialShader>
#include <QFile>
#include <QDebug>
#include <qmath.h>
namespace
{
struct QskArcShadowMaterialProperties
{
QColor color = Qt::red;
QRectF rect;
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;
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);
}
};
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 qreal extend)
{
const auto size = qMin(rect.width(), rect.height());
auto* const material = static_cast<QSGSimpleMaterial< QskArcShadowMaterialProperties >*>(this->material());
auto& state = *material->state();
state.color = color;
state.rect = rect;
state.radius = 1.0 - metrics.thickness() / size;
state.thickness = 2 * metrics.thickness() / size;
state.startAngle = metrics.startAngle();
state.spanAngle = metrics.spanAngle();
state.extend = extend;
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 )
{ {
@ -73,6 +165,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
{ {
enum NodeRole enum NodeRole
{ {
ShadowRole,
FillRole, FillRole,
BorderRole BorderRole
}; };
@ -80,6 +173,9 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
const auto metrics = qskEffectiveMetrics( arcMetrics, rect ); const auto metrics = qskEffectiveMetrics( arcMetrics, rect );
const auto gradient = qskEffectiveGradient( fillGradient, metrics ); const auto gradient = qskEffectiveGradient( fillGradient, metrics );
auto shadowNode = static_cast< QskArcShadowNode* >(
QskSGNode::findChildNode( this, ShadowRole ) );
auto fillNode = static_cast< QskShapeNode* >( auto fillNode = static_cast< QskShapeNode* >(
QskSGNode::findChildNode( this, FillRole ) ); QskSGNode::findChildNode( this, FillRole ) );
@ -89,22 +185,45 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
const auto arcRect = qskEffectiveRect( rect, borderWidth ); const auto arcRect = qskEffectiveRect( rect, borderWidth );
if ( arcRect.isEmpty() ) if ( arcRect.isEmpty() )
{ {
delete shadowNode;
delete fillNode; delete fillNode;
delete borderNode; delete borderNode;
return; return;
} }
const auto path = metrics.painterPath( arcRect ); const auto path = metrics.painterPath( arcRect );
if ( true /* TODO */ )
{
if ( shadowNode == nullptr )
{
shadowNode = new QskArcShadowNode;
QskSGNode::setNodeRole( shadowNode, ShadowRole );
}
const auto extend = 16.0;
const auto e = extend / 4;
auto* const vertices = shadowNode->geometry()->vertexDataAsPoint2D();
const auto shadowRect = arcRect.adjusted( -e, +e, e, -e );
vertices[0].set(shadowRect.left(), shadowRect.top());
vertices[1].set(shadowRect.left(), shadowRect.bottom());
vertices[2].set(shadowRect.right(), shadowRect.top());
vertices[3].set(shadowRect.right(), shadowRect.bottom());
shadowNode->update(shadowRect, metrics, Qt::black, extend);
qDebug() << shadowRect << arcRect;
}
else
{
delete shadowNode;
shadowNode = nullptr;
}
if ( gradient.isVisible() && !metrics.isNull() ) if ( gradient.isVisible() && !metrics.isNull() )
{ {
if ( fillNode == nullptr ) if ( fillNode == nullptr )
{ {
fillNode = new QskShapeNode; fillNode = new QskShapeNode;
QskSGNode::setNodeRole( fillNode, FillRole ); QskSGNode::setNodeRole( fillNode, FillRole );
prependChildNode( fillNode );
} }
fillNode->updateNode( path, QTransform(), arcRect, gradient ); fillNode->updateNode( path, QTransform(), arcRect, gradient );
@ -112,6 +231,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
else else
{ {
delete fillNode; delete fillNode;
fillNode = nullptr;
} }
if ( borderWidth > 0.0 && borderColor.alpha() > 0 ) if ( borderWidth > 0.0 && borderColor.alpha() > 0 )
@ -120,8 +240,6 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
{ {
borderNode = new QskStrokeNode; borderNode = new QskStrokeNode;
QskSGNode::setNodeRole( borderNode, BorderRole ); QskSGNode::setNodeRole( borderNode, BorderRole );
appendChildNode( borderNode );
} }
QPen pen( borderColor, borderWidth ); QPen pen( borderColor, borderWidth );
@ -132,5 +250,23 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
else else
{ {
delete borderNode; delete borderNode;
borderNode = nullptr;
}
const auto oldChildCount = this->childCount();
const auto newChildCount =
( shadowNode ? 1 : 0 ) + ( fillNode ? 1 : 0 ) + ( borderNode ? 1 : 0 );
if ( oldChildCount != newChildCount )
{
removeAllChildNodes();
for ( QSGNode* node : { ( QSGNode* ) shadowNode, ( QSGNode* ) fillNode, ( QSGNode* ) borderNode })
{
if ( node != nullptr )
{
appendChildNode( node );
}
}
} }
} }

View File

@ -2,6 +2,9 @@
<RCC version="1.0"> <RCC version="1.0">
<qresource prefix="/qskinny/"> <qresource prefix="/qskinny/">
<file>shaders/arcshadow.frag</file>
<file>shaders/arcshadow.vert</file>
<file>shaders/boxshadow.vert.qsb</file> <file>shaders/boxshadow.vert.qsb</file>
<file>shaders/boxshadow.frag.qsb</file> <file>shaders/boxshadow.frag.qsb</file>
<file>shaders/boxshadow.vert</file> <file>shaders/boxshadow.vert</file>

View File

@ -0,0 +1,51 @@
uniform lowp float qt_Opacity;
uniform lowp vec4 color;
uniform lowp vec4 rect;
uniform lowp float radius;
uniform lowp float thickness;
uniform lowp float startAngle;
uniform lowp float spanAngle;
uniform lowp float extend;
const float M_PI = 3.141592653589793;
float sdRing( in vec2 p, in vec2 n, in float r, in float th )
{
p.x = abs(p.x);
p = mat2(n.x,n.y,-n.y,n.x)*p;
return max( abs(length(p)-r)-th*0.5,
length(vec2(p.x,max(0.0,abs(r-p.y)-th*0.5)))*sign(p.x) );
}
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
float ra = radians(startAngle + spanAngle / 2.0);
{
float sin_ra = sin(ra);
float cos_ra = cos(ra);
p = mat2(cos_ra, -sin_ra, sin_ra, cos_ra) * p;
}
// distance
float d = sdRing(p, cs, radius, thickness);
float e = 1.0 / shadowSizeUv;
// coloring
float v = 1.0 - abs(d) * e;
float a = d >= 0.0 && abs(d) < e ? v : 0.0; // alpha
gl_FragColor = vec4(color.rgb, a) * qt_Opacity;
}

View File

@ -0,0 +1,7 @@
attribute highp vec4 vertex;
uniform highp mat4 qt_Matrix;
void main()
{
gl_Position = qt_Matrix * vertex;
}