From 40e978df858353cde679d0126fe62cc7168f39e6 Mon Sep 17 00:00:00 2001 From: MacDue Date: Fri, 2 Dec 2022 00:22:53 +0000 Subject: [PATCH] LibGfx: Fix some more antialiased line off-by-ones Turns out most things expect lines to include the endpoint, e.g. 0,0 -> 3,0 is a 4px long line. But the fill_path() implementation seems to expect the line to be the distance between the two points (so the above example is a 3px line instead). This now adds an option to pick between PointToPoint line length or Distance line length and uses the latter for fill_path(). --- .../Libraries/LibGfx/AntiAliasingPainter.cpp | 14 ++++++------- .../Libraries/LibGfx/AntiAliasingPainter.h | 20 ++++++++++++++++--- .../Libraries/LibGfx/FillPathImplementation.h | 4 ++-- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp b/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp index e8258d1a92..2994f12455 100644 --- a/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp +++ b/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp @@ -19,7 +19,7 @@ namespace Gfx { template -void AntiAliasingPainter::draw_anti_aliased_line(FloatPoint actual_from, FloatPoint actual_to, Color color, float thickness, Painter::LineStyle style, Color) +void AntiAliasingPainter::draw_anti_aliased_line(FloatPoint actual_from, FloatPoint actual_to, Color color, float thickness, Painter::LineStyle style, Color, LineLengthMode line_length_mode) { // FIXME: Implement this :P VERIFY(style == Painter::LineStyle::Solid); @@ -45,7 +45,7 @@ void AntiAliasingPainter::draw_anti_aliased_line(FloatPoint actual_from, FloatPo auto mapped_from = m_transform.map(actual_from); auto mapped_to = m_transform.map(actual_to); auto distance = mapped_to.distance_from(mapped_from); - auto length = distance + 1; + auto length = distance + (line_length_mode == LineLengthMode::PointToPoint); // Axis-aligned lines: if (mapped_from.y() == mapped_to.y()) { @@ -107,7 +107,7 @@ void AntiAliasingPainter::draw_anti_aliased_line(FloatPoint actual_from, FloatPo float x_error = 0; float x_error_per_y = x_gradient - x_step; - auto y_offset = int_thickness; + auto y_offset = int_thickness + 1; auto x_offset = int(x_gradient * y_offset); int const line_start_x = mapped_from.x(); int const line_start_y = mapped_from.y(); @@ -154,9 +154,9 @@ void AntiAliasingPainter::draw_anti_aliased_line(FloatPoint actual_from, FloatPo } } -void AntiAliasingPainter::draw_line_for_path(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Painter::LineStyle style, Color alternate_color) +void AntiAliasingPainter::draw_line_for_path(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Painter::LineStyle style, Color alternate_color, LineLengthMode line_length_mode) { - draw_anti_aliased_line(actual_from, actual_to, color, thickness, style, alternate_color); + draw_anti_aliased_line(actual_from, actual_to, color, thickness, style, alternate_color, line_length_mode); } void AntiAliasingPainter::draw_dotted_line(IntPoint point1, IntPoint point2, Color color, int thickness) @@ -201,11 +201,11 @@ void AntiAliasingPainter::draw_dotted_line(IntPoint point1, IntPoint point2, Col } } -void AntiAliasingPainter::draw_line(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Painter::LineStyle style, Color alternate_color) +void AntiAliasingPainter::draw_line(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Painter::LineStyle style, Color alternate_color, LineLengthMode line_length_mode) { if (style == Painter::LineStyle::Dotted) return draw_dotted_line(actual_from.to_rounded(), actual_to.to_rounded(), color, static_cast(round(thickness))); - draw_anti_aliased_line(actual_from, actual_to, color, thickness, style, alternate_color); + draw_anti_aliased_line(actual_from, actual_to, color, thickness, style, alternate_color, line_length_mode); } void AntiAliasingPainter::fill_path(Path& path, Color color, Painter::WindingRule rule) diff --git a/Userland/Libraries/LibGfx/AntiAliasingPainter.h b/Userland/Libraries/LibGfx/AntiAliasingPainter.h index 1b048af0e8..2ba0bdb211 100644 --- a/Userland/Libraries/LibGfx/AntiAliasingPainter.h +++ b/Userland/Libraries/LibGfx/AntiAliasingPainter.h @@ -19,8 +19,20 @@ public: { } - void draw_line(FloatPoint const&, FloatPoint const&, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent); - void draw_line_for_path(FloatPoint const&, FloatPoint const&, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent); + enum class LineLengthMode { + // E.g. A line from 0,1 -> 2,1 is 3px long + PointToPoint, + // E.g. A line from 0,1 -> 2,1 is 2px long + Distance + }; + + void draw_line(FloatPoint const&, FloatPoint const&, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent, LineLengthMode line_length_mode = LineLengthMode::PointToPoint); + void draw_line_for_path(FloatPoint const&, FloatPoint const&, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid, Color alternate_color = Color::Transparent, LineLengthMode line_length_mode = LineLengthMode::PointToPoint); + void draw_line_for_fill_path(FloatPoint const& from, FloatPoint const& to, Color color, float thickness = 1) + { + draw_line_for_path(from, to, color, thickness, Painter::LineStyle::Solid, Color {}, LineLengthMode::Distance); + } + void fill_path(Path&, Color, Painter::WindingRule rule = Painter::WindingRule::Nonzero); void stroke_path(Path const&, Color, float thickness); void draw_quadratic_bezier_curve(FloatPoint const& control_point, FloatPoint const&, FloatPoint const&, Color, float thickness = 1, Painter::LineStyle style = Painter::LineStyle::Solid); @@ -81,8 +93,10 @@ private: Yes, No, }; + template - void draw_anti_aliased_line(FloatPoint, FloatPoint, Color, float thickness, Painter::LineStyle style, Color alternate_color); + void draw_anti_aliased_line(FloatPoint, FloatPoint, Color, float thickness, Painter::LineStyle style, Color alternate_color, LineLengthMode line_length_mode = LineLengthMode::PointToPoint); + void stroke_segment_intersection(FloatPoint const& current_line_a, FloatPoint const& current_line_b, FloatLine const& previous_line, Color, float thickness); Painter& m_underlying_painter; diff --git a/Userland/Libraries/LibGfx/FillPathImplementation.h b/Userland/Libraries/LibGfx/FillPathImplementation.h index 238d6906c3..577d34a122 100644 --- a/Userland/Libraries/LibGfx/FillPathImplementation.h +++ b/Userland/Libraries/LibGfx/FillPathImplementation.h @@ -47,8 +47,8 @@ void fill_path(Painter& painter, Path const& path, Color color, Gfx::Painter::Wi using GridCoordinateType = Conditional; using PointType = Point; auto draw_line = [&](auto... args) { - if constexpr (requires { painter.draw_line_for_path(args...); }) - painter.draw_line_for_path(args...); + if constexpr (requires { painter.draw_line_for_fill_path(args...); }) + painter.draw_line_for_fill_path(args...); else painter.draw_line(args...); };