From 4f56261f768ebee744133eaa63e27233657a9d44 Mon Sep 17 00:00:00 2001 From: Amelie Date: Mon, 24 Jul 2023 17:04:39 +0200 Subject: [PATCH] GPv3: Stroke mode for the Eraser tool Implementation of the stroke mode of the eraser tool for grease pencil. In this mode, the eraser removes each stroke that it touches, meaning each stroke that either intersects the eraser or that has all points inside of it. Pull Request: https://projects.blender.org/blender/blender/pulls/110304 --- .../sculpt_paint/grease_pencil_erase.cc | 52 ++++++++++++++++++- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/sculpt_paint/grease_pencil_erase.cc b/source/blender/editors/sculpt_paint/grease_pencil_erase.cc index 076699a50d7..6355d6e1612 100644 --- a/source/blender/editors/sculpt_paint/grease_pencil_erase.cc +++ b/source/blender/editors/sculpt_paint/grease_pencil_erase.cc @@ -450,6 +450,54 @@ struct EraseOperationExecutor { return true; } + + bool stroke_eraser(const blender::bke::CurvesGeometry &src, + const Array &screen_space_positions, + blender::bke::CurvesGeometry &dst) const + { + const OffsetIndices src_points_by_curve = src.points_by_curve(); + const VArray src_cyclic = src.cyclic(); + + IndexMaskMemory memory; + IndexMask strokes_to_remove = IndexMask::from_predicate( + src.curves_range(), GrainSize(256), memory, [&](const int64_t src_curve) { + const IndexRange src_curve_points = src_points_by_curve[src_curve]; + + /* If any segment of the stroke is closer to the eraser than its radius, then remove the + * stroke. */ + for (const int src_point : src_curve_points.drop_back(1)) { + const float dist_to_eraser = dist_to_line_segment_v2( + this->mouse_position, + screen_space_positions[src_point], + screen_space_positions[src_point + 1]); + if (dist_to_eraser < this->eraser_radius) { + return true; + } + } + + if (src_cyclic[src_curve]) { + const float dist_to_eraser = dist_to_line_segment_v2( + this->mouse_position, + screen_space_positions[src_curve_points.first()], + screen_space_positions[src_curve_points.last()]); + if (dist_to_eraser < this->eraser_radius) { + return true; + } + } + + return false; + }); + + if (strokes_to_remove.size() == 0) { + return false; + } + + dst = std::move(src); + dst.remove_curves(strokes_to_remove); + + return true; + } + void execute(EraseOperation &self, const bContext &C, const InputSample &extension_sample) { using namespace blender::bke::greasepencil; @@ -491,8 +539,8 @@ struct EraseOperationExecutor { bool erased = false; switch (self.eraser_mode) { case GP_BRUSH_ERASER_STROKE: - // To be implemented - return; + erased = stroke_eraser(src, screen_space_positions, dst); + break; case GP_BRUSH_ERASER_HARD: erased = hard_eraser(src, screen_space_positions, dst, self.keep_caps); break;