Blender V4.3
anim_deps.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 <cstring>
10
11#include "MEM_guardedalloc.h"
12
13#include "DNA_anim_types.h"
14#include "DNA_armature_types.h"
17#include "DNA_mask_types.h"
18#include "DNA_object_types.h"
19#include "DNA_scene_types.h"
20#include "DNA_sequence_types.h"
21#include "DNA_space_types.h"
23
24#include "BLI_blenlib.h"
25#include "BLI_set.hh"
26#include "BLI_utildefines.h"
27
28#include "BKE_action.hh"
29#include "BKE_anim_data.hh"
30#include "BKE_context.hh"
31#include "BKE_fcurve.hh"
32#include "BKE_gpencil_legacy.h"
33#include "BKE_grease_pencil.hh"
34#include "BKE_screen.hh"
35#include "BKE_workspace.hh"
36
37#include "DEG_depsgraph.hh"
38
39#include "RNA_access.hh"
40#include "RNA_path.hh"
41
42#include "SEQ_sequencer.hh"
43#include "SEQ_utils.hh"
44
45#include "ED_anim_api.hh"
46
47#include "ANIM_action.hh"
48
49/* **************************** depsgraph tagging ******************************** */
50
52{
53 ID *id;
54 FCurve *fcu;
55 AnimData *adt;
56
57 id = ale->id;
58 if (!id) {
59 return;
60 }
61
62 /* tag AnimData for refresh so that other views will update in realtime with these changes */
63 adt = BKE_animdata_from_id(id);
64 if (adt) {
66 if (adt->action != nullptr) {
68 }
69 }
70
71 /* Tag copy on the main object if updating anything directly inside AnimData */
73 {
75 return;
76 }
77
78 /* update data */
79 fcu = static_cast<FCurve *>((ale->datatype == ALE_FCURVE) ? ale->key_data : nullptr);
80
81 if (fcu && fcu->rna_path) {
82 /* If we have an fcurve, call the update for the property we
83 * are editing, this is then expected to do the proper redraws
84 * and depsgraph updates. */
86 PropertyRNA *prop;
87
89
90 if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
91 RNA_property_update_main(bmain, scene, &ptr, prop);
92 }
93 }
94 else {
95 /* in other case we do standard depsgraph update, ideally
96 * we'd be calling property update functions here too ... */
97 DEG_id_tag_update(id, /* XXX: or do we want something more restrictive? */
99 }
100}
101
102void ANIM_id_update(Main *bmain, ID *id)
103{
104 if (id) {
106 id, /* XXX: or do we want something more restrictive? */
108 }
109}
110
111/* **************************** animation data <-> data syncing ******************************** */
112/* This code here is used to synchronize the
113 * - selection (to find selected data easier)
114 * - ... (insert other relevant items here later)
115 * status in relevant Blender data with the status stored in animation channels.
116 *
117 * This should be called in the refresh() callbacks for various editors in
118 * response to appropriate notifiers.
119 */
120
121/* perform syncing updates for Action Groups */
122static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp)
123{
124 bActionGroup *agrp = (bActionGroup *)ale->data;
125 ID *owner_id = ale->id;
126
127 /* major priority is selection status
128 * so we need both a group and an owner
129 */
130 if (ELEM(nullptr, agrp, owner_id)) {
131 return;
132 }
133
134 /* for standard Objects, check if group is the name of some bone */
135 if (GS(owner_id->name) == ID_OB) {
136 Object *ob = (Object *)owner_id;
137
138 /* check if there are bones, and whether the name matches any
139 * NOTE: this feature will only really work if groups by default contain the F-Curves
140 * for a single bone.
141 */
142 if (ob->pose) {
144 bArmature *arm = static_cast<bArmature *>(ob->data);
145
146 if (pchan) {
147 /* if one matches, sync the selection status */
148 if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED)) {
149 agrp->flag |= AGRP_SELECTED;
150 }
151 else {
152 agrp->flag &= ~AGRP_SELECTED;
153 }
154
155 /* also sync active group status */
156 if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) {
157 /* if no previous F-Curve has active flag, then we're the first and only one to get it */
158 if (*active_agrp == nullptr) {
159 agrp->flag |= AGRP_ACTIVE;
160 *active_agrp = agrp;
161 }
162 else {
163 /* someone else has already taken it - set as not active */
164 agrp->flag &= ~AGRP_ACTIVE;
165 }
166 }
167 else {
168 /* this can't possibly be active now */
169 agrp->flag &= ~AGRP_ACTIVE;
170 }
171
172 /* sync bone color */
174 }
175 }
176 }
177}
178
180{
181 ID *owner_id = ale->id;
182 BLI_assert(GS(owner_id->name) == ID_SCE);
183 Scene *scene = (Scene *)owner_id;
184 FCurve *fcu = (FCurve *)ale->data;
185 Sequence *seq = nullptr;
186
187 /* Only affect if F-Curve involves sequence_editor.sequences. */
188 char seq_name[sizeof(seq->name)];
189 if (!BLI_str_quoted_substr(fcu->rna_path, "sequences_all[", seq_name, sizeof(seq_name))) {
190 return;
191 }
192
193 /* Check if this strip is selected. */
194 Editing *ed = SEQ_editing_get(scene);
195 seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
196 if (seq == nullptr) {
197 return;
198 }
199
200 /* update selection status */
201 if (seq->flag & SELECT) {
202 fcu->flag |= FCURVE_SELECTED;
203 }
204 else {
205 fcu->flag &= ~FCURVE_SELECTED;
206 }
207}
208
209/* perform syncing updates for F-Curves */
211{
212 FCurve *fcu = (FCurve *)ale->data;
213 ID *owner_id = ale->id;
214
215 /* major priority is selection status, so refer to the checks done in `anim_filter.cc`
216 * #skip_fcurve_selected_data() for reference about what's going on here.
217 */
218 if (ELEM(nullptr, fcu, fcu->rna_path, owner_id)) {
219 return;
220 }
221
222 switch (GS(owner_id->name)) {
223 case ID_SCE:
225 break;
226 default:
227 break;
228 }
229}
230
231/* perform syncing updates for GPencil Layers */
233{
234 bGPDlayer *gpl = (bGPDlayer *)ale->data;
235
236 /* Make sure the selection flags agree with the "active" flag.
237 * The selection flags are used in the Dopesheet only, whereas
238 * the active flag is used everywhere else. Hence, we try to
239 * sync these here so that it all seems to be have as the user
240 * expects - #50184
241 *
242 * Assume that we only really do this when the active status changes.
243 * (NOTE: This may prove annoying if it means selection is always lost)
244 */
245 if (gpl->flag & GP_LAYER_ACTIVE) {
246 gpl->flag |= GP_LAYER_SELECT;
247 }
248 else {
249 gpl->flag &= ~GP_LAYER_SELECT;
250 }
251}
252
253/* ---------------- */
254
256{
257 bAnimContext ac;
258 ListBase anim_data = {nullptr, nullptr};
259 int filter;
260
261 bActionGroup *active_agrp = nullptr;
262
263 /* get animation context info for filtering the channels */
264 if (ANIM_animdata_get_context(C, &ac) == 0) {
265 return;
266 }
267
268 /* filter data */
269
270 /* NOTE: we want all channels, since we want to be able to set selection status on some of them
271 * even when collapsed... however,
272 * don't include duplicates so that selection statuses don't override each other.
273 */
276 &ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));
277
278 /* flush settings as appropriate depending on the types of the channels */
279 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
280 switch (ale->type) {
281 case ANIMTYPE_GROUP:
282 animchan_sync_group(&ac, ale, &active_agrp);
283 break;
284
285 case ANIMTYPE_FCURVE:
287 break;
288
289 case ANIMTYPE_GPLAYER:
291 break;
293 using namespace blender::bke::greasepencil;
294 GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(ale->id);
295 Layer *layer = static_cast<Layer *>(ale->data);
296 layer->set_selected(grease_pencil->is_layer_active(layer));
297 break;
298 }
299
300 case ANIMTYPE_NONE:
303 case ANIMTYPE_SUMMARY:
304 case ANIMTYPE_SCENE:
305 case ANIMTYPE_OBJECT:
312 case ANIMTYPE_DSMAT:
313 case ANIMTYPE_DSLAM:
314 case ANIMTYPE_DSCAM:
316 case ANIMTYPE_DSCUR:
317 case ANIMTYPE_DSSKEY:
318 case ANIMTYPE_DSWOR:
319 case ANIMTYPE_DSNTREE:
320 case ANIMTYPE_DSPART:
321 case ANIMTYPE_DSMBALL:
322 case ANIMTYPE_DSARM:
323 case ANIMTYPE_DSMESH:
324 case ANIMTYPE_DSTEX:
325 case ANIMTYPE_DSLAT:
327 case ANIMTYPE_DSSPK:
329 case ANIMTYPE_DSMCLIP:
330 case ANIMTYPE_DSHAIR:
341 case ANIMTYPE_PALETTE:
343 break;
344 }
345 }
346
347 ANIM_animdata_freelist(&anim_data);
348}
349
351{
352 LISTBASE_FOREACH (bAnimListElem *, ale, anim_data) {
353 if (ale->type == ANIMTYPE_GPLAYER) {
354 bGPDlayer *gpl = static_cast<bGPDlayer *>(ale->data);
355
356 if (ale->update & ANIM_UPDATE_ORDER) {
357 ale->update &= ~ANIM_UPDATE_ORDER;
358 if (gpl) {
359 BKE_gpencil_layer_frames_sort(gpl, nullptr);
360 }
361 }
362
363 if (ale->update & ANIM_UPDATE_DEPS) {
364 ale->update &= ~ANIM_UPDATE_DEPS;
365 ANIM_list_elem_update(ac->bmain, ac->scene, ale);
366 }
367 /* disable handles to avoid crash */
368 if (ale->update & ANIM_UPDATE_HANDLES) {
369 ale->update &= ~ANIM_UPDATE_HANDLES;
370 }
371 }
372 else if (ale->datatype == ALE_MASKLAY) {
373 MaskLayer *masklay = static_cast<MaskLayer *>(ale->data);
374
375 if (ale->update & ANIM_UPDATE_ORDER) {
376 ale->update &= ~ANIM_UPDATE_ORDER;
377 if (masklay) {
378 /* While correct & we could enable it: 'posttrans_mask_clean' currently
379 * both sorts and removes doubles, so this is not necessary here. */
380 // BKE_mask_layer_shape_sort(masklay);
381 }
382 }
383
384 if (ale->update & ANIM_UPDATE_DEPS) {
385 ale->update &= ~ANIM_UPDATE_DEPS;
386 ANIM_list_elem_update(ac->bmain, ac->scene, ale);
387 }
388 /* Disable handles to avoid assert. */
389 if (ale->update & ANIM_UPDATE_HANDLES) {
390 ale->update &= ~ANIM_UPDATE_HANDLES;
391 }
392 }
393 else if (ale->datatype == ALE_FCURVE) {
394 FCurve *fcu = static_cast<FCurve *>(ale->key_data);
395
396 if (ale->update & ANIM_UPDATE_ORDER) {
397 ale->update &= ~ANIM_UPDATE_ORDER;
398 if (fcu) {
399 sort_time_fcurve(fcu);
400 }
401 }
402
403 if (ale->update & ANIM_UPDATE_HANDLES) {
404 ale->update &= ~ANIM_UPDATE_HANDLES;
405 if (fcu) {
407 }
408 }
409
410 if (ale->update & ANIM_UPDATE_DEPS) {
411 ale->update &= ~ANIM_UPDATE_DEPS;
412 ANIM_list_elem_update(ac->bmain, ac->scene, ale);
413 }
414 }
415 else if (ELEM(ale->type,
420 {
421 if (ale->update & ANIM_UPDATE_DEPS) {
422 ale->update &= ~ANIM_UPDATE_DEPS;
423 ANIM_list_elem_update(ac->bmain, ac->scene, ale);
424 }
425 }
426 else if (ELEM(ale->type,
430 {
431 if (ale->update & ANIM_UPDATE_DEPS) {
432 ale->update &= ~ANIM_UPDATE_DEPS;
433 ANIM_list_elem_update(ac->bmain, ac->scene, ale);
434 }
435 /* Order appears to be already handled in `grease_pencil_layer_apply_trans_data` when
436 * translating. */
437 ale->update &= ~(ANIM_UPDATE_HANDLES | ANIM_UPDATE_ORDER);
438 }
439 else if (ale->update) {
440#if 0
441 if (G.debug & G_DEBUG) {
442 printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n",
443 __func__,
444 ale->update,
445 ale->type,
446 ale->data);
447 }
448#endif
449 /* Prevent crashes in cases where it can't be handled */
450 ale->update = eAnim_Update_Flags(0);
451 }
452
453 BLI_assert(ale->update == 0);
454 }
455}
456
458{
459#ifndef NDEBUG
460 bAnimListElem *ale, *ale_next;
461 for (ale = static_cast<bAnimListElem *>(anim_data->first); ale; ale = ale_next) {
462 ale_next = ale->next;
463 BLI_assert(ale->update == 0);
464 MEM_freeN(ale);
465 }
466 BLI_listbase_clear(anim_data);
467#else
468 BLI_freelistN(anim_data);
469#endif
470}
471
473{
474 using namespace blender;
475
476 wmWindow *ctx_window = CTX_wm_window(C);
477 ScrArea *ctx_area = CTX_wm_area(C);
478 ARegion *ctx_region = CTX_wm_region(C);
479
480 Set<bAction *> dna_actions;
481 LISTBASE_FOREACH (wmWindow *, win, &CTX_wm_manager(C)->windows) {
482 bScreen *screen = BKE_workspace_active_screen_get(win->workspace_hook);
483
484 LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) {
485 if (!ELEM(area->spacetype, SPACE_GRAPH, SPACE_ACTION)) {
486 continue;
487 }
488 ARegion *window_region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW);
489
490 if (!window_region) {
491 continue;
492 }
493
494 CTX_wm_window_set(C, win);
495 CTX_wm_area_set(C, area);
496 CTX_wm_region_set(C, window_region);
497 bAnimContext ac;
498 if (!ANIM_animdata_get_context(C, &ac)) {
499 continue;
500 }
501 ListBase anim_data = {nullptr, nullptr};
503 ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
504 LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
505 if (!ale->adt || !ale->adt->action) {
506 continue;
507 }
508 dna_actions.add(ale->adt->action);
509 }
510 ANIM_animdata_freelist(&anim_data);
511 }
512 }
513
514 CTX_wm_window_set(C, ctx_window);
515 CTX_wm_area_set(C, ctx_area);
516 CTX_wm_region_set(C, ctx_region);
517
518 for (bAction *dna_action : dna_actions) {
519 animrig::action_deselect_keys(dna_action->wrap());
520 }
521}
Functions and classes to work with Actions.
Blender kernel action and pose functionality.
void action_group_colors_set_from_posebone(bActionGroup *grp, const bPoseChannel *pchan)
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
ScrArea * CTX_wm_area(const bContext *C)
wmWindow * CTX_wm_window(const bContext *C)
void CTX_wm_window_set(bContext *C, wmWindow *win)
void CTX_wm_area_set(bContext *C, ScrArea *area)
void CTX_wm_region_set(bContext *C, ARegion *region)
ARegion * CTX_wm_region(const bContext *C)
wmWindowManager * CTX_wm_manager(const bContext *C)
void BKE_fcurve_handles_recalc(FCurve *fcu)
void sort_time_fcurve(FCurve *fcu)
@ G_DEBUG
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames)
Low-level operations for grease pencil.
ARegion * BKE_area_find_region_type(const ScrArea *area, int region_type)
Definition screen.cc:815
bScreen * BKE_workspace_active_screen_get(const WorkSpaceInstanceHook *hook) GETTER_ATTRS
Definition workspace.cc:613
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition listbase.cc:496
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.c:517
#define ELEM(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_id_tag_update_ex(Main *bmain, ID *id, unsigned int flags)
@ ID_RECALC_TRANSFORM
Definition DNA_ID.h:1021
@ ID_RECALC_ANIMATION
Definition DNA_ID.h:1044
@ ID_RECALC_GEOMETRY
Definition DNA_ID.h:1041
@ ID_SCE
@ ID_OB
@ AGRP_ACTIVE
@ AGRP_SELECTED
@ FCURVE_SELECTED
@ BONE_SELECTED
Object is a sort of wrapper for general info.
@ RGN_TYPE_WINDOW
@ SPACE_ACTION
@ SPACE_GRAPH
@ ANIMTYPE_DSSPK
@ ANIMTYPE_DSTEX
@ ANIMTYPE_SUMMARY
@ ANIMTYPE_DSNTREE
@ ANIMTYPE_NLACURVE
@ ANIMTYPE_SHAPEKEY
@ ANIMTYPE_DSMBALL
@ ANIMTYPE_DSCAM
@ ANIMTYPE_DSPOINTCLOUD
@ ANIMTYPE_FILLDRIVERS
@ ANIMTYPE_NONE
@ ANIMTYPE_DSPART
@ ANIMTYPE_DSLINESTYLE
@ ANIMTYPE_GROUP
@ ANIMTYPE_ACTION_SLOT
@ ANIMTYPE_SPECIALDATA__UNUSED
@ ANIMTYPE_GREASE_PENCIL_DATABLOCK
@ ANIMTYPE_DSCUR
@ ANIMTYPE_SCENE
@ ANIMTYPE_DSARM
@ ANIMTYPE_NLACONTROLS
@ ANIMTYPE_GPLAYER
@ ANIMTYPE_MASKDATABLOCK
@ ANIMTYPE_ANIMDATA
@ ANIMTYPE_MASKLAYER
@ ANIMTYPE_DSGPENCIL
@ ANIMTYPE_DSLAT
@ ANIMTYPE_NLAACTION
@ ANIMTYPE_DSMCLIP
@ ANIMTYPE_DSMAT
@ ANIMTYPE_NUM_TYPES
@ ANIMTYPE_DSCACHEFILE
@ ANIMTYPE_DSVOLUME
@ ANIMTYPE_FCURVE
@ ANIMTYPE_DSLAM
@ ANIMTYPE_PALETTE
@ ANIMTYPE_GPDATABLOCK
@ ANIMTYPE_GREASE_PENCIL_LAYER
@ ANIMTYPE_FILLACT_LAYERED
@ ANIMTYPE_FILLACTD
@ ANIMTYPE_OBJECT
@ ANIMTYPE_DSMESH
@ ANIMTYPE_GREASE_PENCIL_LAYER_GROUP
@ ANIMTYPE_NLATRACK
@ ANIMTYPE_DSWOR
@ ANIMTYPE_DSSKEY
@ ANIMTYPE_DSHAIR
@ ALE_FCURVE
@ ALE_MASKLAY
eAnim_Update_Flags
@ ANIM_UPDATE_DEPS
@ ANIM_UPDATE_HANDLES
@ ANIM_UPDATE_ORDER
eAnimCont_Types
eAnimFilter_Flags
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_LIST_CHANNELS
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_FCURVESONLY
Read Guarded memory(de)allocation.
static void animchan_sync_fcurve_scene(bAnimListElem *ale)
Definition anim_deps.cc:179
static void animchan_sync_fcurve(bAnimListElem *ale)
Definition anim_deps.cc:210
void ANIM_animdata_freelist(ListBase *anim_data)
Definition anim_deps.cc:457
static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp)
Definition anim_deps.cc:122
void ANIM_deselect_keys_in_animation_editors(bContext *C)
Definition anim_deps.cc:472
void ANIM_sync_animchannels_to_data(const bContext *C)
Definition anim_deps.cc:255
void ANIM_id_update(Main *bmain, ID *id)
Definition anim_deps.cc:102
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
Definition anim_deps.cc:51
static void animchan_sync_gplayer(bAnimListElem *ale)
Definition anim_deps.cc:232
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition anim_deps.cc:350
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
#define printf
#define SELECT
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
#define GS(x)
Definition iris.cc:202
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define G(x, y, z)
void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition rna_path.cc:553
Sequence * SEQ_get_sequence_by_name(ListBase *seqbase, const char *name, bool recursive)
Editing * SEQ_editing_get(const Scene *scene)
Definition sequencer.cc:262
bAction * action
ListBase * seqbasep
char * rna_path
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
void * first
struct bPose * pose
eAnimCont_Types datatype
Object * obact
bAnimListElem * next
eAnim_ChannelType type
eAnim_Update_Flags update
eAnim_KeyType datatype
struct Bone * bone
PointerRNA * ptr
Definition wm_files.cc:4126