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