Blender V5.0
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_task.hh"
13
15
17#include "DNA_view3d_types.h"
18
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);
76 ARegion &region = *CTX_wm_region(&C);
78 Object &object = *CTX_data_active_object(&C);
79 Object &object_eval = *DEG_get_evaluated(&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(&depsgraph, &ob_orig);
127 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_orig.data);
128
129 init_brush(brush);
130 init_auto_masking(C, start_sample);
131
132 this->prev_mouse_position = start_sample.mouse_position;
133
135 this->drawing_data.reinitialize(drawings.size());
136 threading::parallel_for_each(drawings.index_range(), [&](const int i) {
137 const MutableDrawingInfo &info = drawings[i];
138 const AutoMaskingInfo &auto_mask_info = this->auto_masking_info_per_drawing[i];
139 BLI_assert(info.layer_index >= 0);
140 PointWeights &data = this->drawing_data[i];
141
142 const bke::greasepencil::Layer &layer = grease_pencil.layer(info.layer_index);
143 BLI_assert(grease_pencil.get_drawing_at(layer, info.frame_number) == &info.drawing);
144
145 GreasePencilStrokeParams params = {*scene.toolsettings,
146 region,
147 rv3d,
148 scene,
149 ob_orig,
150 ob_eval,
151 layer,
152 info.layer_index,
153 info.frame_number,
154 info.multi_frame_falloff,
155 info.drawing};
156
157 Array<float2> view_positions = calculate_view_positions(params, auto_mask_info.point_mask);
158
159 /* Cache points under brush influence. */
160 Vector<float> weights;
162 brush,
163 start_sample.mouse_position,
164 1.0f,
165 info.multi_frame_falloff,
166 auto_mask_info.point_mask,
167 view_positions,
168 weights,
169 data.memory);
170
171 if (point_mask.is_empty()) {
172 /* Set empty point mask to skip. */
173 data.point_mask = {};
174 return;
175 }
176 data.layer_index = info.layer_index;
177 data.frame_number = info.frame_number;
178 data.multi_frame_falloff = info.multi_frame_falloff;
179 data.layer_to_win = ED_view3d_ob_project_mat_get(&rv3d, &ob_eval) *
180 layer.to_object_space(ob_eval);
181 data.point_mask = std::move(point_mask);
182 data.weights = std::move(weights);
183 });
184}
185
186void GrabOperation::on_stroke_extended(const bContext &C, const InputSample &extension_sample)
187{
189 C,
191 const DeltaProjectionFunc &projection_fn,
192 const IndexMask &mask,
193 const Span<float> weights) {
194 /* Transform mouse delta into layer space. */
195 const float2 mouse_delta_win = this->mouse_delta(extension_sample);
196
197 bke::CurvesGeometry &curves = params.drawing.strokes_for_write();
199 MutableSpan<float3> positions = curves.positions_for_write();
200 mask.foreach_index(GrainSize(4096), [&](const int point_i, const int index) {
201 /* Translate the point with the influence factor. */
202 positions[point_i] += compute_orig_delta(
203 projection_fn, deformation, point_i, mouse_delta_win * weights[index]);
204 });
205
206 params.drawing.tag_positions_changed();
207 return true;
208 });
209 this->stroke_extended(extension_sample);
210}
211
212std::unique_ptr<GreasePencilStrokeOperation> new_grab_operation(const BrushStrokeMode stroke_mode)
213{
214 return std::make_unique<GrabOperation>(stroke_mode);
215}
216
217} // 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:476
Brush * BKE_paint_brush(Paint *paint)
Definition paint.cc:645
void DEG_id_tag_update(ID *id, unsigned int flags)
T * DEG_get_evaluated(const Depsgraph *depsgraph, T *id)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
blender::float4x4 ED_view3d_ob_project_mat_get(const RegionView3D *rv3d, const Object *ob)
#define C
Definition RandGen.cpp:29
#define NC_GEOM
Definition WM_types.hh:393
#define ND_DATA
Definition WM_types.hh:509
BMesh const char void * data
BPy_StructRNA * depsgraph
IndexRange index_range() const
Definition BLI_array.hh:360
void reinitialize(const int64_t new_size)
Definition BLI_array.hh:419
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
blender::ed::greasepencil::MutableDrawingInfo MutableDrawingInfo
void on_stroke_begin(const bContext &C, const InputSample &start_sample) override
void on_stroke_extended(const bContext &C, const InputSample &extension_sample) override
void init_auto_masking(const bContext &C, const InputSample &start_sample)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
std::unique_ptr< GreasePencilStrokeOperation > new_grab_operation(BrushStrokeMode stroke_mode)
IndexMask brush_point_influence_mask(const Paint &paint, 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)
Array< float2 > calculate_view_positions(const GreasePencilStrokeParams &params, const IndexMask &selection)
Vector< ed::greasepencil::MutableDrawingInfo > get_drawings_with_masking_for_stroke_operation(const bContext &C)
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)
float3 compute_orig_delta(const DeltaProjectionFunc &projection_fn, const bke::crazyspace::GeometryDeformation &deformation, int index, const float2 &screen_delta)
std::function< float3(const float3 position, const float2 &screen_delta)> DeltaProjectionFunc
void parallel_for_each(Range &&range, const Function &function)
Definition BLI_task.hh:56
MatBase< float, 4, 4 > float4x4
VecBase< float, 2 > float2
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)
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)