Blender  V3.3
mask_editaction.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. */
3 
8 #include <math.h>
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 
14 #include "MEM_guardedalloc.h"
15 
16 #include "BLI_blenlib.h"
17 #include "BLI_utildefines.h"
18 
19 #include "DNA_mask_types.h"
20 #include "DNA_scene_types.h"
21 
22 #include "BKE_fcurve.h"
23 #include "BKE_mask.h"
24 
25 #include "ED_anim_api.h"
26 #include "ED_keyframes_edit.h"
27 #include "ED_markers.h"
28 #include "ED_mask.h" /* own include */
29 
30 /* ***************************************** */
31 /* NOTE ABOUT THIS FILE:
32  * This file contains code for editing Mask data in the Action Editor
33  * as a 'keyframes', so that a user can adjust the timing of Mask shape-keys.
34  * Therefore, this file mostly contains functions for selecting Mask frames (shape-keys).
35  */
36 /* ***************************************** */
37 /* Generics - Loopers */
38 
40  Scene *scene,
41  bool (*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
42 {
43  MaskLayerShape *mask_layer_shape;
44 
45  /* error checker */
46  if (mask_layer == NULL) {
47  return false;
48  }
49 
50  /* do loop */
51  for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
52  mask_layer_shape = mask_layer_shape->next) {
53  /* execute callback */
54  if (mask_layer_shape_cb(mask_layer_shape, scene)) {
55  return true;
56  }
57  }
58 
59  /* nothing to return */
60  return false;
61 }
62 
63 /* ****************************************** */
64 /* Data Conversion Tools */
65 
66 void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool onlysel)
67 {
68  MaskLayerShape *mask_layer_shape;
69  CfraElem *ce;
70 
71  /* error checking */
72  if (ELEM(NULL, mask_layer, elems)) {
73  return;
74  }
75 
76  /* loop through mask-frames, adding */
77  for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
78  mask_layer_shape = mask_layer_shape->next) {
79  if ((onlysel == false) || (mask_layer_shape->flag & MASK_SHAPE_SELECT)) {
80  ce = MEM_callocN(sizeof(CfraElem), "CfraElem");
81 
82  ce->cfra = (float)mask_layer_shape->frame;
83  ce->sel = (mask_layer_shape->flag & MASK_SHAPE_SELECT) ? 1 : 0;
84 
85  BLI_addtail(elems, ce);
86  }
87  }
88 }
89 
90 /* ***************************************** */
91 /* Selection Tools */
92 
94 {
95  MaskLayerShape *mask_layer_shape;
96 
97  /* error checking */
98  if (mask_layer == NULL) {
99  return 0;
100  }
101 
102  /* stop at the first one found */
103  for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
104  mask_layer_shape = mask_layer_shape->next) {
105  if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
106  return true;
107  }
108  }
109 
110  /* not found */
111  return false;
112 }
113 
114 /* helper function - select mask-frame based on SELECT_* mode */
115 static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short select_mode)
116 {
117  if (mask_layer_shape == NULL) {
118  return;
119  }
120 
121  switch (select_mode) {
122  case SELECT_ADD:
123  mask_layer_shape->flag |= MASK_SHAPE_SELECT;
124  break;
125  case SELECT_SUBTRACT:
126  mask_layer_shape->flag &= ~MASK_SHAPE_SELECT;
127  break;
128  case SELECT_INVERT:
129  mask_layer_shape->flag ^= MASK_SHAPE_SELECT;
130  break;
131  }
132 }
133 
134 void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
135 {
136  MaskLayerShape *mask_layer_shape;
137 
138  /* error checking */
139  if (mask_layer == NULL) {
140  return;
141  }
142 
143  /* handle according to mode */
144  for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
145  mask_layer_shape = mask_layer_shape->next) {
146  mask_layer_shape_select(mask_layer_shape, select_mode);
147  }
148 }
149 
150 void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
151 {
152  /* error checking */
153  if (mask_layer == NULL) {
154  return;
155  }
156 
157  /* now call the standard function */
158  ED_mask_select_frames(mask_layer, mode);
159 }
160 
161 void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
162 {
163  MaskLayerShape *mask_layer_shape;
164 
165  if (mask_layer == NULL) {
166  return;
167  }
168 
169  mask_layer_shape = BKE_mask_layer_shape_find_frame(mask_layer, selx);
170 
171  if (mask_layer_shape) {
172  mask_layer_shape_select(mask_layer_shape, select_mode);
173  }
174 }
175 
176 void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
177 {
178  MaskLayerShape *mask_layer_shape;
179 
180  if (mask_layer == NULL) {
181  return;
182  }
183 
184  /* only select those frames which are in bounds */
185  for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
186  mask_layer_shape = mask_layer_shape->next) {
187  if (IN_RANGE(mask_layer_shape->frame, min, max)) {
188  mask_layer_shape_select(mask_layer_shape, select_mode);
189  }
190  }
191 }
192 
194  MaskLayer *mask_layer,
195  short tool,
196  short select_mode)
197 {
198  MaskLayerShape *mask_layer_shape;
199 
200  if (mask_layer == NULL) {
201  return;
202  }
203 
204  /* only select frames which are within the region */
205  for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
206  mask_layer_shape = mask_layer_shape->next) {
207  /* construct a dummy point coordinate to do this testing with */
208  float pt[2] = {0};
209 
210  pt[0] = mask_layer_shape->frame;
211  pt[1] = ked->channel_y;
212 
213  /* check the necessary regions */
214  if (tool == BEZT_OK_CHANNEL_LASSO) {
215  /* Lasso */
216  if (keyframe_region_lasso_test(ked->data, pt)) {
217  mask_layer_shape_select(mask_layer_shape, select_mode);
218  }
219  }
220  else if (tool == BEZT_OK_CHANNEL_CIRCLE) {
221  /* Circle */
222  if (keyframe_region_circle_test(ked->data, pt)) {
223  mask_layer_shape_select(mask_layer_shape, select_mode);
224  }
225  }
226  }
227 }
228 
229 /* ***************************************** */
230 /* Frame Editing Tools */
231 
233 {
234  MaskLayerShape *mask_layer_shape, *mask_layer_shape_next;
235  bool changed = false;
236 
237  /* error checking */
238  if (mask_layer == NULL) {
239  return false;
240  }
241 
242  /* check for frames to delete */
243  for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
244  mask_layer_shape = mask_layer_shape_next) {
245  mask_layer_shape_next = mask_layer_shape->next;
246 
247  if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
248  BKE_mask_layer_shape_unlink(mask_layer, mask_layer_shape);
249  changed = true;
250  }
251  }
252 
253  return changed;
254 }
255 
257 {
258  MaskLayerShape *mask_layer_shape, *gpfn;
259 
260  /* Error checking. */
261  if (mask_layer == NULL) {
262  return;
263  }
264 
265  /* Duplicate selected frames. */
266  for (mask_layer_shape = mask_layer->splines_shapes.first; mask_layer_shape;
267  mask_layer_shape = gpfn) {
268  gpfn = mask_layer_shape->next;
269 
270  /* Duplicate this frame. */
271  if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
272  MaskLayerShape *mask_shape_dupe;
273 
274  /* Duplicate frame, and deselect self. */
275  mask_shape_dupe = BKE_mask_layer_shape_duplicate(mask_layer_shape);
276  mask_layer_shape->flag &= ~MASK_SHAPE_SELECT;
277 
278  /* XXX: how to handle duplicate frames? */
279  BLI_insertlinkafter(&mask_layer->splines_shapes, mask_layer_shape, mask_shape_dupe);
280  }
281  }
282 }
283 
284 /* -------------------------------------- */
285 /* Snap Tools */
286 
287 static bool snap_mask_layer_nearest(MaskLayerShape *mask_layer_shape, Scene *UNUSED(scene))
288 {
289  if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
290  mask_layer_shape->frame = (int)(floor(mask_layer_shape->frame + 0.5));
291  }
292  return false;
293 }
294 
295 static bool snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *scene)
296 {
297  float secf = (float)FPS;
298  if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
299  mask_layer_shape->frame = (int)(floorf(mask_layer_shape->frame / secf + 0.5f) * secf);
300  }
301  return false;
302 }
303 
304 static bool snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
305 {
306  if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
307  mask_layer_shape->frame = (int)scene->r.cfra;
308  }
309  return false;
310 }
311 
312 static bool snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *scene)
313 {
314  if (mask_layer_shape->flag & MASK_SHAPE_SELECT) {
315  mask_layer_shape->frame = (int)ED_markers_find_nearest_marker_time(
316  &scene->markers, (float)mask_layer_shape->frame);
317  }
318  return false;
319 }
320 
321 void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
322 {
323  switch (mode) {
324  case SNAP_KEYS_NEARFRAME: /* snap to nearest frame */
326  break;
327  case SNAP_KEYS_CURFRAME: /* snap to current frame */
329  break;
330  case SNAP_KEYS_NEARMARKER: /* snap to nearest marker */
332  break;
333  case SNAP_KEYS_NEARSEC: /* snap to nearest second */
335  break;
336  default: /* just in case */
337  break;
338  }
339 }
typedef float(TangentPoint)[2]
void BKE_mask_layer_shape_unlink(struct MaskLayer *masklay, struct MaskLayerShape *masklay_shape)
Definition: mask.c:1799
struct MaskLayerShape * BKE_mask_layer_shape_duplicate(struct MaskLayerShape *masklay_shape)
Definition: mask.c:1786
struct MaskLayerShape * BKE_mask_layer_shape_find_frame(struct MaskLayer *masklay, int frame)
Definition: mask.c:1715
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink) ATTR_NONNULL(1)
Definition: listbase.c:301
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition: listbase.c:80
#define IN_RANGE(a, b, c)
#define UNUSED(x)
#define ELEM(...)
@ MASK_SHAPE_SELECT
#define FPS
@ BEZT_OK_CHANNEL_CIRCLE
@ BEZT_OK_CHANNEL_LASSO
@ SNAP_KEYS_CURFRAME
@ SNAP_KEYS_NEARFRAME
@ SNAP_KEYS_NEARMARKER
@ SNAP_KEYS_NEARSEC
@ SELECT_INVERT
@ SELECT_SUBTRACT
@ SELECT_ADD
Read Guarded memory(de)allocation.
int ED_markers_find_nearest_marker_time(ListBase *markers, float x)
Definition: anim_markers.c:163
Scene scene
bool keyframe_region_lasso_test(const KeyframeEdit_LassoData *data_lasso, const float xy[2])
bool keyframe_region_circle_test(const KeyframeEdit_CircleData *data_circle, const float xy[2])
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
static bool snap_mask_layer_nearest(MaskLayerShape *mask_layer_shape, Scene *UNUSED(scene))
bool ED_masklayer_frame_select_check(const MaskLayer *mask_layer)
static void mask_layer_shape_select(MaskLayerShape *mask_layer_shape, short select_mode)
void ED_mask_select_frame(MaskLayer *mask_layer, int selx, short select_mode)
void ED_mask_select_frames(MaskLayer *mask_layer, short select_mode)
void ED_masklayer_snap_frames(MaskLayer *mask_layer, Scene *scene, short mode)
void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *mask_layer, short tool, short select_mode)
bool ED_masklayer_frames_delete(MaskLayer *mask_layer)
void ED_masklayer_frames_select_box(MaskLayer *mask_layer, float min, float max, short select_mode)
bool ED_masklayer_frames_looper(MaskLayer *mask_layer, Scene *scene, bool(*mask_layer_shape_cb)(MaskLayerShape *, Scene *))
void ED_masklayer_frames_duplicate(MaskLayer *mask_layer)
void ED_masklayer_make_cfra_list(MaskLayer *mask_layer, ListBase *elems, bool onlysel)
static bool snap_mask_layer_nearmarker(MaskLayerShape *mask_layer_shape, Scene *scene)
static bool snap_mask_layer_nearestsec(MaskLayerShape *mask_layer_shape, Scene *scene)
void ED_masklayer_frame_select_set(MaskLayer *mask_layer, short mode)
static bool snap_mask_layer_cframe(MaskLayerShape *mask_layer_shape, Scene *scene)
#define floorf(x)
Definition: metal/compat.h:224
T floor(const T &a)
#define min(a, b)
Definition: sort.c:35
float cfra
Definition: BKE_fcurve.h:40
int sel
Definition: BKE_fcurve.h:41
void * first
Definition: DNA_listBase.h:31
struct MaskLayerShape * next
ListBase splines_shapes
struct RenderData r
ListBase markers
float max