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