5d25d732fe8f408fae0b4c6de286d213ecad7542
[blender.git] / source / blender / editors / animation / anim_deps.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2008 Blender Foundation.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edanimation
22  */
23
24 #include <string.h>
25
26 #include "MEM_guardedalloc.h"
27
28 #include "DNA_anim_types.h"
29 #include "DNA_armature_types.h"
30 #include "DNA_gpencil_types.h"
31 #include "DNA_object_types.h"
32 #include "DNA_node_types.h"
33 #include "DNA_scene_types.h"
34 #include "DNA_sequence_types.h"
35
36 #include "BLI_blenlib.h"
37 #include "BLI_utildefines.h"
38
39 #include "BKE_animsys.h"
40 #include "BKE_action.h"
41 #include "BKE_context.h"
42 #include "BKE_fcurve.h"
43 #include "BKE_gpencil.h"
44 #include "BKE_main.h"
45 #include "BKE_node.h"
46 #include "BKE_sequencer.h"
47
48 #include "DEG_depsgraph.h"
49
50 #include "RNA_access.h"
51
52 #include "ED_anim_api.h"
53
54 /* **************************** depsgraph tagging ******************************** */
55
56 /* tags the given anim list element for refreshes (if applicable)
57  * due to Animation Editor editing
58  */
59 void ANIM_list_elem_update(Main *bmain, Scene *scene, bAnimListElem *ale)
60 {
61   ID *id;
62   FCurve *fcu;
63   AnimData *adt;
64
65   id = ale->id;
66   if (!id)
67     return;
68
69   /* tag AnimData for refresh so that other views will update in realtime with these changes */
70   adt = BKE_animdata_from_id(id);
71   if (adt) {
72     DEG_id_tag_update(id, ID_RECALC_ANIMATION);
73     if (adt->action != NULL) {
74       DEG_id_tag_update(&adt->action->id, ID_RECALC_ANIMATION);
75     }
76   }
77
78   /* Tag copy on the main object if updating anything directly inside AnimData */
79   if (ELEM(ale->type,
80            ANIMTYPE_ANIMDATA,
81            ANIMTYPE_NLAACTION,
82            ANIMTYPE_NLATRACK,
83            ANIMTYPE_NLACURVE)) {
84     DEG_id_tag_update(id, ID_RECALC_ANIMATION);
85     return;
86   }
87
88   /* update data */
89   fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL;
90
91   if (fcu && fcu->rna_path) {
92     /* if we have an fcurve, call the update for the property we
93      * are editing, this is then expected to do the proper redraws
94      * and depsgraph updates  */
95     PointerRNA id_ptr, ptr;
96     PropertyRNA *prop;
97
98     RNA_id_pointer_create(id, &id_ptr);
99
100     if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop))
101       RNA_property_update_main(bmain, scene, &ptr, prop);
102   }
103   else {
104     /* in other case we do standard depsgraph update, ideally
105      * we'd be calling property update functions here too ... */
106     DEG_id_tag_update(id,
107                       ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY |
108                           ID_RECALC_ANIMATION);  // XXX or do we want something more restrictive?
109   }
110 }
111
112 /* tags the given ID block for refreshes (if applicable) due to
113  * Animation Editor editing */
114 void ANIM_id_update(Main *bmain, ID *id)
115 {
116   if (id) {
117     DEG_id_tag_update_ex(
118         bmain,
119         id,
120         ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY |
121             ID_RECALC_ANIMATION);  // XXX or do we want something more restrictive?
122   }
123 }
124
125 /* **************************** animation data <-> data syncing ******************************** */
126 /* This code here is used to synchronize the
127  * - selection (to find selected data easier)
128  * - ... (insert other relevant items here later)
129  * status in relevant Blender data with the status stored in animation channels.
130  *
131  * This should be called in the refresh() callbacks for various editors in
132  * response to appropriate notifiers.
133  */
134
135 /* perform syncing updates for Action Groups */
136 static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp)
137 {
138   bActionGroup *agrp = (bActionGroup *)ale->data;
139   ID *owner_id = ale->id;
140
141   /* major priority is selection status
142    * so we need both a group and an owner
143    */
144   if (ELEM(NULL, agrp, owner_id))
145     return;
146
147   /* for standard Objects, check if group is the name of some bone */
148   if (GS(owner_id->name) == ID_OB) {
149     Object *ob = (Object *)owner_id;
150
151     /* check if there are bones, and whether the name matches any
152      * NOTE: this feature will only really work if groups by default contain the F-Curves
153      * for a single bone.
154      */
155     if (ob->pose) {
156       bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
157       bArmature *arm = ob->data;
158
159       if (pchan) {
160         bActionGroup *bgrp;
161
162         /* if one matches, sync the selection status */
163         if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
164           agrp->flag |= AGRP_SELECTED;
165         else
166           agrp->flag &= ~AGRP_SELECTED;
167
168         /* also sync active group status */
169         if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) {
170           /* if no previous F-Curve has active flag, then we're the first and only one to get it */
171           if (*active_agrp == NULL) {
172             agrp->flag |= AGRP_ACTIVE;
173             *active_agrp = agrp;
174           }
175           else {
176             /* someone else has already taken it - set as not active */
177             agrp->flag &= ~AGRP_ACTIVE;
178           }
179         }
180         else {
181           /* this can't possibly be active now */
182           agrp->flag &= ~AGRP_ACTIVE;
183         }
184
185         /* sync group colors */
186         bgrp = (bActionGroup *)BLI_findlink(&ob->pose->agroups, (pchan->agrp_index - 1));
187         if (bgrp) {
188           agrp->customCol = bgrp->customCol;
189           action_group_colors_sync(agrp, bgrp);
190         }
191       }
192     }
193   }
194 }
195
196 /* perform syncing updates for F-Curves */
197 static void animchan_sync_fcurve(bAnimContext *UNUSED(ac),
198                                  bAnimListElem *ale,
199                                  FCurve **active_fcurve)
200 {
201   FCurve *fcu = (FCurve *)ale->data;
202   ID *owner_id = ale->id;
203
204   /* major priority is selection status, so refer to the checks done in anim_filter.c
205    * skip_fcurve_selected_data() for reference about what's going on here...
206    */
207   if (ELEM(NULL, fcu, fcu->rna_path, owner_id))
208     return;
209
210   if (GS(owner_id->name) == ID_SCE) {
211     Scene *scene = (Scene *)owner_id;
212
213     /* only affect if F-Curve involves sequence_editor.sequences */
214     if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
215       Editing *ed = BKE_sequencer_editing_get(scene, false);
216       Sequence *seq;
217       char *seq_name;
218
219       /* get strip name, and check if this strip is selected */
220       seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
221       seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false);
222       if (seq_name)
223         MEM_freeN(seq_name);
224
225       /* update selection status */
226       if (seq) {
227         if (seq->flag & SELECT)
228           fcu->flag |= FCURVE_SELECTED;
229         else
230           fcu->flag &= ~FCURVE_SELECTED;
231       }
232     }
233   }
234   else if (GS(owner_id->name) == ID_NT) {
235     bNodeTree *ntree = (bNodeTree *)owner_id;
236
237     /* check for selected nodes */
238     if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
239       bNode *node;
240       char *node_name;
241
242       /* get strip name, and check if this strip is selected */
243       node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes[");
244       node = nodeFindNodebyName(ntree, node_name);
245       if (node_name)
246         MEM_freeN(node_name);
247
248       /* update selection/active status */
249       if (node) {
250         /* update selection status */
251         if (node->flag & NODE_SELECT)
252           fcu->flag |= FCURVE_SELECTED;
253         else
254           fcu->flag &= ~FCURVE_SELECTED;
255
256         /* update active status */
257         /* XXX: this may interfere with setting bones as active if both exist at once;
258          * then again, if that's the case, production setups aren't likely to be animating
259          * nodes while working with bones?
260          */
261         if (node->flag & NODE_ACTIVE) {
262           if (*active_fcurve == NULL) {
263             fcu->flag |= FCURVE_ACTIVE;
264             *active_fcurve = fcu;
265           }
266           else {
267             fcu->flag &= ~FCURVE_ACTIVE;
268           }
269         }
270         else {
271           fcu->flag &= ~FCURVE_ACTIVE;
272         }
273       }
274     }
275   }
276 }
277
278 /* perform syncing updates for GPencil Layers */
279 static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale)
280 {
281   bGPDlayer *gpl = (bGPDlayer *)ale->data;
282
283   /* Make sure the selection flags agree with the "active" flag.
284    * The selection flags are used in the Dopesheet only, whereas
285    * the active flag is used everywhere else. Hence, we try to
286    * sync these here so that it all seems to be have as the user
287    * expects - T50184
288    *
289    * Assume that we only really do this when the active status changes.
290    * (NOTE: This may prove annoying if it means selection is always lost)
291    */
292   if (gpl->flag & GP_LAYER_ACTIVE) {
293     gpl->flag |= GP_LAYER_SELECT;
294   }
295   else {
296     gpl->flag &= ~GP_LAYER_SELECT;
297   }
298 }
299
300 /* ---------------- */
301
302 /* Main call to be exported to animation editors */
303 void ANIM_sync_animchannels_to_data(const bContext *C)
304 {
305   bAnimContext ac;
306   ListBase anim_data = {NULL, NULL};
307   bAnimListElem *ale;
308   int filter;
309
310   bActionGroup *active_agrp = NULL;
311   FCurve *active_fcurve = NULL;
312
313   /* get animation context info for filtering the channels */
314   if (ANIM_animdata_get_context(C, &ac) == 0)
315     return;
316
317   /* filter data */
318
319   /* NOTE: we want all channels, since we want to be able to set selection status on some of them
320    * even when collapsed... however,
321    * don't include duplicates so that selection statuses don't override each other.
322    */
323   filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS;
324   ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
325
326   /* flush settings as appropriate depending on the types of the channels */
327   for (ale = anim_data.first; ale; ale = ale->next) {
328     switch (ale->type) {
329       case ANIMTYPE_GROUP:
330         animchan_sync_group(&ac, ale, &active_agrp);
331         break;
332
333       case ANIMTYPE_FCURVE:
334         animchan_sync_fcurve(&ac, ale, &active_fcurve);
335         break;
336
337       case ANIMTYPE_GPLAYER:
338         animchan_sync_gplayer(&ac, ale);
339         break;
340     }
341   }
342
343   ANIM_animdata_freelist(&anim_data);
344 }
345
346 void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
347 {
348   bAnimListElem *ale;
349
350   if (ELEM(ac->datatype, ANIMCONT_MASK)) {
351 #ifdef DEBUG
352     /* quiet assert */
353     for (ale = anim_data->first; ale; ale = ale->next) {
354       ale->update = 0;
355     }
356 #endif
357     return;
358   }
359
360   for (ale = anim_data->first; ale; ale = ale->next) {
361     if (ale->type == ANIMTYPE_GPLAYER) {
362       bGPDlayer *gpl = ale->data;
363
364       if (ale->update & ANIM_UPDATE_ORDER) {
365         ale->update &= ~ANIM_UPDATE_ORDER;
366         if (gpl) {
367           //gpencil_sort_frames(gpl);
368         }
369       }
370
371       if (ale->update & ANIM_UPDATE_DEPS) {
372         ale->update &= ~ANIM_UPDATE_DEPS;
373         ANIM_list_elem_update(ac->bmain, ac->scene, ale);
374       }
375       /* disable handles to avoid crash */
376       if (ale->update & ANIM_UPDATE_HANDLES) {
377         ale->update &= ~ANIM_UPDATE_HANDLES;
378       }
379     }
380     else if (ale->datatype == ALE_FCURVE) {
381       FCurve *fcu = ale->key_data;
382
383       if (ale->update & ANIM_UPDATE_ORDER) {
384         ale->update &= ~ANIM_UPDATE_ORDER;
385         if (fcu)
386           sort_time_fcurve(fcu);
387       }
388
389       if (ale->update & ANIM_UPDATE_HANDLES) {
390         ale->update &= ~ANIM_UPDATE_HANDLES;
391         if (fcu)
392           calchandles_fcurve(fcu);
393       }
394
395       if (ale->update & ANIM_UPDATE_DEPS) {
396         ale->update &= ~ANIM_UPDATE_DEPS;
397         ANIM_list_elem_update(ac->bmain, ac->scene, ale);
398       }
399     }
400     else if (ELEM(ale->type,
401                   ANIMTYPE_ANIMDATA,
402                   ANIMTYPE_NLAACTION,
403                   ANIMTYPE_NLATRACK,
404                   ANIMTYPE_NLACURVE)) {
405       if (ale->update & ANIM_UPDATE_DEPS) {
406         ale->update &= ~ANIM_UPDATE_DEPS;
407         ANIM_list_elem_update(ac->bmain, ac->scene, ale);
408       }
409     }
410     else if (ale->update) {
411 #if 0
412       if (G.debug & G_DEBUG) {
413         printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n",
414                __func__,
415                ale->update,
416                ale->type,
417                ale->data);
418       }
419 #endif
420       /* Prevent crashes in cases where it can't be handled */
421       ale->update = 0;
422     }
423
424     BLI_assert(ale->update == 0);
425   }
426 }
427
428 void ANIM_animdata_freelist(ListBase *anim_data)
429 {
430 #ifndef NDEBUG
431   bAnimListElem *ale, *ale_next;
432   for (ale = anim_data->first; ale; ale = ale_next) {
433     ale_next = ale->next;
434     BLI_assert(ale->update == 0);
435     MEM_freeN(ale);
436   }
437   BLI_listbase_clear(anim_data);
438 #else
439   BLI_freelistN(anim_data);
440 #endif
441 }