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
This commit is contained in:
Lukas Tönne
2024-03-07 15:15:57 +01:00
parent 2a18bbbdbc
commit 645aeb9dbe

View File

@@ -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;
}
}