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