aspectRatio for conic gradients added to support f.e for filling ellipsoid arcs.

This commit is contained in:
Uwe Rathmann 2023-04-18 16:08:37 +02:00
parent e858e15b41
commit 9e99735d2f
10 changed files with 88 additions and 18 deletions

View File

@ -171,7 +171,7 @@ QskGradient::QskGradient( const QGradient& qGradient )
QskGradient::QskGradient( const QskGradient& other ) noexcept
: m_stops( other.m_stops )
, m_values{ other.m_values[0], other.m_values[1],
other.m_values[2], other.m_values[3], }
other.m_values[2], other.m_values[3], other.m_values[4] }
, m_type( other.m_type )
, m_spreadMode( other.m_spreadMode )
, m_stretchMode( other.m_stretchMode )
@ -197,6 +197,7 @@ QskGradient& QskGradient::operator=( const QskGradient& other ) noexcept
m_values[1] = other.m_values[1];
m_values[2] = other.m_values[2];
m_values[3] = other.m_values[3];
m_values[4] = other.m_values[4];
m_isDirty = other.m_isDirty;
m_isValid = other.m_isValid;
@ -215,6 +216,7 @@ bool QskGradient::operator==( const QskGradient& other ) const noexcept
&& ( m_values[1] == other.m_values[1] )
&& ( m_values[2] == other.m_values[2] )
&& ( m_values[3] == other.m_values[3] )
&& ( m_values[4] == other.m_values[4] )
&& ( m_stops == other.m_stops );
}
@ -439,6 +441,10 @@ void QskGradient::stretchTo( const QRectF& rect )
case Conic:
{
transform.map( m_values[0], m_values[1], &m_values[0], &m_values[1] );
if ( m_values[4] == 0.0 && !rect.isEmpty() )
m_values[4] = rect.width() / rect.height();
break;
}
}
@ -657,6 +663,13 @@ void QskGradient::setConicDirection( qreal x, qreal y,
setConicDirection( QskConicDirection( x, y, startAngle, spanAngle ) );
}
void QskGradient::setConicDirection( qreal x, qreal y,
qreal startAngle, qreal spanAngle, qreal aspectRatio )
{
const QskConicDirection dir( x, y, startAngle, spanAngle, aspectRatio );
setConicDirection( dir );
}
void QskGradient::setConicDirection( const QskConicDirection& direction )
{
m_type = Conic;
@ -665,6 +678,7 @@ void QskGradient::setConicDirection( const QskConicDirection& direction )
m_values[1] = direction.center().y();
m_values[2] = direction.startAngle();
m_values[3] = direction.spanAngle();
m_values[4] = direction.aspectRatio();
}
QskConicDirection QskGradient::conicDirection() const
@ -674,7 +688,10 @@ QskConicDirection QskGradient::conicDirection() const
if ( m_type != Conic )
return QskConicDirection( 0.5, 0.5, 0.0, 0.0 );
return QskConicDirection( m_values[0], m_values[1], m_values[2], m_values[3] );
QskConicDirection dir( m_values[0], m_values[1], m_values[2], m_values[3] );
dir.setAspectRatio( m_values[4] );
return dir;
}
void QskGradient::setDirection( Type type )
@ -702,7 +719,7 @@ void QskGradient::setDirection( Type type )
void QskGradient::resetDirection()
{
m_type = Stops;
m_values[0] = m_values[1] = m_values[2] = m_values[3] = 0.0;
m_values[0] = m_values[1] = m_values[2] = m_values[3] = m_values[4] = 0.0;
}
QskGradient QskGradient::effectiveGradient() const
@ -803,6 +820,7 @@ QDebug operator<<( QDebug debug, const QskGradient& gradient )
const auto dir = gradient.conicDirection();
debug << dir.center().x() << "," << dir.center().y()
<< ",AR:" << dir.aspectRatio()
<< ",[" << dir.startAngle() << "," << dir.spanAngle() << "])";
break;
}

View File

@ -97,8 +97,14 @@ class QSK_EXPORT QskGradient
void setRadialDirection( const qreal x, qreal y, qreal radiusX, qreal radiusY );
QskRadialDirection radialDirection() const;
void setConicDirection( qreal, qreal );
void setConicDirection( qreal, qreal, qreal, qreal = 360.0 );
void setConicDirection( qreal x, qreal y );
void setConicDirection( qreal x, qreal y,
qreal startAngle, qreal spanAngle = 360.0 );
void setConicDirection( qreal x, qreal y,
qreal startAngle, qreal spanAngle, qreal aspectRatio );
void setConicDirection( const QskConicDirection& );
QskConicDirection conicDirection() const;
@ -172,9 +178,9 @@ class QSK_EXPORT QskGradient
/*
Linear: x1, y1, x2, y2
Radial: centerX, centerY, radiusX, radiusY
Conic: centerX, centerY, startAngle, spanAngle
Conic: centerX, centerY, startAngle, spanAngle, aspectRatio
*/
qreal m_values[4] = {};
qreal m_values[5] = {};
unsigned int m_type : 3;
unsigned int m_spreadMode : 3;

View File

@ -228,6 +228,11 @@ void QskConicDirection::setSpanAngle( qreal degrees ) noexcept
m_spanAngle = qBound( -360.0, degrees, 360.0 );
}
void QskConicDirection::setAspectRatio( qreal ratio ) noexcept
{
m_aspectRatio = qMax( ratio, 0.0 );
}
// -- QskRadialDirection
void QskRadialDirection::setCenter( const QPointF& center ) noexcept

View File

@ -105,16 +105,19 @@ class QSK_EXPORT QskConicDirection
Q_PROPERTY( qreal y READ y WRITE setY )
Q_PROPERTY( qreal startAngle READ startAngle WRITE setStartAngle )
Q_PROPERTY( qreal spanAngle READ spanAngle WRITE setSpanAngle )
Q_PROPERTY( qreal aspectRatio READ aspectRatio WRITE setAspectRatio )
public:
// counter-clockwise
constexpr QskConicDirection() noexcept = default;
constexpr QskConicDirection( qreal x, qreal y, qreal startAngle = 0.0 ) noexcept;
constexpr QskConicDirection( qreal x, qreal y, qreal startAngle, qreal spanAngle ) noexcept;
constexpr QskConicDirection( qreal x, qreal y,
qreal startAngle, qreal spanAngle, qreal aspectRatio = 0.0 ) noexcept;
constexpr QskConicDirection( const QPointF&, qreal startAngle = 0.0 ) noexcept;
constexpr QskConicDirection( const QPointF&, qreal startAngle, qreal spanAngle ) noexcept;
constexpr QskConicDirection( const QPointF&,
qreal startAngle, qreal spanAngle, qreal aspectRatio = 0.0 ) noexcept;
constexpr QPointF center() const noexcept;
void setCenter(const QPointF& center) noexcept;
@ -132,11 +135,15 @@ class QSK_EXPORT QskConicDirection
constexpr qreal spanAngle() const noexcept;
void setSpanAngle( qreal ) noexcept;
constexpr qreal aspectRatio() const noexcept;
void setAspectRatio( qreal ) noexcept;
private:
qreal m_x = 0.5;
qreal m_y = 0.5;
qreal m_startAngle = 0.0;
qreal m_spanAngle = 360.0;
qreal m_aspectRatio = 0.0;
};
class QSK_EXPORT QskRadialDirection
@ -299,12 +306,13 @@ inline constexpr QskConicDirection::QskConicDirection(
{
}
inline constexpr QskConicDirection::QskConicDirection(
qreal x, qreal y, qreal startAngle, qreal spanAngle ) noexcept
inline constexpr QskConicDirection::QskConicDirection( qreal x, qreal y,
qreal startAngle, qreal spanAngle, qreal aspectRatio ) noexcept
: m_x( x )
, m_y( y )
, m_startAngle( startAngle )
, m_spanAngle( spanAngle )
, m_aspectRatio( aspectRatio )
{
}
@ -314,9 +322,9 @@ inline constexpr QskConicDirection::QskConicDirection(
{
}
inline constexpr QskConicDirection::QskConicDirection(
const QPointF& pos, qreal startAngle, qreal spanAngle ) noexcept
: QskConicDirection( pos.x(), pos.y(), startAngle, spanAngle )
inline constexpr QskConicDirection::QskConicDirection( const QPointF& pos,
qreal startAngle, qreal spanAngle, qreal apectRatio ) noexcept
: QskConicDirection( pos.x(), pos.y(), startAngle, spanAngle, apectRatio )
{
}
@ -345,6 +353,11 @@ inline constexpr qreal QskConicDirection::y() const noexcept
return m_y;
}
inline constexpr qreal QskConicDirection::aspectRatio() const noexcept
{
return m_aspectRatio;
}
inline constexpr QskRadialDirection::QskRadialDirection(
qreal x, qreal y, qreal radius ) noexcept
: m_x( x )

View File

@ -510,6 +510,16 @@ namespace
const auto dir = gradient.conicDirection();
float ratio = dir.aspectRatio();
if ( ratio <= 0.0f )
ratio = 1.0f;
if ( ratio != m_aspectRatio )
{
m_aspectRatio = ratio;
changed = true;
}
const QVector2D center( dir.x(), dir.y() );
if ( center != m_center )
@ -555,6 +565,7 @@ namespace
const auto mat = static_cast< const ConicMaterial* >( other );
if ( ( m_center != mat->m_center )
|| !qskFuzzyCompare( m_aspectRatio, mat->m_aspectRatio )
|| !qskFuzzyCompare( m_start, mat->m_start )
|| !qskFuzzyCompare( m_span, mat->m_span ) )
{
@ -567,6 +578,7 @@ namespace
QSGMaterialShader* createShader() const override;
QVector2D m_center;
float m_aspectRatio = 1.0;
float m_start = 0.0;
float m_span = 1.0;
};
@ -585,6 +597,7 @@ namespace
GradientShaderGL::initialize();
m_centerCoordId = program()->uniformLocation( "centerCoord" );
m_aspectRatioId = program()->uniformLocation( "aspectRatio" );
m_startId = program()->uniformLocation( "start" );
m_spanId = program()->uniformLocation( "span" );
}
@ -594,12 +607,14 @@ namespace
auto material = static_cast< const ConicMaterial* >( newMaterial );
program()->setUniformValue( m_centerCoordId, material->m_center );
program()->setUniformValue( m_aspectRatioId, material->m_aspectRatio );
program()->setUniformValue( m_startId, material->m_start );
program()->setUniformValue( m_spanId, material->m_span );
}
private:
int m_centerCoordId = -1;
int m_aspectRatioId = -1;
int m_startId = -1;
int m_spanId = -1;
};
@ -620,7 +635,7 @@ namespace
auto matNew = static_cast< ConicMaterial* >( newMaterial );
auto matOld = static_cast< ConicMaterial* >( oldMaterial );
Q_ASSERT( state.uniformData()->size() >= 84 );
Q_ASSERT( state.uniformData()->size() >= 88 );
auto data = state.uniformData()->data();
bool changed = false;
@ -639,22 +654,28 @@ namespace
changed = true;
}
if ( matOld == nullptr || matNew->m_aspectRatio != matOld->m_aspectRatio )
{
memcpy( data + 72, &matNew->m_aspectRatio, 4 );
changed = true;
}
if ( matOld == nullptr || matNew->m_start != matOld->m_start )
{
memcpy( data + 72, &matNew->m_start, 4 );
memcpy( data + 76, &matNew->m_start, 4 );
changed = true;
}
if ( matOld == nullptr || matNew->m_span != matOld->m_span )
{
memcpy( data + 76, &matNew->m_span, 4 );
memcpy( data + 80, &matNew->m_span, 4 );
changed = true;
}
if ( state.isOpacityDirty() )
{
const float opacity = state.opacity();
memcpy( data + 80, &opacity, 4 );
memcpy( data + 84, &opacity, 4 );
changed = true;
}

View File

@ -7,6 +7,7 @@ layout( std140, binding = 0 ) uniform buf
{
mat4 matrix;
vec2 centerCoord;
float aspectRatio;
float start;
float span;
float opacity;

View File

@ -7,6 +7,7 @@ layout( std140, binding = 0 ) uniform buf
{
mat4 matrix;
vec2 centerCoord;
float aspectRatio;
float start;
float span;
float opacity;
@ -17,5 +18,7 @@ out gl_PerVertex { vec4 gl_Position; };
void main()
{
coord = vertexCoord.xy - ubuf.centerCoord;
coord.y *= ubuf.aspectRatio;
gl_Position = ubuf.matrix * vertexCoord;
}

View File

@ -1,6 +1,7 @@
attribute vec4 vertexCoord;
uniform mat4 matrix;
uniform highp float aspectRatio;
uniform vec2 centerCoord;
varying vec2 coord;
@ -8,5 +9,7 @@ varying vec2 coord;
void main()
{
coord = vertexCoord.xy - centerCoord;
coord.y *= aspectRatio;
gl_Position = matrix * vertexCoord;
}