diff --git a/source/blender/editors/sculpt_paint/grease_pencil_intern.hh b/source/blender/editors/sculpt_paint/grease_pencil_intern.hh index 46c01d99ec9..431a743d152 100644 --- a/source/blender/editors/sculpt_paint/grease_pencil_intern.hh +++ b/source/blender/editors/sculpt_paint/grease_pencil_intern.hh @@ -201,6 +201,11 @@ class GreasePencilStrokeOperationCommon : public GreasePencilStrokeOperation { const IndexMask &points, const DeltaProjectionFunc &projection_fn)> fn) const; + void foreach_editable_drawing( + const bContext &C, + FunctionRef fn) const; + /** Used in vertex paint mode. */ void foreach_editable_drawing( const bContext &C, FunctionRef fn) const; diff --git a/source/blender/editors/sculpt_paint/grease_pencil_paint_common.cc b/source/blender/editors/sculpt_paint/grease_pencil_paint_common.cc index bfb71c6b991..6592f2d3a1b 100644 --- a/source/blender/editors/sculpt_paint/grease_pencil_paint_common.cc +++ b/source/blender/editors/sculpt_paint/grease_pencil_paint_common.cc @@ -529,6 +529,49 @@ void GreasePencilStrokeOperationCommon::foreach_editable_drawing( } } +void GreasePencilStrokeOperationCommon::foreach_editable_drawing( + const bContext &C, + FunctionRef fn) const +{ + using namespace blender::bke::greasepencil; + + const Scene &scene = *CTX_data_scene(&C); + Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C); + ARegion ®ion = *CTX_wm_region(&C); + RegionView3D &rv3d = *CTX_wm_region_view3d(&C); + Object &object = *CTX_data_active_object(&C); + Object &object_eval = *DEG_get_evaluated_object(&depsgraph, &object); + GreasePencil &grease_pencil = *static_cast(object.data); + + bool changed = false; + const Vector drawings = get_drawings_for_stroke_operation(C); + for (const int64_t i : drawings.index_range()) { + const MutableDrawingInfo &info = drawings[i]; + const Layer &layer = grease_pencil.layer(info.layer_index); + GreasePencilStrokeParams params = GreasePencilStrokeParams::from_context( + scene, + depsgraph, + region, + rv3d, + object, + info.layer_index, + info.frame_number, + info.multi_frame_falloff, + info.drawing); + + const DeltaProjectionFunc projection_fn = get_screen_projection_fn(params, object_eval, layer); + if (fn(params, projection_fn)) { + changed = true; + } + } + + if (changed) { + DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil); + } +} + void GreasePencilStrokeOperationCommon::foreach_editable_drawing( const bContext &C, const GrainSize grain_size, diff --git a/source/blender/editors/sculpt_paint/grease_pencil_sculpt_clone.cc b/source/blender/editors/sculpt_paint/grease_pencil_sculpt_clone.cc index 3e51cacfbcd..5b59d915212 100644 --- a/source/blender/editors/sculpt_paint/grease_pencil_sculpt_clone.cc +++ b/source/blender/editors/sculpt_paint/grease_pencil_sculpt_clone.cc @@ -7,6 +7,8 @@ #include "BKE_grease_pencil.hh" #include "BKE_paint.hh" +#include "BLI_bounds.hh" + #include "ED_curves.hh" #include "ED_grease_pencil.hh" #include "ED_view3d.hh" @@ -30,11 +32,6 @@ class CloneOperation : public GreasePencilStrokeOperationCommon { void on_stroke_done(const bContext & /*C*/) override {} }; -static float2 arithmetic_mean(Span values) -{ - return std::accumulate(values.begin(), values.end(), float2(0)) / values.size(); -} - void CloneOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample) { Main &bmain = *CTX_data_main(&C); @@ -49,11 +46,8 @@ void CloneOperation::on_stroke_begin(const bContext &C, const InputSample &start * - Continuous: Create multiple copies during the stroke (disabled) * * Here we only have the GPv2 behavior that actually works for now. */ - this->foreach_editable_drawing_with_automask( - C, - [&](const GreasePencilStrokeParams ¶ms, - const IndexMask & /*point_mask*/, - const DeltaProjectionFunc &projection_fn) { + this->foreach_editable_drawing( + C, [&](const GreasePencilStrokeParams ¶ms, const DeltaProjectionFunc &projection_fn) { /* Only insert on the active layer. */ if (¶ms.layer != grease_pencil.get_active_layer()) { return false; @@ -68,7 +62,6 @@ void CloneOperation::on_stroke_begin(const bContext &C, const InputSample &start return false; } - const bke::crazyspace::GeometryDeformation deformation = get_drawing_deformation(params); bke::CurvesGeometry &curves = params.drawing.strokes_for_write(); const OffsetIndices pasted_points_by_curve = curves.points_by_curve().slice( pasted_curves); @@ -78,15 +71,27 @@ void CloneOperation::on_stroke_begin(const bContext &C, const InputSample &start return false; } - Array view_positions = calculate_view_positions(params, pasted_points); - const float2 center = arithmetic_mean( - view_positions.as_mutable_span().slice(pasted_points)); - const float2 &mouse_delta = start_sample.mouse_position - center; + const Bounds bounds = *bounds::min_max(curves.positions().slice(pasted_points)); + const float4x4 transform = params.layer.to_world_space(params.ob_eval); + /* FIXME: Projecting the center of the bounds to the view can sometimes fail. This might + * result in unexpected behavior on the user end. Figure out a way to not rely on view + * space here and compute the translation offset in layer space instead. */ + float2 view_center(0.0f); + if (ED_view3d_project_float_global(¶ms.region, + math::transform_point(transform, bounds.center()), + view_center, + V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) + { + return false; + } + + const float2 &mouse_delta = start_sample.mouse_position - view_center; + const bke::crazyspace::GeometryDeformation deformation = get_drawing_deformation(params); MutableSpan positions = curves.positions_for_write(); threading::parallel_for(pasted_points, 4096, [&](const IndexRange range) { for (const int point_i : range) { - positions[point_i] = compute_orig_delta( + positions[point_i] += compute_orig_delta( projection_fn, deformation, point_i, mouse_delta); } });