initial commit
This commit is contained in:
parent
c3c9405b65
commit
9f8bf9deaf
|
@ -14,6 +14,98 @@
|
|||
#include <qpen.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(
|
||||
const QskGradient& gradient, const QskArcMetrics& metrics )
|
||||
{
|
||||
|
@ -73,6 +165,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
{
|
||||
enum NodeRole
|
||||
{
|
||||
ShadowRole,
|
||||
FillRole,
|
||||
BorderRole
|
||||
};
|
||||
|
@ -80,6 +173,9 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
const auto metrics = qskEffectiveMetrics( arcMetrics, rect );
|
||||
const auto gradient = qskEffectiveGradient( fillGradient, metrics );
|
||||
|
||||
auto shadowNode = static_cast< QskArcShadowNode* >(
|
||||
QskSGNode::findChildNode( this, ShadowRole ) );
|
||||
|
||||
auto fillNode = static_cast< QskShapeNode* >(
|
||||
QskSGNode::findChildNode( this, FillRole ) );
|
||||
|
||||
|
@ -89,22 +185,45 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
const auto arcRect = qskEffectiveRect( rect, borderWidth );
|
||||
if ( arcRect.isEmpty() )
|
||||
{
|
||||
delete shadowNode;
|
||||
delete fillNode;
|
||||
delete borderNode;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
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 ( fillNode == nullptr )
|
||||
{
|
||||
fillNode = new QskShapeNode;
|
||||
QskSGNode::setNodeRole( fillNode, FillRole );
|
||||
|
||||
prependChildNode( fillNode );
|
||||
}
|
||||
|
||||
fillNode->updateNode( path, QTransform(), arcRect, gradient );
|
||||
|
@ -112,6 +231,7 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
else
|
||||
{
|
||||
delete fillNode;
|
||||
fillNode = nullptr;
|
||||
}
|
||||
|
||||
if ( borderWidth > 0.0 && borderColor.alpha() > 0 )
|
||||
|
@ -120,8 +240,6 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
{
|
||||
borderNode = new QskStrokeNode;
|
||||
QskSGNode::setNodeRole( borderNode, BorderRole );
|
||||
|
||||
appendChildNode( borderNode );
|
||||
}
|
||||
|
||||
QPen pen( borderColor, borderWidth );
|
||||
|
@ -132,5 +250,23 @@ void QskArcNode::setArcData( const QRectF& rect, const QskArcMetrics& arcMetrics
|
|||
else
|
||||
{
|
||||
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">
|
||||
<qresource prefix="/qskinny/">
|
||||
|
||||
<file>shaders/arcshadow.frag</file>
|
||||
<file>shaders/arcshadow.vert</file>
|
||||
|
||||
<file>shaders/boxshadow.vert.qsb</file>
|
||||
<file>shaders/boxshadow.frag.qsb</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