Cleanup: remove redundant doxygen \file argument
[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 \ingroup edanimation
21  */
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_COPY_ON_WRITE);
75                 }
76         }
77
78         /* Tag copy on the main object if updating anything directly inside AnimData */
79         if (ELEM(ale->type, ANIMTYPE_ANIMDATA, ANIMTYPE_NLAACTION, ANIMTYPE_NLATRACK, ANIMTYPE_NLACURVE)) {
80                 DEG_id_tag_update(id, ID_RECALC_ANIMATION | ID_RECALC_COPY_ON_WRITE);
81                 return;
82         }
83
84         /* update data */
85         fcu = (ale->datatype == ALE_FCURVE) ? ale->key_data : NULL;
86
87         if (fcu && fcu->rna_path) {
88                 /* if we have an fcurve, call the update for the property we
89                  * are editing, this is then expected to do the proper redraws
90                  * and depsgraph updates  */
91                 PointerRNA id_ptr, ptr;
92                 PropertyRNA *prop;
93
94                 RNA_id_pointer_create(id, &id_ptr);
95
96                 if (RNA_path_resolve_property(&id_ptr, fcu->rna_path, &ptr, &prop))
97                         RNA_property_update_main(bmain, scene, &ptr, prop);
98         }
99         else {
100                 /* in other case we do standard depsgraph update, ideally
101                  * we'd be calling property update functions here too ... */
102                 DEG_id_tag_update(id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); // XXX or do we want something more restrictive?
103         }
104 }
105
106 /* tags the given ID block for refreshes (if applicable) due to
107  * Animation Editor editing */
108 void ANIM_id_update(Main *bmain, ID *id)
109 {
110         if (id) {
111                 DEG_id_tag_update_ex(bmain, id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_ANIMATION); // XXX or do we want something more restrictive?
112         }
113 }
114
115 /* **************************** animation data <-> data syncing ******************************** */
116 /* This code here is used to synchronize the
117  * - selection (to find selected data easier)
118  * - ... (insert other relevant items here later)
119  * status in relevant Blender data with the status stored in animation channels.
120  *
121  * This should be called in the refresh() callbacks for various editors in
122  * response to appropriate notifiers.
123  */
124
125 /* perform syncing updates for Action Groups */
126 static void animchan_sync_group(bAnimContext *ac, bAnimListElem *ale, bActionGroup **active_agrp)
127 {
128         bActionGroup *agrp = (bActionGroup *)ale->data;
129         ID *owner_id = ale->id;
130
131         /* major priority is selection status
132          * so we need both a group and an owner
133          */
134         if (ELEM(NULL, agrp, owner_id))
135                 return;
136
137         /* for standard Objects, check if group is the name of some bone */
138         if (GS(owner_id->name) == ID_OB) {
139                 Object *ob = (Object *)owner_id;
140
141                 /* check if there are bones, and whether the name matches any
142                  * NOTE: this feature will only really work if groups by default contain the F-Curves for a single bone
143                  */
144                 if (ob->pose) {
145                         bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, agrp->name);
146                         bArmature *arm = ob->data;
147
148                         if (pchan) {
149                                 bActionGroup *bgrp;
150
151                                 /* if one matches, sync the selection status */
152                                 if ((pchan->bone) && (pchan->bone->flag & BONE_SELECTED))
153                                         agrp->flag |= AGRP_SELECTED;
154                                 else
155                                         agrp->flag &= ~AGRP_SELECTED;
156
157                                 /* also sync active group status */
158                                 if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) {
159                                         /* if no previous F-Curve has active flag, then we're the first and only one to get it */
160                                         if (*active_agrp == NULL) {
161                                                 agrp->flag |= AGRP_ACTIVE;
162                                                 *active_agrp = agrp;
163                                         }
164                                         else {
165                                                 /* someone else has already taken it - set as not active */
166                                                 agrp->flag &= ~AGRP_ACTIVE;
167                                         }
168                                 }
169                                 else {
170                                         /* this can't possibly be active now */
171                                         agrp->flag &= ~AGRP_ACTIVE;
172                                 }
173
174                                 /* sync group colors */
175                                 bgrp = (bActionGroup *)BLI_findlink(&ob->pose->agroups, (pchan->agrp_index - 1));
176                                 if (bgrp) {
177                                         agrp->customCol = bgrp->customCol;
178                                         action_group_colors_sync(agrp, bgrp);
179                                 }
180                         }
181                 }
182         }
183 }
184
185 /* perform syncing updates for F-Curves */
186 static void animchan_sync_fcurve(bAnimContext *ac, bAnimListElem *ale, FCurve **active_fcurve)
187 {
188         FCurve *fcu = (FCurve *)ale->data;
189         ID *owner_id = ale->id;
190
191         /* major priority is selection status, so refer to the checks done in anim_filter.c
192          * skip_fcurve_selected_data() for reference about what's going on here...
193          */
194         if (ELEM(NULL, fcu, fcu->rna_path, owner_id))
195                 return;
196
197         if (GS(owner_id->name) == ID_OB) {
198                 Object *ob = (Object *)owner_id;
199
200                 /* only affect if F-Curve involves pose.bones */
201                 if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
202                         bArmature *arm = (bArmature *)ob->data;
203                         bPoseChannel *pchan;
204                         char *bone_name;
205
206                         /* get bone-name, and check if this bone is selected */
207                         bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
208                         pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
209                         if (bone_name) MEM_freeN(bone_name);
210
211                         /* F-Curve selection depends on whether the bone is selected */
212                         if ((pchan) && (pchan->bone)) {
213                                 /* F-Curve selection */
214                                 if (pchan->bone->flag & BONE_SELECTED)
215                                         fcu->flag |= FCURVE_SELECTED;
216                                 else
217                                         fcu->flag &= ~FCURVE_SELECTED;
218
219                                 /* Active F-Curve - it should be the first one for this bone on the
220                                  * active object to be considered as active
221                                  */
222                                 if ((ob == ac->obact) && (pchan->bone == arm->act_bone)) {
223                                         /* if no previous F-Curve has active flag, then we're the first and only one to get it */
224                                         if (*active_fcurve == NULL) {
225                                                 fcu->flag |= FCURVE_ACTIVE;
226                                                 *active_fcurve = fcu;
227                                         }
228                                         else {
229                                                 /* someone else has already taken it - set as not active */
230                                                 fcu->flag &= ~FCURVE_ACTIVE;
231                                         }
232                                 }
233                                 else {
234                                         /* this can't possibly be active now */
235                                         fcu->flag &= ~FCURVE_ACTIVE;
236                                 }
237                         }
238                 }
239         }
240         else if (GS(owner_id->name) == ID_SCE) {
241                 Scene *scene = (Scene *)owner_id;
242
243                 /* only affect if F-Curve involves sequence_editor.sequences */
244                 if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
245                         Editing *ed = BKE_sequencer_editing_get(scene, false);
246                         Sequence *seq;
247                         char *seq_name;
248
249                         /* get strip name, and check if this strip is selected */
250                         seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
251                         seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false);
252                         if (seq_name) MEM_freeN(seq_name);
253
254                         /* update selection status */
255                         if (seq) {
256                                 if (seq->flag & SELECT)
257                                         fcu->flag |= FCURVE_SELECTED;
258                                 else
259                                         fcu->flag &= ~FCURVE_SELECTED;
260                         }
261                 }
262         }
263         else if (GS(owner_id->name) == ID_NT) {
264                 bNodeTree *ntree = (bNodeTree *)owner_id;
265
266                 /* check for selected nodes */
267                 if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
268                         bNode *node;
269                         char *node_name;
270
271                         /* get strip name, and check if this strip is selected */
272                         node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes[");
273                         node = nodeFindNodebyName(ntree, node_name);
274                         if (node_name) MEM_freeN(node_name);
275
276                         /* update selection/active status */
277                         if (node) {
278                                 /* update selection status */
279                                 if (node->flag & NODE_SELECT)
280                                         fcu->flag |= FCURVE_SELECTED;
281                                 else
282                                         fcu->flag &= ~FCURVE_SELECTED;
283
284                                 /* update active status */
285                                 /* XXX: this may interfere with setting bones as active if both exist at once;
286                                  * then again, if that's the case, production setups aren't likely to be animating
287                                  * nodes while working with bones?
288                                  */
289                                 if (node->flag & NODE_ACTIVE) {
290                                         if (*active_fcurve == NULL) {
291                                                 fcu->flag |= FCURVE_ACTIVE;
292                                                 *active_fcurve = fcu;
293                                         }
294                                         else {
295                                                 fcu->flag &= ~FCURVE_ACTIVE;
296                                         }
297                                 }
298                                 else {
299                                         fcu->flag &= ~FCURVE_ACTIVE;
300                                 }
301                         }
302                 }
303         }
304 }
305
306 /* perform syncing updates for GPencil Layers */
307 static void animchan_sync_gplayer(bAnimContext *UNUSED(ac), bAnimListElem *ale)
308 {
309         bGPDlayer *gpl = (bGPDlayer *)ale->data;
310
311         /* Make sure the selection flags agree with the "active" flag.
312          * The selection flags are used in the Dopesheet only, whereas
313          * the active flag is used everywhere else. Hence, we try to
314          * sync these here so that it all seems to be have as the user
315          * expects - T50184
316          *
317          * Assume that we only really do this when the active status changes.
318          * (NOTE: This may prove annoying if it means selection is always lost)
319          */
320         if (gpl->flag & GP_LAYER_ACTIVE) {
321                 gpl->flag |= GP_LAYER_SELECT;
322         }
323         else {
324                 gpl->flag &= ~GP_LAYER_SELECT;
325         }
326 }
327
328 /* ---------------- */
329
330 /* Main call to be exported to animation editors */
331 void ANIM_sync_animchannels_to_data(const bContext *C)
332 {
333         bAnimContext ac;
334         ListBase anim_data = {NULL, NULL};
335         bAnimListElem *ale;
336         int filter;
337
338         bActionGroup *active_agrp = NULL;
339         FCurve *active_fcurve = NULL;
340
341         /* get animation context info for filtering the channels */
342         if (ANIM_animdata_get_context(C, &ac) == 0)
343                 return;
344
345         /* filter data */
346         /* NOTE: we want all channels, since we want to be able to set selection status on some of them even when collapsed
347          *       However, don't include duplicates so that selection statuses don't override each other
348          */
349         filter = ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS;
350         ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype);
351
352         /* flush settings as appropriate depending on the types of the channels */
353         for (ale = anim_data.first; ale; ale = ale->next) {
354                 switch (ale->type) {
355                         case ANIMTYPE_GROUP:
356                                 animchan_sync_group(&ac, ale, &active_agrp);
357                                 break;
358
359                         case ANIMTYPE_FCURVE:
360                                 animchan_sync_fcurve(&ac, ale, &active_fcurve);
361                                 break;
362
363                         case ANIMTYPE_GPLAYER:
364                                 animchan_sync_gplayer(&ac, ale);
365                                 break;
366                 }
367         }
368
369         ANIM_animdata_freelist(&anim_data);
370 }
371
372 void ANIM_animdata_update(bAnimContext *ac, ListBase *anim_data)
373 {
374         bAnimListElem *ale;
375
376         if (ELEM(ac->datatype, ANIMCONT_MASK)) {
377 #ifdef DEBUG
378                 /* quiet assert */
379                 for (ale = anim_data->first; ale; ale = ale->next) {
380                         ale->update = 0;
381                 }
382 #endif
383                 return;
384         }
385
386         for (ale = anim_data->first; ale; ale = ale->next) {
387                 if (ale->type == ANIMTYPE_GPLAYER) {
388                         bGPDlayer *gpl = ale->data;
389
390                         if (ale->update & ANIM_UPDATE_ORDER) {
391                                 ale->update &= ~ANIM_UPDATE_ORDER;
392                                 if (gpl) {
393                                         //gpencil_sort_frames(gpl);
394                                 }
395                         }
396
397                         if (ale->update & ANIM_UPDATE_DEPS) {
398                                 ale->update &= ~ANIM_UPDATE_DEPS;
399                                 ANIM_list_elem_update(ac->bmain, ac->scene, ale);
400                         }
401                         /* disable handles to avoid crash */
402                         if (ale->update & ANIM_UPDATE_HANDLES) {
403                                 ale->update &= ~ANIM_UPDATE_HANDLES;
404                         }
405                 }
406                 else if (ale->datatype == ALE_FCURVE) {
407                         FCurve *fcu = ale->key_data;
408
409                         if (ale->update & ANIM_UPDATE_ORDER) {
410                                 ale->update &= ~ANIM_UPDATE_ORDER;
411                                 if (fcu)
412                                         sort_time_fcurve(fcu);
413                         }
414
415                         if (ale->update & ANIM_UPDATE_HANDLES) {
416                                 ale->update &= ~ANIM_UPDATE_HANDLES;
417                                 if (fcu)
418                                         calchandles_fcurve(fcu);
419                         }
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, ANIMTYPE_ANIMDATA, ANIMTYPE_NLAACTION, ANIMTYPE_NLATRACK, ANIMTYPE_NLACURVE)) {
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 (ale->update) {
433 #if 0
434                         if (G.debug & G_DEBUG) {
435                                 printf("%s: Unhandled animchannel updates (%d) for type=%d (%p)\n",
436                                        __func__, ale->update, ale->type, ale->data);
437                         }
438 #endif
439                         /* Prevent crashes in cases where it can't be handled */
440                         ale->update = 0;
441                 }
442
443                 BLI_assert(ale->update == 0);
444         }
445 }
446
447 void ANIM_animdata_freelist(ListBase *anim_data)
448 {
449 #ifndef NDEBUG
450         bAnimListElem *ale, *ale_next;
451         for (ale = anim_data->first; ale; ale = ale_next) {
452                 ale_next = ale->next;
453                 BLI_assert(ale->update == 0);
454                 MEM_freeN(ale);
455         }
456         BLI_listbase_clear(anim_data);
457 #else
458         BLI_freelistN(anim_data);
459 #endif
460 }