Blender V4.3
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
9#include "ANIM_keyframing.hh"
10
11#include "BKE_context.hh"
12
14
15#include "BKE_curves_utils.hh"
16
17#include "ED_curves.hh"
18#include "ED_grease_pencil.hh"
19
20#include "transform.hh"
21#include "transform_convert.hh"
22
23/* -------------------------------------------------------------------- */
28
30{
32 Scene *scene = CTX_data_scene(C);
33 Object *object = CTX_data_active_object(C);
35 const bool use_proportional_edit = (t->flag & T_PROP_EDIT_ALL) != 0;
36 const bool use_connected_only = (t->flag & T_PROP_CONNECTED) != 0;
37 ToolSettings *ts = scene->toolsettings;
38 const bool is_scale_thickness = ((t->mode == TFM_CURVE_SHRINKFATTEN) ||
40
41 Vector<int> handle_selection;
42
43 int total_number_of_drawings = 0;
45 /* Count the number layers in all objects. */
46 for (const int i : trans_data_contrainers.index_range()) {
47 TransDataContainer &tc = trans_data_contrainers[i];
48 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
49
52
54 for (const int info_i : drawings.index_range()) {
55 blender::bke::greasepencil::Layer &target_layer = grease_pencil.layer(
56 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(*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 for (ed::greasepencil::MutableDrawingInfo info : drawings) {
84 const bke::CurvesGeometry &curves = info.drawing.strokes();
86 curves);
87 std::array<IndexMask, 3> selection_per_attribute;
88
90 *object, info.drawing, info.layer_index, curves_transform_data->memory);
91 const IndexMask selected_editable_strokes =
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 selected_editable_strokes,
109 curves_transform_data->memory);
110 /* Alter selection as in legacy curves bezt_select_to_transform_triple_flag(). */
111 if (!bezier_curves[layer_offset].is_empty()) {
112 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
113 const VArray<int8_t> handle_types_left = curves.handle_types_left();
114 const VArray<int8_t> handle_types_right = curves.handle_types_right();
115
116 handle_selection.clear();
117 bezier_curves[layer_offset].foreach_index([&](const int bezier_index) {
118 for (const int point_i : points_by_curve[bezier_index]) {
119 if (selection_per_attribute[0].contains(point_i)) {
120 const HandleType type_left = HandleType(handle_types_left[point_i]);
121 const HandleType type_right = HandleType(handle_types_right[point_i]);
124 {
125 handle_selection.append(point_i);
126 }
127 }
128 }
129 });
130
131 /* Select bezier handles that must be transformed if the main control point is selected. */
132 const IndexMask handle_selection_mask = IndexMask::from_indices(
133 handle_selection.as_span(), curves_transform_data->memory);
134 if (!handle_selection.is_empty()) {
135 selection_per_attribute[1] = IndexMask::from_union(
136 selection_per_attribute[1], handle_selection_mask, curves_transform_data->memory);
137 selection_per_attribute[2] = IndexMask::from_union(
138 selection_per_attribute[2], handle_selection_mask, curves_transform_data->memory);
139 }
140 }
141
142 if (use_proportional_edit) {
143 Array<int> bezier_point_offset_data(bezier_curves[layer_offset].size() + 1);
145 curves.points_by_curve(), bezier_curves[layer_offset], bezier_point_offset_data);
146
147 const int bezier_point_count = bezier_offsets.total_size();
148 tc.data_len += curves.points_num() + 2 * bezier_point_count;
149 points_to_transform_per_attribute[layer_offset].append(curves.points_range());
150
151 if (bezier_point_count > 0) {
153 const OffsetIndices<int> points_by_curve = curves.points_by_curve();
154 bezier_curves[layer_offset].foreach_index(GrainSize(512), [&](const int bezier_curve_i) {
155 bezier_point_ranges.append(points_by_curve[bezier_curve_i]);
156 });
157 IndexMask bezier_points = IndexMask::from_initializers(bezier_point_ranges,
158 curves_transform_data->memory);
159 points_to_transform_per_attribute[layer_offset].append(bezier_points);
160 points_to_transform_per_attribute[layer_offset].append(bezier_points);
161 }
162 }
163 else {
164 for (const int selection_i : selection_attribute_names.index_range()) {
165 points_to_transform_per_attribute[layer_offset].append(
166 selection_per_attribute[selection_i]);
167 tc.data_len += points_to_transform_per_attribute[layer_offset][selection_i].size();
168 }
169 }
170
171 layer_offset++;
172 }
173
174 if (tc.data_len > 0) {
175 tc.data = MEM_cnew_array<TransData>(tc.data_len, __func__);
176 curves_transform_data->positions.reinitialize(tc.data_len);
177 }
178 else {
179 tc.custom.type.free_cb(t, &tc, &tc.custom.type);
180 }
181 }
182
183 /* Reuse the variable `layer_offset`. */
184 layer_offset = 0;
185 IndexMaskMemory memory;
186
187 /* Populate TransData structs. */
188 for (const int i : trans_data_contrainers.index_range()) {
189 TransDataContainer &tc = trans_data_contrainers[i];
190 if (tc.data_len == 0) {
191 continue;
192 }
194 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
195 Span<const bke::greasepencil::Layer *> layers = grease_pencil.layers();
196
197 const Vector<ed::greasepencil::MutableDrawingInfo> drawings = all_drawings[i];
198 for (ed::greasepencil::MutableDrawingInfo info : drawings) {
199 const bke::greasepencil::Layer &layer = *layers[info.layer_index];
200 const float4x4 layer_space_to_world_space = layer.to_world_space(*object_eval);
201 bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
202
203 std::optional<MutableSpan<float>> value_attribute;
204 if (is_scale_thickness) {
205 MutableSpan<float> radii = info.drawing.radii_for_write();
206 value_attribute = radii;
207 }
208 else if (t->mode == TFM_GPENCIL_OPACITY) {
209 MutableSpan<float> opacities = info.drawing.opacities_for_write();
210 value_attribute = opacities;
211 }
212
213 const IndexMask affected_strokes = use_proportional_edit ?
215 *object, info.drawing, info.layer_index, memory) :
216 IndexMask();
218 curves,
219 layer_space_to_world_space,
220 value_attribute,
221 points_to_transform_per_attribute[layer_offset],
222 affected_strokes,
223 use_connected_only,
224 bezier_curves[layer_offset]);
225 layer_offset++;
226 }
227 }
228}
229
231{
232 bContext *C = t->context;
233 Scene *scene = CTX_data_scene(C);
234
235 const Span<TransDataContainer> trans_data_contrainers(t->data_container, t->data_container_len);
236 for (const TransDataContainer &tc : trans_data_contrainers) {
237 GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
238
241
242 int layer_i = 0;
243 for (const int64_t i : drawings.index_range()) {
244 ed::greasepencil::MutableDrawingInfo info = drawings[i];
246
247 if (t->mode == TFM_CURVE_SHRINKFATTEN) {
248 /* No cache to update currently. */
249 }
250 else if (t->mode == TFM_TILT) {
251 /* No cache to update currently. */
252 }
253 else {
254 const Vector<MutableSpan<float3>> positions_per_selection_attr =
256 for (MutableSpan<float3> positions : positions_per_selection_attr) {
257 copy_positions_from_curves_transform_custom_data(tc.custom.type, layer_i++, positions);
258 }
259 curves.tag_positions_changed();
260 curves.calculate_bezier_auto_handles();
262 }
263 }
264
265 DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
266 }
267}
268
269} // namespace blender::ed::transform::greasepencil
270
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.
#define ELEM(...)
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
@ CURVE_TYPE_BEZIER
HandleType
@ BEZIER_HANDLE_ALIGN
@ BEZIER_HANDLE_AUTO
@ GP_SCULPT_SETT_FLAG_SCALE_THICKNESS
@ TFM_CURVE_SHRINKFATTEN
@ TFM_TILT
@ TFM_GPENCIL_OPACITY
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
int64_t size() const
Definition BLI_array.hh:245
constexpr IndexRange index_range() const
Definition BLI_span.hh:671
constexpr IndexRange index_range() const
Definition BLI_span.hh:402
int64_t size() const
void append(const T &value)
bool is_empty() const
IndexRange index_range() const
Span< T > as_span() const
bke::CurvesGeometry & strokes_for_write()
std::optional< int > start_frame_at(int frame_number) const
static IndexMask from_union(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
static IndexMask from_intersection(const IndexMask &mask_a, const IndexMask &mask_b, IndexMaskMemory &memory)
static IndexMask from_indices(Span< T > indices, IndexMaskMemory &memory)
static IndexMask from_initializers(const Span< Initializer > initializers, IndexMaskMemory &memory)
const Depsgraph * depsgraph
bool is_autokey_on(const Scene *scene)
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_and_selected_strokes(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
IndexMask retrieve_editable_points(Object &object, const bke::greasepencil::Drawing &drawing, int layer_index, IndexMaskMemory &memory)
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)
static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
OffsetIndices< int > gather_selected_offsets(OffsetIndices< int > src_offsets, const IndexMask &selection, int start_offset, MutableSpan< int > dst_offsets)
__int64 int64_t
Definition stdint.h:89
blender::IndexMaskMemory memory
blender::Array< blender::float3 > positions
struct GP_Sculpt_Settings gp_sculpt
TransCustomData type
Definition transform.hh:425
void(* free_cb)(TransInfo *, TransDataContainer *tc, TransCustomData *custom_data)
Definition transform.hh:409
TransCustomDataContainer custom
Definition transform.hh:501
TransData * data
Definition transform.hh:445
eTfmMode mode
Definition transform.hh:517
int data_container_len
Definition transform.hh:506
eTFlag flag
Definition transform.hh:523
TransDataContainer * data_container
Definition transform.hh:505
bContext * context
Definition transform.hh:649
@ T_PROP_CONNECTED
Definition transform.hh:99
@ T_POINTS
Definition transform.hh:93
@ T_EDIT
Definition transform.hh:91
#define T_PROP_EDIT_ALL
Definition transform.hh:157
conversion and adaptation of different datablocks to a common struct.
void curve_populate_trans_data_structs(TransDataContainer &tc, blender::bke::CurvesGeometry &curves, const blender::float4x4 &transform, std::optional< blender::MutableSpan< float > > value_attribute, const blender::Span< blender::IndexMask > points_to_transform_indices, const blender::IndexMask &affected_curves, bool use_connected_only, const blender::IndexMask &bezier_curves)
CurvesTransformData * create_curves_transform_custom_data(TransCustomData &custom_data)
void copy_positions_from_curves_transform_custom_data(const TransCustomData &custom_data, const int layer, blender::MutableSpan< blender::float3 > positions_dst)
TransConvertTypeInfo TransConvertType_GreasePencil