shadows added to playground
This commit is contained in:
parent
7b59793054
commit
bbbc02f122
|
@ -5,6 +5,7 @@ SUBDIRS += \
|
||||||
dialogbuttons \
|
dialogbuttons \
|
||||||
invoker \
|
invoker \
|
||||||
inputpanel \
|
inputpanel \
|
||||||
|
shadows \
|
||||||
images
|
images
|
||||||
|
|
||||||
qtHaveModule(webengine) {
|
qtHaveModule(webengine) {
|
||||||
|
|
|
@ -0,0 +1,275 @@
|
||||||
|
#include "BoxShadowNode.h"
|
||||||
|
#include "QskBoxShapeMetrics.h"
|
||||||
|
|
||||||
|
#include <QColor>
|
||||||
|
#include <QSGMaterialShader>
|
||||||
|
#include <QSGMaterial>
|
||||||
|
|
||||||
|
#include <private/qsgnode_p.h>
|
||||||
|
|
||||||
|
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_matrixLocation = -1;
|
||||||
|
int m_opacityLocation = -1;
|
||||||
|
int m_aspectLocation = -1;
|
||||||
|
int m_extentLocation = -1;
|
||||||
|
int m_radiusLocation = -1;
|
||||||
|
int m_colorLocation = -1;
|
||||||
|
int m_offsetLocation = -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 extent = 0.0;
|
||||||
|
QVector4D radius = QVector4D{0.0, 0.0, 0.0, 0.0};
|
||||||
|
QColor color = Qt::black;
|
||||||
|
QVector2D offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
Shader::Shader()
|
||||||
|
{
|
||||||
|
const QString root( ":/qskinny/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_matrixLocation = p->uniformLocation( "matrix" );
|
||||||
|
m_aspectLocation = p->uniformLocation( "aspect" );
|
||||||
|
m_opacityLocation = p->uniformLocation( "opacity" );
|
||||||
|
m_extentLocation = p->uniformLocation( "extent" );
|
||||||
|
m_offsetLocation = p->uniformLocation( "offset" );
|
||||||
|
m_radiusLocation = p->uniformLocation( "radius" );
|
||||||
|
m_colorLocation = p->uniformLocation( "color" );
|
||||||
|
}
|
||||||
|
|
||||||
|
void Shader::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 == nullptr || newMaterial->compare( oldMaterial ) != 0
|
||||||
|
|| state.isCachedMaterialDataDirty( ))
|
||||||
|
{
|
||||||
|
auto material = static_cast< const Material* >(newMaterial);
|
||||||
|
|
||||||
|
p->setUniformValue( m_aspectLocation, material->aspect );
|
||||||
|
p->setUniformValue( m_extentLocation, material->extent );
|
||||||
|
p->setUniformValue( m_radiusLocation, material->radius );
|
||||||
|
p->setUniformValue( m_colorLocation, material->color );
|
||||||
|
p->setUniformValue( m_offsetLocation, material->offset );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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->offset == offset
|
||||||
|
&& material->aspect == aspect
|
||||||
|
&& qFuzzyCompare(material->extent, extent)
|
||||||
|
&& 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 newAspect( 1.0, 1.0 );
|
||||||
|
|
||||||
|
if ( rect.width() >= rect.height() )
|
||||||
|
newAspect.setX( rect.width() / rect.height());
|
||||||
|
else
|
||||||
|
newAspect.setY( rect.height() / rect.width() );
|
||||||
|
|
||||||
|
if ( d->material.aspect != newAspect)
|
||||||
|
{
|
||||||
|
d->material.aspect = newAspect;
|
||||||
|
markDirty( QSGNode::DirtyMaterial );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowNode::setShape( const QskBoxShapeMetrics& shape )
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
const float t = 0.5 * 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::setShadow( qreal extent, qreal dx, qreal dy )
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
if ( extent <= 0.0 )
|
||||||
|
extent = 0.0;
|
||||||
|
|
||||||
|
const auto minDimension = std::min( d->rect.width(), d->rect.height() );
|
||||||
|
|
||||||
|
const float uniformExtent = ( extent / minDimension ) * 2.0;
|
||||||
|
|
||||||
|
if ( !qFuzzyCompare( d->material.extent, uniformExtent ) )
|
||||||
|
{
|
||||||
|
d->material.extent = uniformExtent;
|
||||||
|
markDirty(QSGNode::DirtyMaterial);
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto uniformOffset = QVector2D( dx, dy ) / minDimension;
|
||||||
|
|
||||||
|
if ( d->material.offset != uniformOffset)
|
||||||
|
{
|
||||||
|
d->material.offset = uniformOffset;
|
||||||
|
markDirty( QSGNode::DirtyMaterial );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void BoxShadowNode::updateGeometry()
|
||||||
|
{
|
||||||
|
Q_D( BoxShadowNode );
|
||||||
|
|
||||||
|
const auto sz = d->material.extent;
|
||||||
|
const auto aspect = d->material.aspect;
|
||||||
|
|
||||||
|
auto rect = d->rect.adjusted(
|
||||||
|
-sz * aspect.x(), -sz * aspect.y(),
|
||||||
|
sz * aspect.x(), sz * aspect.y()
|
||||||
|
);
|
||||||
|
|
||||||
|
auto offsetLength = d->material.offset.length();
|
||||||
|
|
||||||
|
rect = rect.adjusted(
|
||||||
|
-offsetLength * aspect.x(), -offsetLength * aspect.y(),
|
||||||
|
offsetLength * aspect.x(), offsetLength * aspect.y() );
|
||||||
|
|
||||||
|
QSGGeometry::updateTexturedRectGeometry(
|
||||||
|
&d->geometry, rect, QRectF( 0.0, 0.0, 1.0, 1.0 ) );
|
||||||
|
|
||||||
|
markDirty( QSGNode::DirtyGeometry );
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#ifndef BOX_SHADOW_NODE_H
|
||||||
|
#define BOX_SHADOW_NODE_H
|
||||||
|
|
||||||
|
#include <QSGGeometryNode>
|
||||||
|
|
||||||
|
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 setShadow( qreal extent, qreal dx, qreal dy );
|
||||||
|
|
||||||
|
void updateGeometry();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Q_DECLARE_PRIVATE( BoxShadowNode )
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,138 @@
|
||||||
|
#include "ShadowedBox.h"
|
||||||
|
#include "BoxShadowNode.h"
|
||||||
|
|
||||||
|
#include <QskBoxNode.h>
|
||||||
|
#include <QskBoxBorderMetrics.h>
|
||||||
|
#include <QskBoxBorderColors.h>
|
||||||
|
#include <QskGradient.h>
|
||||||
|
#include <QskSkinlet.h>
|
||||||
|
|
||||||
|
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 );
|
||||||
|
|
||||||
|
switch ( nodeRole )
|
||||||
|
{
|
||||||
|
case ShadowRole:
|
||||||
|
{
|
||||||
|
auto shadowNode = static_cast< BoxShadowNode* >( node );
|
||||||
|
if ( shadowNode == nullptr )
|
||||||
|
shadowNode = new BoxShadowNode();
|
||||||
|
|
||||||
|
const auto& s = box->shadow();
|
||||||
|
const qreal dx = s.extent + s.xOffset;
|
||||||
|
const qreal dy = s.extent + s.yOffset;
|
||||||
|
|
||||||
|
auto r = box->subControlRect( ShadowedBox::Panel );
|
||||||
|
r.adjust( -dx, -dy, dx, dy );
|
||||||
|
|
||||||
|
shadowNode->setRect( r );
|
||||||
|
shadowNode->setShape( box->shape() );
|
||||||
|
shadowNode->setShadow( s.extent, s.xOffset, s.yOffset );
|
||||||
|
shadowNode->setColor( box->shadowColor() );
|
||||||
|
shadowNode->updateGeometry();
|
||||||
|
|
||||||
|
return shadowNode;
|
||||||
|
}
|
||||||
|
case PanelRole:
|
||||||
|
{
|
||||||
|
auto boxNode = static_cast< QskBoxNode* >( node );
|
||||||
|
if ( boxNode == nullptr )
|
||||||
|
boxNode = new QskBoxNode();
|
||||||
|
|
||||||
|
const QRectF r = box->subControlRect( ShadowedBox::Panel );
|
||||||
|
|
||||||
|
boxNode->setBoxData( r, box->shape(), QskBoxBorderMetrics(),
|
||||||
|
QskBoxBorderColors(), box->gradient() );
|
||||||
|
|
||||||
|
return boxNode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
QSK_SUBCONTROL( ShadowedBox, Panel )
|
||||||
|
|
||||||
|
ShadowedBox::ShadowedBox(QQuickItem *parentItem)
|
||||||
|
: QskControl( parentItem )
|
||||||
|
{
|
||||||
|
setFlag( QQuickItem::ItemHasContents, true );
|
||||||
|
setSkinlet( new Skinlet() );
|
||||||
|
}
|
||||||
|
|
||||||
|
ShadowedBox::~ShadowedBox()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowedBox::setShadow( const Shadow& shadow )
|
||||||
|
{
|
||||||
|
m_shadow = shadow;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
const ShadowedBox::Shadow& ShadowedBox::shadow() const
|
||||||
|
{
|
||||||
|
return m_shadow;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShadowedBox::setShadowColor( const QColor& color )
|
||||||
|
{
|
||||||
|
m_shadowColor = color;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
QColor ShadowedBox::shadowColor() const
|
||||||
|
{
|
||||||
|
return m_shadowColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_ShadowedBox.cpp"
|
|
@ -0,0 +1,46 @@
|
||||||
|
#ifndef SHADOWED_BOX_H
|
||||||
|
#define SHADOWED_BOX_H
|
||||||
|
|
||||||
|
#include <QskControl.h>
|
||||||
|
#include <QskBoxShapeMetrics.h>
|
||||||
|
|
||||||
|
class QskGradient;
|
||||||
|
|
||||||
|
class ShadowedBox : public QskControl
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
QSK_SUBCONTROLS( Panel )
|
||||||
|
|
||||||
|
class Shadow
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
qreal extent = 0.0;
|
||||||
|
qreal xOffset = 0.0;
|
||||||
|
qreal yOffset = 0.0;
|
||||||
|
};
|
||||||
|
|
||||||
|
ShadowedBox(QQuickItem *parent = nullptr);
|
||||||
|
~ShadowedBox() override;
|
||||||
|
|
||||||
|
void setShadow( const Shadow& );
|
||||||
|
const Shadow& shadow() const;
|
||||||
|
|
||||||
|
void setGradient( const QskGradient& );
|
||||||
|
const QskGradient& gradient() const;
|
||||||
|
|
||||||
|
void setShadowColor( const QColor& );
|
||||||
|
QColor shadowColor() const;
|
||||||
|
|
||||||
|
void setShape( const QskBoxShapeMetrics& );
|
||||||
|
const QskBoxShapeMetrics& shape() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Shadow m_shadow;
|
||||||
|
QColor m_shadowColor = Qt::black;
|
||||||
|
QskGradient m_gradient;
|
||||||
|
QskBoxShapeMetrics m_shape;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
Heavily inspired by code from the kirigami project:
|
||||||
|
Copyright 2020 Arjen Hiemstra <ahiemstra@heimr.nl>
|
||||||
|
License: LGPL-2.0-or-later
|
||||||
|
|
||||||
|
https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
|
||||||
|
Copyright: 2017 Inigo Quilez
|
||||||
|
License: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
uniform lowp float opacity;
|
||||||
|
uniform lowp float extent;
|
||||||
|
uniform lowp vec4 radius;
|
||||||
|
uniform lowp vec4 color;
|
||||||
|
uniform lowp vec2 offset;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isInside( in lowp vec2 point, in lowp vec2 size, in lowp vec4 radii )
|
||||||
|
{
|
||||||
|
lowp float r = effectiveRadius( radii, point );
|
||||||
|
lowp vec2 d = abs(point) - size + r;
|
||||||
|
|
||||||
|
lowp float l = min( max(d.x, d.y), 0.0) + length( max(d, 0.0) ) - r;
|
||||||
|
return l <= 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lowp float shadowAt(
|
||||||
|
in lowp vec2 point, in lowp vec2 size, in lowp vec4 radii )
|
||||||
|
{
|
||||||
|
lowp float r = effectiveRadius( radii, point );
|
||||||
|
lowp vec2 d = abs(point) - size + r;
|
||||||
|
|
||||||
|
return min( max(d.x, d.y), 0.0) + length( max(d, 0.0) ) - r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
lowp vec4 col = vec4(0.0);
|
||||||
|
|
||||||
|
if ( extent > 0.0 && opacity > 0.0 )
|
||||||
|
{
|
||||||
|
lowp float t = 1.0 + 2.0 * length( offset ) + extent;
|
||||||
|
|
||||||
|
if ( !isInside( coord, aspect / t, radius / t) )
|
||||||
|
{
|
||||||
|
const lowp float minRadius = 0.05;
|
||||||
|
lowp float e2 = 0.5 * extent;
|
||||||
|
|
||||||
|
lowp vec4 f = minRadius / max( radius, minRadius );
|
||||||
|
lowp vec4 r = radius + e2 * f;
|
||||||
|
|
||||||
|
lowp float shadow = shadowAt(
|
||||||
|
coord - 2.0 * offset / t, aspect / t, r / t);
|
||||||
|
|
||||||
|
lowp float v = smoothstep( -e2, e2, shadow );
|
||||||
|
|
||||||
|
col = mix( color, vec4(0.0), v ) * opacity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
gl_FragColor = col;
|
||||||
|
}
|
|
@ -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 = ( -1.0 + 2.0 * in_coord ) * aspect;
|
||||||
|
gl_Position = matrix * in_vertex;
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/******************************************************************************
|
||||||
|
* QSkinny - Copyright (C) 2016 Uwe Rathmann
|
||||||
|
* This file may be used under the terms of the 3-clause BSD License
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include "ShadowedBox.h"
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QskObjectCounter.h>
|
||||||
|
#include <QskWindow.h>
|
||||||
|
#include <QskLinearBox.h>
|
||||||
|
#include <QskBoxShapeMetrics.h>
|
||||||
|
#include <QskRgbValue.h>
|
||||||
|
|
||||||
|
class Box : public ShadowedBox
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Box( QQuickItem* parent = nullptr )
|
||||||
|
: ShadowedBox( parent )
|
||||||
|
{
|
||||||
|
Shadow shadow;
|
||||||
|
shadow.extent = 10;
|
||||||
|
shadow.xOffset = 20.0;
|
||||||
|
shadow.yOffset = 20.0;
|
||||||
|
|
||||||
|
setShadow( shadow );
|
||||||
|
setShadowColor( Qt::black );
|
||||||
|
setGradient( Qt::darkRed );
|
||||||
|
setShape( QskBoxShapeMetrics( 5, 10, 15, 20 ) );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main( int argc, char* argv[] )
|
||||||
|
{
|
||||||
|
#ifdef ITEM_STATISTICS
|
||||||
|
QskObjectCounter counter( true );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
QGuiApplication app( argc, argv );
|
||||||
|
|
||||||
|
auto layout = new QskLinearBox();
|
||||||
|
layout->setPanel( true );
|
||||||
|
#if 1
|
||||||
|
layout->setGradientHint( QskBox::Panel,
|
||||||
|
QskGradient( Qt::Vertical, QskRgb::WhiteSmoke, QskRgb::MistyRose ) );
|
||||||
|
#else
|
||||||
|
layout->setGradientHint( QskBox::Panel, Qt::white );
|
||||||
|
#endif
|
||||||
|
layout->setPadding( 60 );
|
||||||
|
(void ) new Box( layout );
|
||||||
|
|
||||||
|
QskWindow window;
|
||||||
|
window.setColor( QskRgb::PapayaWhip );
|
||||||
|
window.addItem( layout );
|
||||||
|
window.resize( 600, 600 );
|
||||||
|
window.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
<!DOCTYPE RCC>
|
||||||
|
<RCC version="1.0">
|
||||||
|
<qresource prefix="/qskinny/shaders">
|
||||||
|
<file>boxshadow.vert</file>
|
||||||
|
<file>boxshadow.frag</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
|
@ -0,0 +1,14 @@
|
||||||
|
CONFIG += qskexample
|
||||||
|
QT += quick_private
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
shaders.qrc
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
ShadowedBox.h \
|
||||||
|
BoxShadowNode.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
ShadowedBox.cpp \
|
||||||
|
BoxShadowNode.cpp \
|
||||||
|
main.cpp
|
Loading…
Reference in New Issue