Blender V4.5
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;
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
53
54 if (animrig::is_autokey_on(scene)) {
55 for (const int info_i : drawings.index_range()) {
56 bke::greasepencil::Layer &target_layer = grease_pencil.layer(drawings[info_i].layer_index);
57 const int current_frame = scene->r.cfra;
58 std::optional<int> start_frame = target_layer.start_frame_at(current_frame);
59 if (start_frame.has_value() && (start_frame.value() != current_frame)) {
60 grease_pencil.insert_duplicate_frame(
61 target_layer, *target_layer.start_frame_at(current_frame), current_frame, false);
62 }
63 }
64 drawings = ed::greasepencil::retrieve_editable_drawings_with_falloff(*scene, grease_pencil);
65 }
66
67 all_drawings.append(drawings);
68 total_number_of_drawings += drawings.size();
69 }
70
71 Array<Vector<IndexMask>> points_to_transform_per_attribute(total_number_of_drawings);
72 Array<IndexMask> bezier_curves(total_number_of_drawings);
73 int layer_offset = 0;
74
75 /* Count selected elements per layer per object and create TransData structs. */
76 for (const int i : trans_data_contrainers.index_range()) {
77 TransDataContainer &tc = trans_data_contrainers[i];
79 tc.custom.type);
80 tc.data_len = 0;
81
82 const Vector<ed::greasepencil::MutableDrawingInfo> drawings = all_drawings[i];
83 curves_transform_data->grease_pencil_falloffs.reinitialize(drawings.size());
84 for (ed::greasepencil::MutableDrawingInfo info : drawings) {
85 bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
87 curves);
88 std::array<IndexMask, 3> selection_per_attribute;
89
91 *object, info.drawing, info.layer_index, curves_transform_data->memory);
93 *object, info.drawing, info.layer_index, curves_transform_data->memory);
94
95 for (const int attribute_i : selection_attribute_names.index_range()) {
96 const StringRef &selection_name = selection_attribute_names[attribute_i];
97 selection_per_attribute[attribute_i] = ed::curves::retrieve_selected_points(
98 curves, selection_name, curves_transform_data->memory);
99
100 /* Make sure only editable points are used. */
101 selection_per_attribute[attribute_i] = IndexMask::from_intersection(
102 selection_per_attribute[attribute_i], editable_points, curves_transform_data->memory);
103 }
104
105 bezier_curves[layer_offset] = bke::curves::indices_for_type(curves.curve_types(),
106 curves.curve_type_counts(),
108 editable_strokes,
109 curves_transform_data->memory);
110 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
111 const IndexMask bezier_points = IndexMask::from_ranges(
112 points_by_curve, bezier_curves[layer_offset], curves_transform_data->memory);
113
114 /* Alter selection as in legacy curves bezt_select_to_transform_triple_flag(). */
115 if (!bezier_points.is_empty()) {
116 IndexMaskMemory memory;
117 /* Selected handles, but not the control point. */
118 const IndexMask selected_left = IndexMask::from_difference(
119 selection_per_attribute[1], selection_per_attribute[0], memory);
120 const IndexMask selected_right = IndexMask::from_difference(
121 selection_per_attribute[2], selection_per_attribute[0], memory);
122 MutableSpan<int8_t> handle_types_left = curves.handle_types_left_for_write();
123 MutableSpan<int8_t> handle_types_right = curves.handle_types_right_for_write();
124
125 curves::update_vector_handle_types(selected_left, handle_types_left);
126 curves::update_vector_handle_types(selected_right, handle_types_right);
128 selected_left, selected_right, bezier_points, handle_types_left, handle_types_right);
129 curves.tag_topology_changed();
130 info.drawing.tag_topology_changed();
131
133 const index_mask::Expr &selected_bezier_points = builder.intersect(
134 {&bezier_points, &selection_per_attribute[0]});
135
136 /* Select bezier handles that must be transformed because the control point is
137 * selected. */
138 selection_per_attribute[1] = evaluate_expression(
139 builder.merge({&selection_per_attribute[1], &selected_bezier_points}),
140 curves_transform_data->memory);
141 selection_per_attribute[2] = evaluate_expression(
142 builder.merge({&selection_per_attribute[2], &selected_bezier_points}),
143 curves_transform_data->memory);
144 }
145
146 if (use_proportional_edit) {
147 const IndexMask editable_bezier_points = IndexMask::from_intersection(
148 editable_points, bezier_points, curves_transform_data->memory);
149 tc.data_len += editable_points.size() + 2 * editable_bezier_points.size();
150 points_to_transform_per_attribute[layer_offset].append(editable_points);
151
152 if (selection_attribute_names.size() > 1) {
153 points_to_transform_per_attribute[layer_offset].append(editable_bezier_points);
154 points_to_transform_per_attribute[layer_offset].append(editable_bezier_points);
155 }
156 }
157 else {
158 for (const int selection_i : selection_attribute_names.index_range()) {
159 points_to_transform_per_attribute[layer_offset].append(
160 selection_per_attribute[selection_i]);
161 tc.data_len += points_to_transform_per_attribute[layer_offset][selection_i].size();
162 }
163 }
164
165 layer_offset++;
166 }
167
168 if (tc.data_len > 0) {
169 tc.data = MEM_calloc_arrayN<TransData>(tc.data_len, __func__);
170 curves_transform_data->positions.reinitialize(tc.data_len);
171 }
172 else {
173 tc.custom.type.free_cb(t, &tc, &tc.custom.type);
174 }
175 }
176
177 /* Reuse the variable `layer_offset`. */
178 layer_offset = 0;
179 IndexMaskMemory memory;
180
181 /* Populate TransData structs. */
182 for (const int i : trans_data_contrainers.index_range()) {
183 TransDataContainer &tc = trans_data_contrainers[i];
184 if (tc.data_len == 0) {
185 continue;
186 }
187 Object *object_eval = DEG_get_evaluated(depsgraph, tc.obedit);
188 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
189 Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
190
191 const Vector<ed::greasepencil::MutableDrawingInfo> drawings = all_drawings[i];
192 for (const int drawing : drawings.index_range()) {
193 ed::greasepencil::MutableDrawingInfo info = drawings[drawing];
194 const bke::greasepencil::Layer &layer = *layers[info.layer_index];
195 const float4x4 layer_space_to_world_space = layer.to_world_space(*object_eval);
197 const bke::crazyspace::GeometryDeformation deformation =
199 *CTX_data_depsgraph_pointer(C), *object, info.drawing);
200
201 std::optional<MutableSpan<float>> value_attribute;
202 if (t->mode == TFM_GPENCIL_OPACITY) {
204 value_attribute = opacities;
205 }
206 else if (is_scale_thickness) {
208 value_attribute = radii;
209 }
210
211 const IndexMask affected_strokes = use_proportional_edit || use_individual_origins ?
213 *object, info.drawing, info.layer_index, memory) :
214 IndexMask();
215
216 CurvesTransformData &curves_transform_data = *static_cast<CurvesTransformData *>(
217 tc.custom.type.data);
218 curves_transform_data.grease_pencil_falloffs[drawing] = info.multi_frame_falloff;
219 float &drawing_falloff = curves_transform_data.grease_pencil_falloffs[drawing];
221 tc,
222 curves,
223 layer_space_to_world_space,
224 deformation,
225 value_attribute,
226 points_to_transform_per_attribute[layer_offset],
227 affected_strokes,
228 use_connected_only,
229 bezier_curves[layer_offset],
230 &drawing_falloff);
231 layer_offset++;
232 }
233 }
234}
235
237{
238 if (t->state != TRANS_CANCEL) {
240 }
241
242 bContext *C = t->context;
243 Scene *scene = CTX_data_scene(C);
244
245 const Span<TransDataContainer> trans_data_contrainers(t->data_container, t->data_container_len);
246 for (const TransDataContainer &tc : trans_data_contrainers) {
247 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
248
251
252 int layer_i = 0;
253 for (const int64_t i : drawings.index_range()) {
256
257 if (t->mode == TFM_CURVE_SHRINKFATTEN) {
258 curves.tag_radii_changed();
259 }
260 else if (t->mode == TFM_TILT) {
261 curves.tag_normals_changed();
262 }
263 else {
264 const Vector<MutableSpan<float3>> positions_per_selection_attr =
266 for (MutableSpan<float3> positions : positions_per_selection_attr) {
268 tc.custom.type, layer_i++, positions);
269 }
270 curves.tag_positions_changed();
271 curves.calculate_bezier_auto_handles();
273 }
274 }
275
276 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
277 }
278}
279
281
283 /*flags*/ (T_EDIT | T_POINTS),
284 /*create_trans_data*/ createTransGreasePencilVerts,
285 /*recalc_data*/ recalcData_grease_pencil,
286 /*special_aftertrans_update*/ nullptr,
287};
288
289} // 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:982
@ CURVE_TYPE_BEZIER
@ 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:245
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)
static IndexMask from_difference(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
int64_t size() const
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)
Vector< MutableDrawingInfo > retrieve_editable_drawings(const Scene &scene, GreasePencil &grease_pencil)
void update_vector_handle_types(const IndexMask &selected_handles, MutableSpan< int8_t > handle_types)
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, const 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, const int layer, MutableSpan< float3 > positions_dst)
CurvesTransformData * create_curves_transform_custom_data(TransCustomData &custom_data)
void update_auto_handle_types(const IndexMask &selected_handles_left, const IndexMask &selected_handles_right, const IndexMask &bezier_points, MutableSpan< int8_t > handle_types_left, MutableSpan< int8_t > handle_types_right)
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
void(* free_cb)(TransInfo *, TransDataContainer *tc, TransCustomData *custom_data)
Definition transform.hh:628
TransDataContainer * data_container
Definition transform.hh:797
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.