initial commit
This commit is contained in:
parent
c3c9405b65
commit
9f8bf9deaf
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
attribute highp vec4 vertex;
|
||||||
|
uniform highp mat4 qt_Matrix;
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
gl_Position = qt_Matrix * vertex;
|
||||||
|
}
|
Loading…
Reference in New Issue