Blender V5.0
mask_shapekey.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2012 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <cstdlib>
10
11#include "BLI_listbase.h"
12
13#include "BKE_context.hh"
14#include "BKE_mask.h"
15
16#include "DNA_mask_types.h"
17#include "DNA_scene_types.h"
18
19#include "DEG_depsgraph.hh"
20
21#include "RNA_access.hh"
22#include "RNA_define.hh"
23
24#include "WM_api.hh"
25#include "WM_types.hh"
26
27#include "ED_mask.hh" /* own include */
28
29#include "mask_intern.hh" /* own include */
30
32{
33 Scene *scene = CTX_data_scene(C);
34 const int frame = scene->r.cfra;
36 bool changed = false;
37
38 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
39 MaskLayerShape *mask_layer_shape;
40
41 if (!ED_mask_layer_select_check(mask_layer)) {
42 continue;
43 }
44
45 mask_layer_shape = BKE_mask_layer_shape_verify_frame(mask_layer, frame);
46 BKE_mask_layer_shape_from_mask(mask_layer, mask_layer_shape);
47 changed = true;
48 }
49
50 if (changed) {
52 DEG_id_tag_update(&mask->id, 0);
53
54 return OPERATOR_FINISHED;
55 }
56 return OPERATOR_CANCELLED;
57}
58
60{
61 /* identifiers */
62 ot->name = "Insert Shape Key";
63 ot->description = "Insert mask shape keyframe for active mask layer at the current frame";
64 ot->idname = "MASK_OT_shape_key_insert";
65
66 /* API callbacks. */
69
70 /* flags */
72}
73
75{
76 Scene *scene = CTX_data_scene(C);
77 const int frame = scene->r.cfra;
79 bool changed = false;
80
81 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
82 MaskLayerShape *mask_layer_shape;
83
84 if (!ED_mask_layer_select_check(mask_layer)) {
85 continue;
86 }
87
88 mask_layer_shape = BKE_mask_layer_shape_find_frame(mask_layer, frame);
89
90 if (mask_layer_shape) {
91 BKE_mask_layer_shape_unlink(mask_layer, mask_layer_shape);
92 changed = true;
93 }
94 }
95
96 if (changed) {
99
100 return OPERATOR_FINISHED;
101 }
102 return OPERATOR_CANCELLED;
103}
104
106{
107 /* identifiers */
108 ot->name = "Clear Shape Key";
109 ot->description = "Remove mask shape keyframe for active mask layer at the current frame";
110 ot->idname = "MASK_OT_shape_key_clear";
111
112 /* API callbacks. */
115
116 /* flags */
118}
119
121{
122 Scene *scene = CTX_data_scene(C);
123 const int frame = scene->r.cfra;
125 bool changed = false;
126
127 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
128
129 if (mask_layer->visibility_flag & (MASK_HIDE_VIEW | MASK_HIDE_SELECT)) {
130 continue;
131 }
132
133 if (mask_layer->splines_shapes.first) {
134 MaskLayerShape *mask_layer_shape_reset;
135
136 /* Get the shape-key of the current state. */
137 mask_layer_shape_reset = BKE_mask_layer_shape_alloc(mask_layer, frame);
138 /* Initialize from mask - as if inserting a keyframe. */
139 BKE_mask_layer_shape_from_mask(mask_layer, mask_layer_shape_reset);
140
141 LISTBASE_FOREACH (MaskLayerShape *, mask_layer_shape, &mask_layer->splines_shapes) {
142 if (mask_layer_shape_reset->tot_vert == mask_layer_shape->tot_vert) {
143 int i_abs = 0;
144 MaskLayerShapeElem *shape_ele_src;
145 MaskLayerShapeElem *shape_ele_dst;
146
147 shape_ele_src = (MaskLayerShapeElem *)mask_layer_shape_reset->data;
148 shape_ele_dst = (MaskLayerShapeElem *)mask_layer_shape->data;
149
150 LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
151 for (int i = 0; i < spline->tot_point; i++) {
152 MaskSplinePoint *point = &spline->points[i];
153
154 if (MASKPOINT_ISSEL_ANY(point)) {
155 /* TODO: nicer access here. */
156 shape_ele_dst->value[6] = shape_ele_src->value[6];
157 }
158
159 shape_ele_src++;
160 shape_ele_dst++;
161
162 i_abs++;
163 }
164 }
165 (void)i_abs; /* Quiet set-but-unused warning (may be removed). */
166 }
167 else {
168 // printf("%s: skipping\n", __func__);
169 }
170
171 changed = true;
172 }
173
174 BKE_mask_layer_shape_free(mask_layer_shape_reset);
175 }
176 }
177
178 if (changed) {
180 DEG_id_tag_update(&mask->id, 0);
181
182 return OPERATOR_FINISHED;
183 }
184 return OPERATOR_CANCELLED;
185}
186
188{
189 /* identifiers */
190 ot->name = "Feather Reset Animation";
191 ot->description = "Reset feather weights on all selected points animation values";
192 ot->idname = "MASK_OT_shape_key_feather_reset";
193
194 /* API callbacks. */
197
198 /* flags */
200}
201
202/*
203 * - loop over selected shape-keys.
204 * - find first-selected/last-selected pairs.
205 * - move these into a temp list.
206 * - re-key all the original shapes.
207 * - copy unselected values back from the original.
208 * - free the original.
209 */
211{
212 Scene *scene = CTX_data_scene(C);
213 const int frame = scene->r.cfra;
215 bool changed = false;
216
217 const bool do_feather = RNA_boolean_get(op->ptr, "feather");
218 const bool do_location = RNA_boolean_get(op->ptr, "location");
219
220 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
221 if (mask_layer->visibility_flag & (MASK_HIDE_VIEW | MASK_HIDE_SELECT)) {
222 continue;
223 }
224
225 /* we need at least one point selected here to bother re-interpolating */
226 if (!ED_mask_layer_select_check(mask_layer)) {
227 continue;
228 }
229
230 if (mask_layer->splines_shapes.first) {
231 MaskLayerShape *mask_layer_shape, *mask_layer_shape_next;
232 MaskLayerShape *mask_layer_shape_lastsel = nullptr;
233
234 for (mask_layer_shape = static_cast<MaskLayerShape *>(mask_layer->splines_shapes.first);
235 mask_layer_shape;
236 mask_layer_shape = mask_layer_shape_next)
237 {
238 MaskLayerShape *mask_layer_shape_a = nullptr;
239 MaskLayerShape *mask_layer_shape_b = nullptr;
240
241 mask_layer_shape_next = mask_layer_shape->next;
242
243 /* find contiguous selections */
244 if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
245 if (mask_layer_shape_lastsel == nullptr) {
246 mask_layer_shape_lastsel = mask_layer_shape;
247 }
248 if ((mask_layer_shape->next == nullptr) ||
249 (((MaskLayerShape *)mask_layer_shape->next)->flag & MASK_SHAPE_SELECT) == 0)
250 {
251 mask_layer_shape_a = mask_layer_shape_lastsel;
252 mask_layer_shape_b = mask_layer_shape;
253 mask_layer_shape_lastsel = nullptr;
254
255 /* this will be freed below, step over selection */
256 mask_layer_shape_next = mask_layer_shape->next;
257 }
258 }
259
260 /* we have a from<>to? - re-interpolate! */
261 if (mask_layer_shape_a && mask_layer_shape_b) {
262 ListBase shapes_tmp = {nullptr, nullptr};
263 MaskLayerShape *mask_layer_shape_tmp;
264 MaskLayerShape *mask_layer_shape_tmp_next;
265 MaskLayerShape *mask_layer_shape_tmp_last = mask_layer_shape_b->next;
266 MaskLayerShape *mask_layer_shape_tmp_rekey;
267
268 /* move keys */
269 for (mask_layer_shape_tmp = mask_layer_shape_a;
270 mask_layer_shape_tmp && (mask_layer_shape_tmp != mask_layer_shape_tmp_last);
271 mask_layer_shape_tmp = mask_layer_shape_tmp_next)
272 {
273 mask_layer_shape_tmp_next = mask_layer_shape_tmp->next;
274 BLI_remlink(&mask_layer->splines_shapes, mask_layer_shape_tmp);
275 BLI_addtail(&shapes_tmp, mask_layer_shape_tmp);
276 }
277
278 /* re-key, NOTE: can't modify the keys here since it messes up. */
279 for (mask_layer_shape_tmp = static_cast<MaskLayerShape *>(shapes_tmp.first);
280 mask_layer_shape_tmp;
281 mask_layer_shape_tmp = mask_layer_shape_tmp->next)
282 {
283 BKE_mask_layer_evaluate(mask_layer, mask_layer_shape_tmp->frame, true);
284 mask_layer_shape_tmp_rekey = BKE_mask_layer_shape_verify_frame(
285 mask_layer, mask_layer_shape_tmp->frame);
286 BKE_mask_layer_shape_from_mask(mask_layer, mask_layer_shape_tmp_rekey);
287 mask_layer_shape_tmp_rekey->flag = mask_layer_shape_tmp->flag & MASK_SHAPE_SELECT;
288 }
289
290 /* restore unselected points and free copies */
291 for (mask_layer_shape_tmp = static_cast<MaskLayerShape *>(shapes_tmp.first);
292 mask_layer_shape_tmp;
293 mask_layer_shape_tmp = mask_layer_shape_tmp_next)
294 {
295 /* restore */
296 int i_abs = 0;
297 MaskLayerShapeElem *shape_ele_src;
298 MaskLayerShapeElem *shape_ele_dst;
299
300 mask_layer_shape_tmp_next = mask_layer_shape_tmp->next;
301
302 /* we know this exists, added above */
303 mask_layer_shape_tmp_rekey = BKE_mask_layer_shape_find_frame(
304 mask_layer, mask_layer_shape_tmp->frame);
305
306 shape_ele_src = (MaskLayerShapeElem *)mask_layer_shape_tmp->data;
307 shape_ele_dst = (MaskLayerShapeElem *)mask_layer_shape_tmp_rekey->data;
308
309 LISTBASE_FOREACH (MaskSpline *, spline, &mask_layer->splines) {
310 for (int i = 0; i < spline->tot_point; i++) {
311 MaskSplinePoint *point = &spline->points[i];
312
313 /* not especially efficient but makes this easier to follow */
314 std::swap(*shape_ele_src, *shape_ele_dst);
315
316 if (MASKPOINT_ISSEL_ANY(point)) {
317 if (do_location) {
318 memcpy(shape_ele_dst->value, shape_ele_src->value, sizeof(float[6]));
319 }
320 if (do_feather) {
321 shape_ele_dst->value[6] = shape_ele_src->value[6];
322 }
323 }
324
325 shape_ele_src++;
326 shape_ele_dst++;
327
328 i_abs++;
329 }
330 }
331 (void)i_abs; /* Quiet set-but-unused warning (may be removed). */
332
333 BKE_mask_layer_shape_free(mask_layer_shape_tmp);
334 }
335
336 changed = true;
337 }
338 }
339
340 /* re-evaluate */
341 BKE_mask_layer_evaluate(mask_layer, frame, true);
342 }
343 }
344
345 if (changed) {
347 DEG_id_tag_update(&mask->id, 0);
348
349 return OPERATOR_FINISHED;
350 }
351 return OPERATOR_CANCELLED;
352}
353
355{
356 /* identifiers */
357 ot->name = "Re-Key Points of Selected Shapes";
358 ot->description =
359 "Recalculate animation data on selected points for frames selected in the dopesheet";
360 ot->idname = "MASK_OT_shape_key_rekey";
361
362 /* API callbacks. */
365
366 /* flags */
368
369 /* properties */
370 RNA_def_boolean(ot->srna, "location", true, "Location", "");
371 RNA_def_boolean(ot->srna, "feather", true, "Feather", "");
372}
373
374/* *** Shape Key Utils *** */
375
376void ED_mask_layer_shape_auto_key(MaskLayer *mask_layer, const int frame)
377{
378 MaskLayerShape *mask_layer_shape;
379
380 mask_layer_shape = BKE_mask_layer_shape_verify_frame(mask_layer, frame);
381 BKE_mask_layer_shape_from_mask(mask_layer, mask_layer_shape);
382}
383
385{
386 bool changed = false;
387
388 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
389 ED_mask_layer_shape_auto_key(mask_layer, frame);
390 changed = true;
391 }
392
393 return changed;
394}
395
397{
398 bool changed = false;
399
400 LISTBASE_FOREACH (MaskLayer *, mask_layer, &mask->masklayers) {
401
402 if (!ED_mask_layer_select_check(mask_layer)) {
403 continue;
404 }
405
406 ED_mask_layer_shape_auto_key(mask_layer, frame);
407 changed = true;
408 }
409
410 return changed;
411}
Mask * CTX_data_edit_mask(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
#define MASKPOINT_ISSEL_ANY(p)
Definition BKE_mask.h:292
void BKE_mask_layer_shape_unlink(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape)
struct MaskLayerShape * BKE_mask_layer_shape_alloc(struct MaskLayer *masklay, int frame)
void BKE_mask_layer_evaluate(struct MaskLayer *masklay, float ctime, bool do_newframe)
void BKE_mask_layer_shape_from_mask(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape)
void BKE_mask_layer_shape_free(struct MaskLayerShape *masklay_shape)
struct MaskLayerShape * BKE_mask_layer_shape_verify_frame(struct MaskLayer *masklay, int frame)
struct MaskLayerShape * BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, int frame)
#define LISTBASE_FOREACH(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
void BLI_remlink(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:131
void DEG_id_tag_update(ID *id, unsigned int flags)
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1074
@ MASK_HIDE_SELECT
@ MASK_HIDE_VIEW
@ MASK_SHAPE_SELECT
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
bool ED_maskedit_mask_visible_splines_poll(bContext *C)
Definition mask_edit.cc:76
#define C
Definition RandGen.cpp:29
#define ND_DATA
Definition WM_types.hh:509
@ OPTYPE_UNDO
Definition WM_types.hh:182
@ OPTYPE_REGISTER
Definition WM_types.hh:180
#define NC_MASK
Definition WM_types.hh:398
bool ED_mask_layer_select_check(const MaskLayer *mask_layer)
void MASK_OT_shape_key_insert(wmOperatorType *ot)
void MASK_OT_shape_key_feather_reset(wmOperatorType *ot)
static wmOperatorStatus mask_shape_key_rekey_exec(bContext *C, wmOperator *op)
void MASK_OT_shape_key_rekey(wmOperatorType *ot)
void MASK_OT_shape_key_clear(wmOperatorType *ot)
bool ED_mask_layer_shape_auto_key_select(Mask *mask, const int frame)
void ED_mask_layer_shape_auto_key(MaskLayer *mask_layer, const int frame)
bool ED_mask_layer_shape_auto_key_all(Mask *mask, const int frame)
static wmOperatorStatus mask_shape_key_insert_exec(bContext *C, wmOperator *)
static wmOperatorStatus mask_shape_key_feather_reset_exec(bContext *C, wmOperator *)
static wmOperatorStatus mask_shape_key_clear_exec(bContext *C, wmOperator *)
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, const bool default_value, const char *ui_name, const char *ui_description)
void * first
float value[MASK_OBJECT_SHAPE_ELEM_SIZE]
struct MaskLayerShape * next
struct RenderData r
struct PointerRNA * ptr
i
Definition text_draw.cc:230
void WM_event_add_notifier(const bContext *C, uint type, void *reference)
wmOperatorType * ot
Definition wm_files.cc:4237