Browse Source

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().
MacDue 2 years ago
parent
commit
40e978df85

+ 7 - 7
Userland/Libraries/LibGfx/AntiAliasingPainter.cpp

@@ -19,7 +19,7 @@
 namespace Gfx {
 
 template<AntiAliasingPainter::FixmeEnableHacksForBetterPathPainting path_hacks>
-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<FixmeEnableHacksForBetterPathPainting::Yes>(actual_from, actual_to, color, thickness, style, alternate_color);
+    draw_anti_aliased_line<FixmeEnableHacksForBetterPathPainting::Yes>(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<int>(), actual_to.to_rounded<int>(), color, static_cast<int>(round(thickness)));
-    draw_anti_aliased_line<FixmeEnableHacksForBetterPathPainting::No>(actual_from, actual_to, color, thickness, style, alternate_color);
+    draw_anti_aliased_line<FixmeEnableHacksForBetterPathPainting::No>(actual_from, actual_to, color, thickness, style, alternate_color, line_length_mode);
 }
 
 void AntiAliasingPainter::fill_path(Path& path, Color color, Painter::WindingRule rule)

+ 17 - 3
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<FixmeEnableHacksForBetterPathPainting path_hacks>
-    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;

+ 2 - 2
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<fill_path_mode == FillPathMode::PlaceOnIntGrid, int, float>;
     using PointType = Point<GridCoordinateType>;
     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...);
     };