Blender V4.3
grease_pencil_sculpt_grab.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "BKE_context.hh"
6#include "BKE_crazyspace.hh"
7#include "BKE_curves.hh"
9#include "BKE_paint.hh"
10
11#include "BLI_index_mask.hh"
12#include "BLI_math_matrix.hh"
13#include "BLI_task.hh"
14
16
18#include "DNA_view3d_types.h"
19#include "ED_grease_pencil.hh"
20#include "ED_view3d.hh"
21
22#include "WM_api.hh"
23#include "WM_types.hh"
24
26#include "paint_intern.hh"
27
29
31 public:
34
35 /* Cached point mask and influence for a particular drawing. */
36 struct PointWeights {
40
41 /* Layer space to view space projection at the start of the stroke. */
43 /* Points that are grabbed at the beginning of the stroke. */
45 /* Influence weights for grabbed points. */
47
49 };
50 /* Cached point data for each affected drawing. */
52
55 const DeltaProjectionFunc &projection_fn,
56 const IndexMask &mask,
57 Span<float> weights)> fn) const;
58
59 void on_stroke_begin(const bContext &C, const InputSample &start_sample) override;
60 void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override;
61 void on_stroke_done(const bContext & /*C*/) override {}
62};
63
65 const bContext &C,
67 const DeltaProjectionFunc &projection_fn,
68 const IndexMask &mask,
69 Span<float> weights)> fn) const
70{
73
74 const Scene &scene = *CTX_data_scene(&C);
75 Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
76 ARegion &region = *CTX_wm_region(&C);
78 Object &object = *CTX_data_active_object(&C);
79 Object &object_eval = *DEG_get_evaluated_object(&depsgraph, &object);
80 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object.data);
81
82 bool changed = false;
83 threading::parallel_for_each(this->drawing_data.index_range(), [&](const int i) {
84 const PointWeights &data = this->drawing_data[i];
85 if (data.point_mask.is_empty()) {
86 return;
87 }
88 const Layer &layer = grease_pencil.layer(data.layer_index);
89 /* If a new frame is created, could be impossible find the stroke. */
90 bke::greasepencil::Drawing *drawing = grease_pencil.get_drawing_at(layer, data.frame_number);
91 if (drawing == nullptr) {
92 return;
93 }
94
96 scene,
98 region,
99 rv3d,
100 object,
101 data.layer_index,
102 data.frame_number,
103 data.multi_frame_falloff,
104 *drawing);
105 DeltaProjectionFunc projection_fn = get_screen_projection_fn(params, object_eval, layer);
106 if (fn(params, projection_fn, data.point_mask, data.weights)) {
107 changed = true;
108 }
109 });
110
111 if (changed) {
112 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
113 WM_event_add_notifier(&C, NC_GEOM | ND_DATA, &grease_pencil);
114 }
115}
116
117void GrabOperation::on_stroke_begin(const bContext &C, const InputSample &start_sample)
118{
119 const ARegion &region = *CTX_wm_region(&C);
120 const RegionView3D &rv3d = *CTX_wm_region_view3d(&C);
121 const Scene &scene = *CTX_data_scene(&C);
123 Brush &brush = *BKE_paint_brush(&paint);
124 const Depsgraph &depsgraph = *CTX_data_depsgraph_pointer(&C);
125 Object &ob_orig = *CTX_data_active_object(&C);
126 Object &ob_eval = *DEG_get_evaluated_object(&depsgraph, &ob_orig);
127 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
128
129 const bool is_masking = GPENCIL_ANY_SCULPT_MASK(
130 eGP_Sculpt_SelectMaskFlag(scene.toolsettings->gpencil_selectmode_sculpt));
131
132 init_brush(brush);
133
134 this->prev_mouse_position = start_sample.mouse_position;
135
137 this->drawing_data.reinitialize(drawings.size());
138 threading::parallel_for_each(drawings.index_range(), [&](const int i) {
139 const MutableDrawingInfo &info = drawings[i];
140 BLI_assert(info.layer_index >= 0);
141 PointWeights &data = this->drawing_data[i];
142
143 const bke::greasepencil::Layer &layer = grease_pencil.layer(info.layer_index);
144 BLI_assert(grease_pencil.get_drawing_at(layer, info.frame_number) == &info.drawing);
145
146 GreasePencilStrokeParams params = {*scene.toolsettings,
147 region,
148 rv3d,
149 scene,
150 ob_orig,
151 ob_eval,
152 layer,
153 info.layer_index,
154 info.frame_number,
155 info.multi_frame_falloff,
156 info.drawing};
157 IndexMaskMemory selection_memory;
158 IndexMask selection = point_selection_mask(params, is_masking, selection_memory);
159
160 Array<float2> view_positions = calculate_view_positions(params, selection);
161
162 /* Cache points under brush influence. */
163 Vector<float> weights;
164 IndexMask point_mask = brush_point_influence_mask(scene,
165 brush,
166 start_sample.mouse_position,
167 1.0f,
168 info.multi_frame_falloff,
169 selection,
170 view_positions,
171 weights,
172 data.memory);
173
174 if (point_mask.is_empty()) {
175 /* Set empty point mask to skip. */
176 data.point_mask = {};
177 return;
178 }
179 data.layer_index = info.layer_index;
180 data.frame_number = info.frame_number;
181 data.multi_frame_falloff = info.multi_frame_falloff;
182 data.layer_to_win = ED_view3d_ob_project_mat_get(&rv3d, &ob_eval) *
183 layer.to_object_space(ob_eval);
184 data.point_mask = std::move(point_mask);
185 data.weights = std::move(weights);
186 });
187}
188
189void GrabOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
190{
191 this->foreach_grabbed_drawing(
192 C,
194 const DeltaProjectionFunc &projection_fn,
195 const IndexMask &mask,
196 const Span<float> weights) {
197 /* Transform mouse delta into layer space. */
198 const float2 mouse_delta_win = this->mouse_delta(extension_sample);
199
200 bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
202 MutableSpan<float3> positions = curves.positions_for_write();
203 mask.foreach_index(GrainSize(4096), [&](const int point_i, const int index) {
204 /* Translate the point with the influence factor. */
205 positions[point_i] = projection_fn(deformation.positions[point_i],
206 mouse_delta_win * weights[index]);
207 });
208
209 params.drawing.tag_positions_changed();
210 return true;
211 });
212 this->stroke_extended(extension_sample);
213}
214
215std::unique_ptr<GreasePencilStrokeOperation> new_grab_operation(const BrushStrokeMode stroke_mode)
216{
217 return std::make_unique<GrabOperation>(stroke_mode);
218}
219
220} // namespace blender::ed::sculpt_paint::greasepencil
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
RegionView3D * CTX_wm_region_view3d(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
Low-level operations for curves.
Low-level operations for grease pencil.
Paint * BKE_paint_get_active_from_context(const bContext *C)
Definition paint.cc:477
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:649
void DEG_id_tag_update(ID *id, unsigned int flags)
Object * DEG_get_evaluated_object(const Depsgraph *depsgraph, Object *object)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
#define GPENCIL_ANY_SCULPT_MASK(flag)
eGP_Sculpt_SelectMaskFlag
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
#define NC_GEOM
Definition WM_types.hh:360
#define ND_DATA
Definition WM_types.hh:475
IndexRange index_range() const
Definition BLI_array.hh:349
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:388
int64_t size() const
IndexRange index_range() const
void foreach_grabbed_drawing(const bContext &C, FunctionRef< bool(const GreasePencilStrokeParams &params, const DeltaProjectionFunc &projection_fn, const IndexMask &mask, Span< float > weights)> fn) const
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override
const Depsgraph * depsgraph
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
std::unique_ptr< GreasePencilStrokeOperation > new_grab_operation(BrushStrokeMode stroke_mode)
Vector< ed::greasepencil::MutableDrawingInfo > get_drawings_for_painting(const bContext &C)
IndexMask point_selection_mask(const GreasePencilStrokeParams &params, const bool use_masking, IndexMaskMemory &memory)
Array< float2 > calculate_view_positions(const GreasePencilStrokeParams &params, const IndexMask &selection)
IndexMask brush_point_influence_mask(const Scene &scene, const Brush &brush, const float2 &mouse_position, float pressure, float multi_frame_falloff, const IndexMask &selection, Span< float2 > view_positions, Vector< float > &influences, IndexMaskMemory &memory)
bke::crazyspace::GeometryDeformation get_drawing_deformation(const GreasePencilStrokeParams &params)
DeltaProjectionFunc get_screen_projection_fn(const GreasePencilStrokeParams &params, const Object &object, const bke::greasepencil::Layer &layer)
std::function< float3(const float3 position, const float2 &screen_delta)> DeltaProjectionFunc
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:58
BrushStrokeMode
static GreasePencilStrokeParams from_context(const Scene &scene, Depsgraph &depsgraph, ARegion &region, RegionView3D &rv3d, Object &object, int layer_index, int frame_number, float multi_frame_falloff, bke::greasepencil::Drawing &drawing)
void WM_event_add_notifier(const bContext *C, uint type, void *reference)