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

View File

@ -97,8 +97,14 @@ class QSK_EXPORT QskGradient
void setRadialDirection( const qreal x, qreal y, qreal radiusX, qreal radiusY ); void setRadialDirection( const qreal x, qreal y, qreal radiusX, qreal radiusY );
QskRadialDirection radialDirection() const; QskRadialDirection radialDirection() const;
void setConicDirection( qreal, qreal ); void setConicDirection( qreal x, qreal y );
void setConicDirection( qreal, qreal, qreal, qreal = 360.0 );
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& ); void setConicDirection( const QskConicDirection& );
QskConicDirection conicDirection() const; QskConicDirection conicDirection() const;
@ -172,9 +178,9 @@ class QSK_EXPORT QskGradient
/* /*
Linear: x1, y1, x2, y2 Linear: x1, y1, x2, y2
Radial: centerX, centerY, radiusX, radiusY 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_type : 3;
unsigned int m_spreadMode : 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 ); m_spanAngle = qBound( -360.0, degrees, 360.0 );
} }
void QskConicDirection::setAspectRatio( qreal ratio ) noexcept
{
m_aspectRatio = qMax( ratio, 0.0 );
}
// -- QskRadialDirection // -- QskRadialDirection
void QskRadialDirection::setCenter( const QPointF& center ) noexcept 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 y READ y WRITE setY )
Q_PROPERTY( qreal startAngle READ startAngle WRITE setStartAngle ) Q_PROPERTY( qreal startAngle READ startAngle WRITE setStartAngle )
Q_PROPERTY( qreal spanAngle READ spanAngle WRITE setSpanAngle ) Q_PROPERTY( qreal spanAngle READ spanAngle WRITE setSpanAngle )
Q_PROPERTY( qreal aspectRatio READ aspectRatio WRITE setAspectRatio )
public: public:
// counter-clockwise // counter-clockwise
constexpr QskConicDirection() noexcept = default; constexpr QskConicDirection() noexcept = default;
constexpr QskConicDirection( qreal x, qreal y, qreal startAngle = 0.0 ) noexcept; 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 = 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; constexpr QPointF center() const noexcept;
void setCenter(const QPointF& center) noexcept; void setCenter(const QPointF& center) noexcept;
@ -132,11 +135,15 @@ class QSK_EXPORT QskConicDirection
constexpr qreal spanAngle() const noexcept; constexpr qreal spanAngle() const noexcept;
void setSpanAngle( qreal ) noexcept; void setSpanAngle( qreal ) noexcept;
constexpr qreal aspectRatio() const noexcept;
void setAspectRatio( qreal ) noexcept;
private: private:
qreal m_x = 0.5; qreal m_x = 0.5;
qreal m_y = 0.5; qreal m_y = 0.5;
qreal m_startAngle = 0.0; qreal m_startAngle = 0.0;
qreal m_spanAngle = 360.0; qreal m_spanAngle = 360.0;
qreal m_aspectRatio = 0.0;
}; };
class QSK_EXPORT QskRadialDirection class QSK_EXPORT QskRadialDirection
@ -299,12 +306,13 @@ inline constexpr QskConicDirection::QskConicDirection(
{ {
} }
inline constexpr QskConicDirection::QskConicDirection( inline constexpr QskConicDirection::QskConicDirection( qreal x, qreal y,
qreal x, qreal y, qreal startAngle, qreal spanAngle ) noexcept qreal startAngle, qreal spanAngle, qreal aspectRatio ) noexcept
: m_x( x ) : m_x( x )
, m_y( y ) , m_y( y )
, m_startAngle( startAngle ) , m_startAngle( startAngle )
, m_spanAngle( spanAngle ) , m_spanAngle( spanAngle )
, m_aspectRatio( aspectRatio )
{ {
} }
@ -314,9 +322,9 @@ inline constexpr QskConicDirection::QskConicDirection(
{ {
} }
inline constexpr QskConicDirection::QskConicDirection( inline constexpr QskConicDirection::QskConicDirection( const QPointF& pos,
const QPointF& pos, qreal startAngle, qreal spanAngle ) noexcept qreal startAngle, qreal spanAngle, qreal apectRatio ) noexcept
: QskConicDirection( pos.x(), pos.y(), startAngle, spanAngle ) : QskConicDirection( pos.x(), pos.y(), startAngle, spanAngle, apectRatio )
{ {
} }
@ -345,6 +353,11 @@ inline constexpr qreal QskConicDirection::y() const noexcept
return m_y; return m_y;
} }
inline constexpr qreal QskConicDirection::aspectRatio() const noexcept
{
return m_aspectRatio;
}
inline constexpr QskRadialDirection::QskRadialDirection( inline constexpr QskRadialDirection::QskRadialDirection(
qreal x, qreal y, qreal radius ) noexcept qreal x, qreal y, qreal radius ) noexcept
: m_x( x ) : m_x( x )

View File

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

View File

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

View File

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

View File

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