Blender  V3.3
anim_deps.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2008 Blender Foundation. All rights reserved. */
3 
8 #include <string.h>
9 
10 #include "MEM_guardedalloc.h"
11 
12 #include "DNA_anim_types.h"
13 #include "DNA_armature_types.h"
14 #include "DNA_gpencil_types.h"
15 #include "DNA_mask_types.h"
16 #include "DNA_node_types.h"
17 #include "DNA_object_types.h"
18 #include "DNA_scene_types.h"
19 #include "DNA_sequence_types.h"
20 
21 #include "BLI_blenlib.h"
22 #include "BLI_utildefines.h"
23 
24 #include "BKE_action.h"
25 #include "BKE_anim_data.h"
26 #include "BKE_context.h"
27 #include "BKE_fcurve.h"
28 #include "BKE_gpencil.h"
29 #include "BKE_main.h"
30 #include "BKE_node.h"
31 
32 #include "DEG_depsgraph.h"
33 
34 #include "RNA_access.h"
35 #include "RNA_path.h"
36 
37 #include "SEQ_sequencer.h"
38 #include "SEQ_utils.h"
39 
40 #include "ED_anim_api.h"
41 
42 /* **************************** depsgraph tagging ******************************** */
43 
45 {
46  ID *id;
47  FCurve *fcu;
48  AnimData *adt;
49 
50  id = ale->id;
51  if (!id) {
52  return;
53  }
54 
55  /* tag AnimData for refresh so that other views will update in realtime with these changes */
56  adt = BKE_animdata_from_id(id);
57  if (adt) {
59  if (adt->action != NULL) {
61  }
62  }
63 
64  /* Tag copy on the main object if updating anything directly inside AnimData */
65  if (ELEM(ale->type,
71  return;
72  }
73 
74  /* update data */
75  fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL;
76 
77  if (fcu && fcu->rna_path) {
78  /* If we have an fcurve, call the update for the property we
79  * are editing, this is then expected to do the proper redraws
80  * and depsgraph updates. */
81  PointerRNA id_ptr, ptr;
82  PropertyRNA *prop;
83 
84  RNA_id_pointer_create(id, &id_ptr);
85 
86  if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop)) {
87  RNA_property_update_main(bmain, scene, &ptr, prop);
88  }
89  }
90  else {
91  /* in other case we do standard depsgraph update, ideally
92  * we'd be calling property update functions here too ... */
94  /* XXX: or do we want something more restrictive? */
96  }
97 }
98 
99 void ANIM_id_update(Main *bmain, ID *id)
100 {
101  if (id) {
102  DEG_id_tag_update_ex(bmain,
103  id,
104  /* XXX: or do we want something more restrictive? */
106  }
107 }
108 
109 /* **************************** animation data <-> data syncing ******************************** */
110 /* This code here is used to synchronize the
111  * - selection (to find selected data easier)
112  * - ... (insert other relevant items here later)
113  * status in relevant Blender data with the status stored in animation channels.
114  *
115  * This should be called in the refresh() callbacks for various editors in
116  * response to appropriate notifiers.
117  */
118 
119 /* perform syncing updates for Action Groups */
120 static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp)
121 {
122  bActionGroup *agrp = (bActionGroup *)ale->data;
123  ID *owner_id = ale->id;
124 
125  /* major priority is selection status
126  * so we need both a group and an owner
127  */
128  if (ELEM(NULL, agrp, owner_id)) {
129  return;
130  }
131 
132  /* for standard Objects, check if group is the name of some bone */
133  if (GS(owner_id->name) == ID_OB) {
134  Object *ob = (Object *)owner_id;
135 
136  /* check if there are bones, and whether the name matches any
137  * NOTE: this feature will only really work if groups by default contain the F-Curves
138  * for a single bone.
139  */
140  if (ob->pose) {
141  bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
142  bArmature *arm = ob->data;
143 
144  if (pchan) {
145  bActionGroup *bgrp;
146 
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 == NULL) {
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 group colors */
173  bgrp = (bActionGroup *)BLI_findlink(&ob->pose->agroups, (pchan->agrp_index - 1));
174  if (bgrp) {
175  agrp->customCol = bgrp->customCol;
176  action_group_colors_sync(agrp, bgrp);
177  }
178  }
179  }
180  }
181 }
182 
184 {
185  ID *owner_id = ale->id;
186  BLI_assert(GS(owner_id->name) == ID_SCE);
187  Scene *scene = (Scene *)owner_id;
188  FCurve *fcu = (FCurve *)ale->data;
189  Sequence *seq = NULL;
190 
191  /* Only affect if F-Curve involves sequence_editor.sequences. */
192  char seq_name[sizeof(seq->name)];
193  if (!BLI_str_quoted_substr(fcu->rna_path, "sequences_all[", seq_name, sizeof(seq_name))) {
194  return;
195  }
196 
197  /* Check if this strip is selected. */
199  seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
200  if (seq == NULL) {
201  return;
202  }
203 
204  /* update selection status */
205  if (seq->flag & SELECT) {
206  fcu->flag |= FCURVE_SELECTED;
207  }
208  else {
209  fcu->flag &= ~FCURVE_SELECTED;
210  }
211 }
212 
213 /* perform syncing updates for F-Curves */
215 {
216  FCurve *fcu = (FCurve *)ale->data;
217  ID *owner_id = ale->id;
218 
219  /* major priority is selection status, so refer to the checks done in anim_filter.c
220  * skip_fcurve_selected_data() for reference about what's going on here...
221  */
222  if (ELEM(NULL, fcu, fcu->rna_path, owner_id)) {
223  return;
224  }
225 
226  switch (GS(owner_id->name)) {
227  case ID_SCE:
229  break;
230  default:
231  break;
232  }
233 }
234 
235 /* perform syncing updates for GPencil Layers */
237 {
238  bGPDlayer *gpl = (bGPDlayer *)ale->data;
239 
240  /* Make sure the selection flags agree with the "active" flag.
241  * The selection flags are used in the Dopesheet only, whereas
242  * the active flag is used everywhere else. Hence, we try to
243  * sync these here so that it all seems to be have as the user
244  * expects - T50184
245  *
246  * Assume that we only really do this when the active status changes.
247  * (NOTE: This may prove annoying if it means selection is always lost)
248  */
249  if (gpl->flag & GP_LAYER_ACTIVE) {
250  gpl->flag |= GP_LAYER_SELECT;
251  }
252  else {
253  gpl->flag &= ~GP_LAYER_SELECT;
254  }
255 }
256 
257 /* ---------------- */
258 
260 {
261  bAnimContext ac;
262  ListBase anim_data = {NULL, NULL};
263  bAnimListElem *ale;
264  int filter;
265 
266  bActionGroup *active_agrp = NULL;
267 
268  /* get animation context info for filtering the channels */
269  if (ANIM_animdata_get_context(C, &ac) == 0) {
270  return;
271  }
272 
273  /* filter data */
274 
275  /* NOTE: we want all channels, since we want to be able to set selection status on some of them
276  * even when collapsed... however,
277  * don't include duplicates so that selection statuses don't override each other.
278  */
280  ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
281 
282  /* flush settings as appropriate depending on the types of the channels */
283  for (ale = anim_data.first; ale; ale = ale->next) {
284  switch (ale->type) {
285  case ANIMTYPE_GROUP:
286  animchan_sync_group(&ac, ale, &active_agrp);
287  break;
288 
289  case ANIMTYPE_FCURVE:
291  break;
292 
293  case ANIMTYPE_GPLAYER:
295  break;
296  }
297  }
298 
299  ANIM_animdata_freelist(&anim_data);
300 }
301 
303 {
304  bAnimListElem *ale;
305 
306  for (ale = anim_data->first; ale; ale = ale->next) {
307  if (ale->type == ANIMTYPE_GPLAYER) {
308  bGPDlayer *gpl = ale->data;
309 
310  if (ale->update & ANIM_UPDATE_ORDER) {
311  ale->update &= ~ANIM_UPDATE_ORDER;
312  if (gpl) {
314  }
315  }
316 
317  if (ale->update & ANIM_UPDATE_DEPS) {
318  ale->update &= ~ANIM_UPDATE_DEPS;
319  ANIM_list_elem_update(ac->bmain, ac->scene, ale);
320  }
321  /* disable handles to avoid crash */
322  if (ale->update & ANIM_UPDATE_HANDLES) {
323  ale->update &= ~ANIM_UPDATE_HANDLES;
324  }
325  }
326  else if (ale->datatype == ALE_MASKLAY) {
327  MaskLayer *masklay = ale->data;
328 
329  if (ale->update & ANIM_UPDATE_ORDER) {
330  ale->update &= ~ANIM_UPDATE_ORDER;
331  if (masklay) {
332  /* While correct & we could enable it: 'posttrans_mask_clean' currently
333  * both sorts and removes doubles, so this is not necessary here. */
334  // BKE_mask_layer_shape_sort(masklay);
335  }
336  }
337 
338  if (ale->update & ANIM_UPDATE_DEPS) {
339  ale->update &= ~ANIM_UPDATE_DEPS;
340  ANIM_list_elem_update(ac->bmain, ac->scene, ale);
341  }
342  /* Disable handles to avoid assert. */
343  if (ale->update & ANIM_UPDATE_HANDLES) {
344  ale->update &= ~ANIM_UPDATE_HANDLES;
345  }
346  }
347  else if (ale->datatype == ALE_FCURVE) {
348  FCurve *fcu = ale->key_data;
349 
350  if (ale->update & ANIM_UPDATE_ORDER) {
351  ale->update &= ~ANIM_UPDATE_ORDER;
352  if (fcu) {
353  sort_time_fcurve(fcu);
354  }
355  }
356 
357  if (ale->update & ANIM_UPDATE_HANDLES) {
358  ale->update &= ~ANIM_UPDATE_HANDLES;
359  if (fcu) {
361  }
362  }
363 
364  if (ale->update & ANIM_UPDATE_DEPS) {
365  ale->update &= ~ANIM_UPDATE_DEPS;
366  ANIM_list_elem_update(ac->bmain, ac->scene, ale);
367  }
368  }
369  else if (ELEM(ale->type,
374  if (ale->update & ANIM_UPDATE_DEPS) {
375  ale->update &= ~ANIM_UPDATE_DEPS;
376  ANIM_list_elem_update(ac->bmain, ac->scene, ale);
377  }
378  }
379  else if (ale->update) {
380 #if 0
381  if (G.debug & G_DEBUG) {
382  printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n",
383  __func__,
384  ale->update,
385  ale->type,
386  ale->data);
387  }
388 #endif
389  /* Prevent crashes in cases where it can't be handled */
390  ale->update = 0;
391  }
392 
393  BLI_assert(ale->update == 0);
394  }
395 }
396 
398 {
399 #ifndef NDEBUG
400  bAnimListElem *ale, *ale_next;
401  for (ale = anim_data->first; ale; ale = ale_next) {
402  ale_next = ale->next;
403  BLI_assert(ale->update == 0);
404  MEM_freeN(ale);
405  }
406  BLI_listbase_clear(anim_data);
407 #else
408  BLI_freelistN(anim_data);
409 #endif
410 }
Blender kernel action and pose functionality.
struct bPoseChannel * BKE_pose_channel_find_name(const struct bPose *pose, const char *name)
void action_group_colors_sync(struct bActionGroup *grp, const struct bActionGroup *ref_grp)
struct AnimData * BKE_animdata_from_id(const struct ID *id)
void sort_time_fcurve(struct FCurve *fcu)
Definition: fcurve.c:1327
void BKE_fcurve_handles_recalc(struct FCurve *fcu)
Definition: fcurve.c:1303
@ G_DEBUG
Definition: BKE_global.h:174
void BKE_gpencil_layer_frames_sort(struct bGPDlayer *gpl, bool *r_has_duplicate_frames)
Definition: gpencil.c:1553
#define BLI_assert(a)
Definition: BLI_assert.h:46
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
Definition: BLI_listbase.h:273
void void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1)
Definition: listbase.c:466
void * BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxlen)
Definition: string.c:424
#define ELEM(...)
void DEG_id_tag_update_ex(struct Main *bmain, struct ID *id, int flag)
void DEG_id_tag_update(struct ID *id, int flag)
@ ID_RECALC_TRANSFORM
Definition: DNA_ID.h:771
@ ID_RECALC_ANIMATION
Definition: DNA_ID.h:794
@ ID_RECALC_GEOMETRY
Definition: DNA_ID.h:791
@ ID_SCE
Definition: DNA_ID_enums.h:45
@ ID_OB
Definition: DNA_ID_enums.h:47
@ AGRP_ACTIVE
@ AGRP_SELECTED
@ FCURVE_SELECTED
@ BONE_SELECTED
@ GP_LAYER_ACTIVE
@ GP_LAYER_SELECT
Object is a sort of wrapper for general info.
@ ANIMTYPE_NLACURVE
Definition: ED_anim_api.h:202
@ ANIMTYPE_GROUP
Definition: ED_anim_api.h:198
@ ANIMTYPE_GPLAYER
Definition: ED_anim_api.h:233
@ ANIMTYPE_ANIMDATA
Definition: ED_anim_api.h:191
@ ANIMTYPE_NLAACTION
Definition: ED_anim_api.h:239
@ ANIMTYPE_FCURVE
Definition: ED_anim_api.h:199
@ ANIMTYPE_NLATRACK
Definition: ED_anim_api.h:238
@ ALE_FCURVE
Definition: ED_anim_api.h:250
@ ALE_MASKLAY
Definition: ED_anim_api.h:252
@ ANIM_UPDATE_DEPS
Definition: ED_anim_api.h:268
@ ANIM_UPDATE_HANDLES
Definition: ED_anim_api.h:270
@ ANIM_UPDATE_ORDER
Definition: ED_anim_api.h:269
@ ANIMFILTER_DATA_VISIBLE
Definition: ED_anim_api.h:292
@ ANIMFILTER_LIST_CHANNELS
Definition: ED_anim_api.h:300
@ ANIMFILTER_NODUPLIS
Definition: ED_anim_api.h:325
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:25
static void animchan_sync_fcurve_scene(bAnimListElem *ale)
Definition: anim_deps.c:183
static void animchan_sync_fcurve(bAnimListElem *ale)
Definition: anim_deps.c:214
void ANIM_animdata_freelist(ListBase *anim_data)
Definition: anim_deps.c:397
static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp)
Definition: anim_deps.c:120
void ANIM_sync_animchannels_to_data(const bContext *C)
Definition: anim_deps.c:259
void ANIM_id_update(Main *bmain, ID *id)
Definition: anim_deps.c:99
void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
Definition: anim_deps.c:44
static void animchan_sync_gplayer(bAnimListElem *ale)
Definition: anim_deps.c:236
void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
Definition: anim_deps.c:302
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
Definition: anim_filter.c:379
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode, void *data, eAnimCont_Types datatype)
Definition: anim_filter.c:3447
#define SELECT
Scene scene
DO_INLINE void filter(lfVector *V, fmatrix3x3 *S)
#define GS(x)
Definition: iris.c:225
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
#define G(x, y, z)
void RNA_id_pointer_create(ID *id, PointerRNA *r_ptr)
Definition: rna_access.c:112
void RNA_property_update_main(Main *bmain, Scene *scene, PointerRNA *ptr, PropertyRNA *prop)
Definition: rna_access.c:2143
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
Definition: rna_path.cc:531
Editing * SEQ_editing_get(const Scene *scene)
Definition: sequencer.c:241
bAction * action
ListBase * seqbasep
char * rna_path
short flag
Definition: DNA_ID.h:368
char name[66]
Definition: DNA_ID.h:378
void * first
Definition: DNA_listBase.h:31
Definition: BKE_main.h:121
struct bPose * pose
void * data
struct Scene * scene
Definition: ED_anim_api.h:84
short datatype
Definition: ED_anim_api.h:62
void * data
Definition: ED_anim_api.h:60
struct Object * obact
Definition: ED_anim_api.h:90
struct Main * bmain
Definition: ED_anim_api.h:82
struct bAnimListElem * next
Definition: ED_anim_api.h:127
void * key_data
Definition: ED_anim_api.h:146
struct ID * id
Definition: ED_anim_api.h:160
struct Bone * bone
ListBase agroups
Sequence * SEQ_get_sequence_by_name(ListBase *seqbase, const char *name, bool recursive)
Definition: utils.c:422
PointerRNA * ptr
Definition: wm_files.c:3480