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