Blender V5.0
transform_convert_grease_pencil.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "ANIM_keyframing.hh"
10
11#include "BKE_context.hh"
12#include "BKE_curves_utils.hh"
13
15
17
18#include "ED_curves.hh"
19#include "ED_grease_pencil.hh"
20
21#include "transform.hh"
22#include "transform_convert.hh"
23#include "transform_snap.hh"
24
25/* -------------------------------------------------------------------- */
28
30
32{
34 Scene *scene = CTX_data_scene(C);
37 const bool use_proportional_edit = (t->flag & T_PROP_EDIT_ALL) != 0;
38 const bool use_connected_only = (t->flag & T_PROP_CONNECTED) != 0;
39 const bool use_individual_origins = (t->around == V3D_AROUND_LOCAL_ORIGINS);
40 ToolSettings *ts = scene->toolsettings;
41 const bool is_scale_thickness = ((t->mode == TFM_CURVE_SHRINKFATTEN) ||
43
44 int total_number_of_drawings = 0;
45 Vector<CurvesTransformData *> all_curves_transform_data;
46 /* Count the number layers in all objects. */
47 for (const int i : trans_data_contrainers.index_range()) {
48 TransDataContainer &tc = trans_data_contrainers[i];
49 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
50
52 tc.custom.type);
53
55 *scene, grease_pencil);
56
57 if (animrig::is_autokey_on(scene)) {
58 for (const int info_i : curves_transform_data->drawings.index_range()) {
59 bke::greasepencil::Layer &target_layer = grease_pencil.layer(
60 curves_transform_data->drawings[info_i].layer_index);
61 const int current_frame = scene->r.cfra;
62 std::optional<int> start_frame = target_layer.start_frame_at(current_frame);
63 if (start_frame.has_value() && (start_frame.value() != current_frame)) {
64 grease_pencil.insert_duplicate_frame(
65 target_layer, *target_layer.start_frame_at(current_frame), current_frame, false);
66 }
67 }
69 *scene, grease_pencil);
70 }
71
72 all_curves_transform_data.append(curves_transform_data);
73 total_number_of_drawings += curves_transform_data->drawings.size();
74 }
75
76 Array<Vector<IndexMask>> points_to_transform_per_attribute(total_number_of_drawings);
77 Array<IndexMask> bezier_curves(total_number_of_drawings);
78 int layer_offset = 0;
79
80 /* Count selected elements per layer per object and create TransData structs. */
81 for (const int i : trans_data_contrainers.index_range()) {
82 TransDataContainer &tc = trans_data_contrainers[i];
83 CurvesTransformData &curves_transform_data = *all_curves_transform_data[i];
84 tc.data_len = 0;
85
87 curves_transform_data.drawings.as_span();
88 curves_transform_data.grease_pencil_falloffs.reinitialize(drawings.size());
89
90 for (ed::greasepencil::MutableDrawingInfo info : drawings) {
91 bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
93 curves);
94 std::array<IndexMask, 3> selection_per_attribute;
95
97 *object, info.drawing, info.layer_index, curves_transform_data.memory);
99 *object, info.drawing, info.layer_index, curves_transform_data.memory);
100
101 bezier_curves[layer_offset] = bke::curves::indices_for_type(curves.curve_types(),
102 curves.curve_type_counts(),
104 editable_strokes,
105 curves_transform_data.memory);
106 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
107 const IndexMask bezier_points = IndexMask::from_ranges(
108 points_by_curve, bezier_curves[layer_offset], curves_transform_data.memory);
109
110 for (const int attribute_i : selection_attribute_names.index_range()) {
111 const StringRef &selection_name = selection_attribute_names[attribute_i];
112 selection_per_attribute[attribute_i] = ed::curves::retrieve_selected_points(
113 curves, selection_name, bezier_points, curves_transform_data.memory);
114
115 /* Make sure only editable points are used. */
116 selection_per_attribute[attribute_i] = IndexMask::from_intersection(
117 selection_per_attribute[attribute_i], editable_points, curves_transform_data.memory);
118 }
119
120 /* Alter selection as in legacy curves bezt_select_to_transform_triple_flag(). */
121 if (!bezier_points.is_empty()) {
123 t->mode, selection_per_attribute, bezier_points, curves))
124 {
125 info.drawing.tag_topology_changed();
126 }
127
129 const index_mask::Expr &selected_bezier_points = builder.intersect(
130 {&bezier_points, &selection_per_attribute[0]});
131
132 /* Select bezier handles that must be transformed because the control point is
133 * selected. */
134 selection_per_attribute[1] = evaluate_expression(
135 builder.merge({&selection_per_attribute[1], &selected_bezier_points}),
136 curves_transform_data.memory);
137 selection_per_attribute[2] = evaluate_expression(
138 builder.merge({&selection_per_attribute[2], &selected_bezier_points}),
139 curves_transform_data.memory);
140 }
141
142 if (use_proportional_edit) {
143 const IndexMask editable_bezier_points = IndexMask::from_intersection(
144 editable_points, bezier_points, curves_transform_data.memory);
145 tc.data_len += editable_points.size() + 2 * editable_bezier_points.size();
146 points_to_transform_per_attribute[layer_offset].append(editable_points);
147
148 if (selection_attribute_names.size() > 1) {
149 points_to_transform_per_attribute[layer_offset].append(editable_bezier_points);
150 points_to_transform_per_attribute[layer_offset].append(editable_bezier_points);
151 }
152 }
153 else {
154 for (const int selection_i : selection_attribute_names.index_range()) {
155 points_to_transform_per_attribute[layer_offset].append(
156 selection_per_attribute[selection_i]);
157 tc.data_len += points_to_transform_per_attribute[layer_offset][selection_i].size();
158 }
159 }
160
161 layer_offset++;
162 }
163
164 if (tc.data_len > 0) {
165 tc.data = MEM_calloc_arrayN<TransData>(tc.data_len, __func__);
166 curves_transform_data.positions.reinitialize(tc.data_len);
167 }
168 else {
169 tc.custom.type.free_cb(t, &tc, &tc.custom.type);
170 }
171 }
172
173 /* Reuse the variable `layer_offset`. */
174 layer_offset = 0;
175 IndexMaskMemory memory;
176
177 /* Populate TransData structs. */
178 for (const int i : trans_data_contrainers.index_range()) {
179 TransDataContainer &tc = trans_data_contrainers[i];
180 if (tc.data_len == 0) {
181 continue;
182 }
183 Object *object_eval = DEG_get_evaluated(depsgraph, tc.obedit);
184 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
185 Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
186
187 CurvesTransformData &transform_data = *static_cast<CurvesTransformData *>(tc.custom.type.data);
188 const Span<ed::greasepencil::MutableDrawingInfo> drawings = transform_data.drawings.as_span();
189
190 transform_data.aligned_with_left.reinitialize(drawings.size());
191 transform_data.aligned_with_right.reinitialize(drawings.size());
192
193 for (const int drawing : drawings.index_range()) {
194 ed::greasepencil::MutableDrawingInfo info = drawings[drawing];
195 const bke::greasepencil::Layer &layer = *layers[info.layer_index];
196 const float4x4 layer_space_to_world_space = layer.to_world_space(*object_eval);
198 const bke::crazyspace::GeometryDeformation deformation =
200 *CTX_data_depsgraph_pointer(C), *object, info.drawing);
201
202 std::optional<MutableSpan<float>> value_attribute;
203 if (t->mode == TFM_GPENCIL_OPACITY) {
205 value_attribute = opacities;
206 }
207 else if (is_scale_thickness) {
209 value_attribute = radii;
210 }
211
212 const IndexMask affected_strokes = use_proportional_edit || use_individual_origins ?
214 *object, info.drawing, info.layer_index, memory) :
215 IndexMask();
216
217 CurvesTransformData &curves_transform_data = *static_cast<CurvesTransformData *>(
218 tc.custom.type.data);
219 curves_transform_data.grease_pencil_falloffs[drawing] = info.multi_frame_falloff;
220 float &drawing_falloff = curves_transform_data.grease_pencil_falloffs[drawing];
222 tc,
223 curves,
224 layer_space_to_world_space,
225 deformation,
226 value_attribute,
227 points_to_transform_per_attribute[layer_offset],
228 affected_strokes,
229 use_connected_only,
230 bezier_curves[layer_offset],
231 &drawing_falloff);
233 curves, points_to_transform_per_attribute[layer_offset], drawing, tc.custom.type);
234
235 layer_offset++;
236 }
237 }
238}
239
241{
242 if (t->state != TRANS_CANCEL) {
244 }
245
246 const Span<TransDataContainer> trans_data_contrainers(t->data_container, t->data_container_len);
247 for (const TransDataContainer &tc : trans_data_contrainers) {
248 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
249 const CurvesTransformData &transform_data = *static_cast<CurvesTransformData *>(
250 tc.custom.type.data);
251
252 const Vector<ed::greasepencil::MutableDrawingInfo> drawings = transform_data.drawings;
253
254 int layer_i = 0;
255 for (const int64_t i : drawings.index_range()) {
258
259 if (t->mode == TFM_CURVE_SHRINKFATTEN) {
260 curves.tag_radii_changed();
261 }
262 else if (t->mode == TFM_TILT) {
263 curves.tag_normals_changed();
264 }
265 else {
266 const Vector<MutableSpan<float3>> positions_per_selection_attr =
268 for (MutableSpan<float3> positions : positions_per_selection_attr) {
270 tc.custom.type, layer_i++, positions);
271 }
272 curves.tag_positions_changed();
273 curves.calculate_bezier_auto_handles();
276 }
277 }
278
279 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
280 }
281}
282
284
286 /*flags*/ (T_EDIT | T_POINTS),
287 /*create_trans_data*/ createTransGreasePencilVerts,
288 /*recalc_data*/ recalcData_grease_pencil,
289 /*special_aftertrans_update*/ nullptr,
290};
291
292} // namespace blender::ed::transform::greasepencil
Functions to insert, delete or modify keyframes.
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
Object * CTX_data_active_object(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Low-level operations for curves.
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
@ GP_SCULPT_SETT_FLAG_SCALE_THICKNESS
@ V3D_AROUND_LOCAL_ORIGINS
#define C
Definition RandGen.cpp:29
BPy_StructRNA * depsgraph
long long int int64_t
void reinitialize(const int64_t new_size)
int64_t size() const
Definition BLI_array.hh:256
static IndexMask from_ranges(OffsetIndices< T > offsets, const IndexMask &mask, IndexMaskMemory &memory)
static IndexMask from_intersection(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
constexpr IndexRange index_range() const
Definition BLI_span.hh:670
constexpr int64_t size() const
Definition BLI_span.hh:252
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
void append(const T &value)
IndexRange index_range() const
MutableSpan< float > opacities_for_write()
MutableSpan< float > radii_for_write()
bke::CurvesGeometry & strokes_for_write()
float4x4 to_world_space(const Object &object) const
std::optional< int > start_frame_at(int frame_number) const
const IntersectionExpr & intersect(const Span< Term > terms)
const UnionExpr & merge(const Span< Term > terms)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
bool is_autokey_on(const Scene *scene)
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval, const Object &ob_orig, const bke::greasepencil::Drawing &drawing_orig)
IndexMask indices_for_type(const VArray< int8_t > &types, const std::array< int, CURVE_TYPES_NUM > &type_counts, const CurveType type, const IndexMask &selection, IndexMaskMemory &memory)
Vector< MutableSpan< float3 > > get_curves_positions_for_write(bke::CurvesGeometry &curves)
Span< StringRef > get_curves_selection_attribute_names(const bke::CurvesGeometry &curves)
IndexMask retrieve_selected_points(const bke::CurvesGeometry &curves, IndexMaskMemory &memory)
IndexMask retrieve_editable_points(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
Vector< MutableDrawingInfo > retrieve_editable_drawings_with_falloff(const Scene &scene, GreasePencil &grease_pencil)
IndexMask retrieve_editable_strokes(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
void create_aligned_handles_masks(const bke::CurvesGeometry &curves, Span< IndexMask > points_to_transform_per_attr, int curve_index, TransCustomData &custom_data)
CurvesTransformData * create_curves_transform_custom_data(TransCustomData &custom_data)
void calculate_aligned_handles(const TransCustomData &custom_data, bke::CurvesGeometry &curves, int curve_index)
bool update_handle_types_for_transform(eTfmMode mode, const std::array< IndexMask, 3 > &selection_per_attribute, const IndexMask &bezier_points, bke::CurvesGeometry &curves)
void curve_populate_trans_data_structs(const TransInfo &t, TransDataContainer &tc, bke::CurvesGeometry &curves, const float4x4 &transform, const bke::crazyspace::GeometryDeformation &deformation, std::optional< MutableSpan< float > > value_attribute, Span< IndexMask > points_to_transform_per_attr, const IndexMask &affected_curves, bool use_connected_only, const IndexMask &bezier_curves, void *extra=nullptr)
void copy_positions_from_curves_transform_custom_data(const TransCustomData &custom_data, int layer, MutableSpan< float3 > positions_dst)
static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
void transform_snap_project_individual_apply(TransInfo *t)
MatBase< float, 4, 4 > float4x4
struct ToolSettings * toolsettings
struct RenderData r
struct GP_Sculpt_Settings gp_sculpt
Vector< ed::greasepencil::MutableDrawingInfo > drawings
void(* free_cb)(TransInfo *, TransDataContainer *tc, TransCustomData *custom_data)
Definition transform.hh:633
TransDataContainer * data_container
Definition transform.hh:802
i
Definition text_draw.cc:230
#define T_PROP_EDIT_ALL
Definition transform.hh:28
conversion and adaptation of different datablocks to a common struct.