From 645aeb9dbe21acabd5a981fa33d55d095bf8e783 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20T=C3=B6nne?= Date: Thu, 7 Mar 2024 15:15:57 +0100 Subject: [PATCH] Fix #119055: GPv3: Set end caps correctly with hard eraser The hard eraser changes end caps to "flat" when cutting strokes. This requires detecting when the start or end points of a stroke have been cut. The previous method relied on checking the next curve's start point for cuts to determine end point cuts, but this only holds true for cutting strokes in the middle. When only the start point is cut the preceding curve should not be affected. The new test uses local properties of the `PointTransferData` to detect unchanged source curve end points, instead of doing a look-ahead for the next curve. This works using the source point indices, which are inverted for end points. Combined with checking for the `is_cut` flag this gives a reliable answer to when a stroke end point is cut. Pull Request: https://projects.blender.org/blender/blender/pulls/119151 --- .../sculpt_paint/grease_pencil_erase.cc | 29 ++++++++++++------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/source/blender/editors/sculpt_paint/grease_pencil_erase.cc b/source/blender/editors/sculpt_paint/grease_pencil_erase.cc index f05279de402..f5676043fff 100644 --- a/source/blender/editors/sculpt_paint/grease_pencil_erase.cc +++ b/source/blender/editors/sculpt_paint/grease_pencil_erase.cc @@ -382,6 +382,17 @@ struct EraseOperationExecutor { float factor; bool is_src_point; bool is_cut; + + /** + * Source point is the last of the curve. + */ + bool is_src_end_point() const + { + /* The src_next_point index increments for all points except the last, where it is set to the + * first point index. This can be used to detect the curve end from the source index alone. + */ + return is_src_point && src_point >= src_next_point; + } }; /** @@ -547,18 +558,16 @@ struct EraseOperationExecutor { threading::parallel_for(dst.curves_range(), 4096, [&](const IndexRange dst_curves) { for (const int dst_curve : dst_curves) { const IndexRange dst_curve_points = dst_points_by_curve[dst_curve]; - if (dst_transfer_data[dst_curve_points.first()].is_cut) { + const PointTransferData &start_point_transfer = + dst_transfer_data[dst_curve_points.first()]; + const PointTransferData &end_point_transfer = dst_transfer_data[dst_curve_points.last()]; + + if (start_point_transfer.is_cut) { dst_start_caps.span[dst_curve] = GP_STROKE_CAP_TYPE_FLAT; } - - if (dst_curve == dst_curves.last()) { - continue; - } - - const PointTransferData &next_point_transfer = - dst_transfer_data[dst_points_by_curve[dst_curve + 1].first()]; - - if (next_point_transfer.is_cut) { + /* The is_cut flag does not work for end points, but any end point that isn't the source + * point must also be a cut. */ + if (!end_point_transfer.is_src_end_point()) { dst_end_caps.span[dst_curve] = GP_STROKE_CAP_TYPE_FLAT; } }