From 519203fbf5b3828f8478112831377ee7e8c56562 Mon Sep 17 00:00:00 2001 From: Chadnaut <63690461+Chadnaut@users.noreply.github.com> Date: Thu, 16 Jan 2025 23:45:22 +0800 Subject: [PATCH] Update fixed radius Update fixed radius --- src/fe_rectangle.cpp | 201 +++++++++++++++++++++++++++++++++++-------- src/fe_rectangle.hpp | 20 ++++- src/fe_vm.cpp | 4 + 3 files changed, 186 insertions(+), 39 deletions(-) diff --git a/src/fe_rectangle.cpp b/src/fe_rectangle.cpp index d26945f0..313885a0 100644 --- a/src/fe_rectangle.cpp +++ b/src/fe_rectangle.cpp @@ -26,6 +26,12 @@ #include "fe_shader.hpp" #include "fe_present.hpp" +namespace +{ + const float DELTA = 0.01; // Used to create non-zero rect size + const int MAX_CORNER_POINTS = 32; // Abitrary limit +} + FeRectangle::FeRectangle( FePresentableParent &p, float x, float y, float w, float h ) : FeBasePresentable( p ), @@ -39,9 +45,13 @@ FeRectangle::FeRectangle( FePresentableParent &p, m_rotation_origin_type( TopLeft ), m_blend_mode( FeBlend::Alpha ), m_corner_radius( 0.f, 0.f ), - m_corner_radius_auto( true ), + m_corner_ratio( 0.f, 0.f ), + m_corner_ratio_x( false ), + m_corner_ratio_y( false ), + m_corner_ratio_auto( false ), m_corner_point_count( 12 ), - m_rect( sf::Vector2f( w, h )) + m_corner_point_actual( -1 ), + m_rect( sf::Vector2f( w, h ), sf::Vector2f( 0, 0 ), 1 ) { setColor( sf::Color::White ); m_rect.setTextureRect( sf::IntRect( sf::Vector2i( 0, 0 ), sf::Vector2i( 1, 1 ))); @@ -353,36 +363,104 @@ float FeRectangle::get_corner_radius_y() const void FeRectangle::set_corner_radius_x( float rx ) { - update_corner_radius( rx, m_corner_radius.y, false ); + if ( m_corner_radius.x != rx || m_corner_ratio_x || m_corner_ratio_auto ) + { + m_corner_ratio_auto = false; + m_corner_ratio_x = false; + m_corner_radius.x = rx; + update_corner_radius(); + } } void FeRectangle::set_corner_radius_y( float ry ) { - update_corner_radius( m_corner_radius.x, ry, false ); + if ( m_corner_radius.y != ry || m_corner_ratio_y || m_corner_ratio_auto ) + { + m_corner_ratio_auto = false; + m_corner_ratio_y = false; + m_corner_radius.y = ry; + update_corner_radius(); + } } void FeRectangle::set_corner_radius( float rx, float ry ) { - update_corner_radius( rx, ry, false ); + if ( m_corner_radius.x != rx || m_corner_radius.y != ry || m_corner_ratio_x || m_corner_ratio_y || m_corner_ratio_auto ) + { + m_corner_ratio_auto = false; + m_corner_ratio_x = false; + m_corner_ratio_y = false; + m_corner_radius.x = rx; + m_corner_radius.y = ry; + update_corner_radius(); + } } void FeRectangle::set_corner_radius( float r ) { - update_corner_radius( r, r, true ); + set_corner_radius( r, r ); +} + +float FeRectangle::get_corner_ratio() const +{ + return m_corner_ratio.x; +} + +float FeRectangle::get_corner_ratio_x() const +{ + return m_corner_ratio.x; +} + +float FeRectangle::get_corner_ratio_y() const +{ + return m_corner_ratio.y; } -void FeRectangle::update_corner_radius( float rx, float ry, bool r_auto ) +void FeRectangle::set_corner_ratio_x( float rx ) { - if ( rx < 0.0 ) rx = 0.0; - if ( rx > 0.5 ) rx = 0.5; - if ( ry < 0.0 ) ry = 0.0; - if ( ry > 0.5 ) ry = 0.5; - if ( rx != m_corner_radius.x || ry != m_corner_radius.y || r_auto != m_corner_radius_auto ) + if ( m_corner_ratio.x != rx || !m_corner_ratio_x || m_corner_ratio_auto ) { - m_corner_radius.x = rx; - m_corner_radius.y = ry; - m_corner_radius_auto = r_auto; - scale(); + m_corner_ratio_auto = false; + m_corner_ratio_x = true; + m_corner_ratio.x = rx; + update_corner_ratio(); + } +} + +void FeRectangle::set_corner_ratio_y( float ry ) +{ + if ( m_corner_ratio.y != ry || !m_corner_ratio_y || m_corner_ratio_auto ) + { + m_corner_ratio_auto = false; + m_corner_ratio_y = true; + m_corner_ratio.y = ry; + update_corner_ratio(); + } +} + +void FeRectangle::set_corner_ratio( float rx, float ry ) +{ + if ( m_corner_ratio.x != rx || m_corner_ratio.y != ry || !m_corner_ratio_x || !m_corner_ratio_y || m_corner_ratio_auto ) + { + m_corner_ratio_auto = false; + m_corner_ratio_x = true; + m_corner_ratio_y = true; + m_corner_ratio.x = rx; + m_corner_ratio.y = ry; + update_corner_ratio(); + } +} + +void FeRectangle::set_corner_ratio( float r ) +{ + if ( m_corner_ratio.x != r || m_corner_ratio.y != r || !m_corner_ratio_x || !m_corner_ratio_y || !m_corner_ratio_auto ) + { + m_corner_ratio_auto = true; + m_corner_ratio_x = true; + m_corner_ratio_y = true; + m_corner_ratio.x = r; + m_corner_ratio.y = r; + update_corner_ratio(); } } @@ -393,13 +471,58 @@ int FeRectangle::get_corner_point_count() const void FeRectangle::set_corner_point_count( int n ) { - if ( n < 1 ) n = 1; - if ( n > 32 ) n = 32; // arbitrary limit - if ( n != m_corner_point_count ) + m_corner_point_count = n; + update_corner_points(); +} + +void FeRectangle::update_corner_points() +{ + // Reduce to a single corner if x or y radius is zero + int n = ( m_corner_radius.x != 0 && m_corner_radius.y != 0 && m_corner_point_count > 0 ) ? m_corner_point_count : 1; + if ( n > MAX_CORNER_POINTS ) n = MAX_CORNER_POINTS; + if ( m_corner_point_actual != n ) { - m_corner_point_count = n; - scale(); + m_corner_point_actual = n; + m_rect.setCornerPointCount( m_corner_point_actual ); + } +} + +void FeRectangle::update_corner_radius() +{ + // Ensure corners are < 0.5 rect size to prevent point overlap, which causes outline issues + float mx = std::max( DELTA, fabs( m_size.x ) - DELTA ); + float my = std::max( DELTA, fabs( m_size.y ) - DELTA ); + float rx = std::min( mx / 2, fabs( m_corner_radius.x ) ); + float ry = std::min( my / 2, fabs( m_corner_radius.y ) ); + + // Flip corners to fix negative size rectangles + if ( m_size.x < 0 ) rx = -rx; + if ( m_size.y < 0 ) ry = -ry; + + m_rect.setCornerRadius( sf::Vector2f( rx, ry ) ); + update_corner_points(); +} + +void FeRectangle::update_corner_ratio() +{ + // Ensure ratio corners have a non-zero size to use, otherwise a zero result creates square outlines + float mx = std::max( DELTA, fabs( m_size.x ) ); + float my = std::max( DELTA, fabs( m_size.y ) ); + + if ( m_corner_ratio_auto ) + { + // If AUTO use the smallest side for the radius + float s = m_corner_ratio.x * std::min( mx, my ); + m_corner_radius = sf::Vector2f( s, s ); } + else + { + // Otherwise calc ratios for each axis + if ( m_corner_ratio_x ) m_corner_radius.x = m_corner_ratio.x * mx; + if ( m_corner_ratio_y ) m_corner_radius.y = m_corner_ratio.y * my; + } + + update_corner_radius(); } sf::Vector2f FeRectangle::alignTypeToVector( int type ) @@ -457,24 +580,28 @@ void FeRectangle::draw( sf::RenderTarget &target, sf::RenderStates states ) cons void FeRectangle::scale() { - sf::Vector2f final_pos = m_position; + sf::Vector2f pos = m_position; + sf::Vector2f size = m_size; - final_pos += sf::Vector2f(( m_rotation_origin.x - m_anchor.x ) * m_size.x, ( m_rotation_origin.y - m_anchor.y ) * m_size.y ); + // update corners before checking if size needs adjusting + update_corner_ratio(); - m_rect.setPosition( final_pos ); - m_rect.setRotation( m_rotation ); - m_rect.setSize( m_size ); - m_rect.setOrigin(( m_origin.x + m_rotation_origin.x * m_size.x ), ( m_origin.y + m_rotation_origin.y * m_size.y )); - m_rect.setCornerPointCount( ( m_corner_radius.x > 0 && ( m_corner_radius_auto || m_corner_radius.y > 0 ) ) ? m_corner_point_count : 1 ); - - if ( m_corner_radius_auto ) - { - // When setting a single radius value it's stored in m_corner_radius.x - float s = m_corner_radius.x * std::min( abs( m_size.x ), abs( m_size.y ) ); - m_rect.setCornerRadius( sf::Vector2f( m_size.x > 0 ? s : -s, m_size.y > 0 ? s : -s ) ); - } - else + // If there's a corner ensure theres a non-zero area to draw it in + // - Fixes outline spike issue on zero-sized rectangles + if ( m_corner_radius.x != 0 || m_corner_radius.y != 0 ) { - m_rect.setCornerRadius( sf::Vector2f( m_corner_radius.x * m_size.x, m_corner_radius.y * m_size.y ) ); + // Use 2x Delta so corner can floor at 1x Delta (see above) + size.x = std::max( 2.0f * DELTA, fabs( m_size.x ) ); + size.y = std::max( 2.0f * DELTA, fabs( m_size.y ) ); + if (m_size.x < 0) size.x = -size.x; + if (m_size.y < 0) size.y = -size.y; } + + pos += sf::Vector2f(( m_rotation_origin.x - m_anchor.x ) * size.x, ( m_rotation_origin.y - m_anchor.y ) * size.y ); + + m_rect.setPosition( pos ); + m_rect.setRotation( m_rotation ); + m_rect.setSize( size ); + m_rect.setOrigin(( m_origin.x + m_rotation_origin.x * size.x ), ( m_origin.y + m_rotation_origin.y * size.y )); + } diff --git a/src/fe_rectangle.hpp b/src/fe_rectangle.hpp index f08dd480..0f85b021 100644 --- a/src/fe_rectangle.hpp +++ b/src/fe_rectangle.hpp @@ -78,9 +78,13 @@ class FeRectangle : public sf::Drawable, public FeBasePresentable int get_olg() const; int get_olb() const; int get_ola() const; + float get_corner_radius() const; float get_corner_radius_x() const; float get_corner_radius_y() const; + float get_corner_ratio() const; + float get_corner_ratio_x() const; + float get_corner_ratio_y() const; int get_corner_point_count() const; void set_origin_x( float x ); @@ -98,10 +102,15 @@ class FeRectangle : public sf::Drawable, public FeBasePresentable void set_olb( int b ); void set_ola( int a ); void set_olrgb( int r, int g, int b ); + void set_corner_radius( float r ); void set_corner_radius( float rx, float ry ); void set_corner_radius_x( float rx ); void set_corner_radius_y( float ry ); + void set_corner_ratio( float r ); + void set_corner_ratio( float rx, float ry ); + void set_corner_ratio_x( float rx ); + void set_corner_ratio_y( float ry ); void set_corner_point_count( int n ); int get_blend_mode() const; @@ -126,12 +135,19 @@ class FeRectangle : public sf::Drawable, public FeBasePresentable FeRectangle::Alignment m_rotation_origin_type; FeBlend::Mode m_blend_mode; float m_rotation; + int m_corner_point_count; + int m_corner_point_actual; sf::Vector2f m_corner_radius; - bool m_corner_radius_auto; + sf::Vector2f m_corner_ratio; + bool m_corner_ratio_x; + bool m_corner_ratio_y; + bool m_corner_ratio_auto; void scale(); - void update_corner_radius( float rx, float ry, bool r_auto ); + void update_corner_radius(); + void update_corner_ratio(); + void update_corner_points(); sf::Vector2f alignTypeToVector( int a ); }; diff --git a/src/fe_vm.cpp b/src/fe_vm.cpp index 22ddb803..009ed0ed 100644 --- a/src/fe_vm.cpp +++ b/src/fe_vm.cpp @@ -844,6 +844,10 @@ bool FeVM::on_new_layout() .Prop(_SC("corner_radius_y"), &FeRectangle::get_corner_radius_y, &FeRectangle::set_corner_radius_y ) .Prop(_SC("corner_radius"), &FeRectangle::get_corner_radius, &FeRectangle::set_corner_radius ) .Overload(_SC("set_corner_radius"), &FeRectangle::set_corner_radius) + .Prop(_SC("corner_ratio_x"), &FeRectangle::get_corner_ratio_x, &FeRectangle::set_corner_ratio_x ) + .Prop(_SC("corner_ratio_y"), &FeRectangle::get_corner_ratio_y, &FeRectangle::set_corner_ratio_y ) + .Prop(_SC("corner_ratio"), &FeRectangle::get_corner_ratio, &FeRectangle::set_corner_ratio ) + .Overload(_SC("set_corner_ratio"), &FeRectangle::set_corner_ratio) .Prop(_SC("blend_mode"), &FeRectangle::get_blend_mode, &FeRectangle::set_blend_mode ) .Func(_SC("set_outline_rgb"), &FeRectangle::set_olrgb ) .Func(_SC("set_anchor"), &FeRectangle::set_anchor )