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