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, Joshua Leung
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup edanimation
22 */
23
24 /* This file contains a system used to provide a layer of abstraction between sources
25 * of animation data and tools in Animation Editors. The method used here involves
26 * generating a list of edit structures which enable tools to naively perform the actions
27 * they require without all the boiler-plate associated with loops within loops and checking
28 * for cases to ignore.
29 *
30 * While this is primarily used for the Action/Dopesheet Editor (and its accessory modes),
31 * the Graph Editor also uses this for its channel list and for determining which curves
32 * are being edited. Likewise, the NLA Editor also uses this for its channel list and in
33 * its operators.
34 *
35 * Note: much of the original system this was based on was built before the creation of the RNA
36 * system. In future, it would be interesting to replace some parts of this code with RNA queries,
37 * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this
38 * system, so if any such work does occur, it should only be used for the internals used here...
39 *
40 * -- Joshua Leung, Dec 2008 (Last revision July 2009)
41 */
42
43 #include <string.h>
44
45 #include "DNA_anim_types.h"
46 #include "DNA_armature_types.h"
47 #include "DNA_brush_types.h"
48 #include "DNA_cachefile_types.h"
49 #include "DNA_camera_types.h"
50 #include "DNA_gpencil_types.h"
51 #include "DNA_hair_types.h"
52 #include "DNA_key_types.h"
53 #include "DNA_lattice_types.h"
54 #include "DNA_layer_types.h"
55 #include "DNA_light_types.h"
56 #include "DNA_linestyle_types.h"
57 #include "DNA_mask_types.h"
58 #include "DNA_material_types.h"
59 #include "DNA_mesh_types.h"
60 #include "DNA_meta_types.h"
61 #include "DNA_movieclip_types.h"
62 #include "DNA_node_types.h"
63 #include "DNA_object_force_types.h"
64 #include "DNA_object_types.h"
65 #include "DNA_particle_types.h"
66 #include "DNA_pointcloud_types.h"
67 #include "DNA_scene_types.h"
68 #include "DNA_screen_types.h"
69 #include "DNA_sequence_types.h"
70 #include "DNA_simulation_types.h"
71 #include "DNA_space_types.h"
72 #include "DNA_speaker_types.h"
73 #include "DNA_userdef_types.h"
74 #include "DNA_volume_types.h"
75 #include "DNA_world_types.h"
76
77 #include "MEM_guardedalloc.h"
78
79 #include "BLI_alloca.h"
80 #include "BLI_blenlib.h"
81 #include "BLI_ghash.h"
82 #include "BLI_string.h"
83 #include "BLI_utildefines.h"
84
85 #include "BKE_action.h"
86 #include "BKE_anim_data.h"
87 #include "BKE_collection.h"
88 #include "BKE_context.h"
89 #include "BKE_fcurve.h"
90 #include "BKE_fcurve_driver.h"
91 #include "BKE_global.h"
92 #include "BKE_key.h"
93 #include "BKE_layer.h"
94 #include "BKE_main.h"
95 #include "BKE_mask.h"
96 #include "BKE_material.h"
97 #include "BKE_modifier.h"
98 #include "BKE_node.h"
99 #include "BKE_sequencer.h"
100
101 #include "ED_anim_api.h"
102 #include "ED_markers.h"
103
104 #include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */
105
106 /* ************************************************************ */
107 /* Blender Context <-> Animation Context mapping */
108
109 /* ----------- Private Stuff - General -------------------- */
110
111 /* Get vertical scaling factor (i.e. typically used for keyframe size) */
animedit_get_yscale_factor(bAnimContext * ac)112 static void animedit_get_yscale_factor(bAnimContext *ac)
113 {
114 bTheme *btheme = UI_GetTheme();
115
116 /* grab scale factor directly from action editor setting
117 * NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally
118 * since it is a float, and the theme settings methods can only handle chars.
119 */
120 ac->yscale_fac = btheme->space_action.keyframe_scale_fac;
121
122 /* clamp to avoid problems with uninitialized values... */
123 if (ac->yscale_fac < 0.1f) {
124 ac->yscale_fac = 1.0f;
125 }
126 // printf("yscale_fac = %f\n", ac->yscale_fac);
127 }
128
129 /* ----------- Private Stuff - Action Editor ------------- */
130
131 /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
132 /* Note: there's a similar function in key.c (BKE_key_from_object) */
actedit_get_shapekeys(bAnimContext * ac)133 static Key *actedit_get_shapekeys(bAnimContext *ac)
134 {
135 ViewLayer *view_layer = ac->view_layer;
136 Object *ob;
137 Key *key;
138
139 ob = OBACT(view_layer);
140 if (ob == NULL) {
141 return NULL;
142 }
143
144 /* XXX pinning is not available in 'ShapeKey' mode... */
145 // if (saction->pin) { return NULL; }
146
147 /* shapekey data is stored with geometry data */
148 key = BKE_key_from_object(ob);
149
150 if (key) {
151 if (key->type == KEY_RELATIVE) {
152 return key;
153 }
154 }
155
156 return NULL;
157 }
158
159 /* Get data being edited in Action Editor (depending on current 'mode') */
actedit_get_context(bAnimContext * ac,SpaceAction * saction)160 static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
161 {
162 /* get dopesheet */
163 ac->ads = &saction->ads;
164
165 /* sync settings with current view status, then return appropriate data */
166 switch (saction->mode) {
167 case SACTCONT_ACTION: /* 'Action Editor' */
168 /* if not pinned, sync with active object */
169 if (/*saction->pin == 0*/ true) {
170 if (ac->obact && ac->obact->adt) {
171 saction->action = ac->obact->adt->action;
172 }
173 else {
174 saction->action = NULL;
175 }
176 }
177
178 ac->datatype = ANIMCONT_ACTION;
179 ac->data = saction->action;
180
181 ac->mode = saction->mode;
182 return true;
183
184 case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
185 ac->datatype = ANIMCONT_SHAPEKEY;
186 ac->data = actedit_get_shapekeys(ac);
187
188 /* if not pinned, sync with active object */
189 if (/*saction->pin == 0*/ true) {
190 Key *key = (Key *)ac->data;
191
192 if (key && key->adt) {
193 saction->action = key->adt->action;
194 }
195 else {
196 saction->action = NULL;
197 }
198 }
199
200 ac->mode = saction->mode;
201 return true;
202
203 case SACTCONT_GPENCIL: /* Grease Pencil */ /* XXX review how this mode is handled... */
204 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
205 saction->ads.source = (ID *)ac->scene;
206
207 ac->datatype = ANIMCONT_GPENCIL;
208 ac->data = &saction->ads;
209
210 ac->mode = saction->mode;
211 return true;
212
213 case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */
214 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
215 saction->ads.source = (ID *)ac->scene;
216
217 ac->datatype = ANIMCONT_CHANNEL;
218 ac->data = &saction->ads;
219
220 ac->mode = saction->mode;
221 return true;
222
223 case SACTCONT_MASK: /* Mask */ /* XXX review how this mode is handled... */
224 {
225 /* TODO, other methods to get the mask */
226 #if 0
227 Sequence *seq = BKE_sequencer_active_get(ac->scene);
228 MovieClip *clip = ac->scene->clip;
229 struct Mask *mask = seq ? seq->mask : NULL;
230 #endif
231
232 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
233 saction->ads.source = (ID *)ac->scene;
234
235 ac->datatype = ANIMCONT_MASK;
236 ac->data = &saction->ads;
237
238 ac->mode = saction->mode;
239 return true;
240 }
241
242 case SACTCONT_DOPESHEET: /* DopeSheet */
243 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
244 saction->ads.source = (ID *)ac->scene;
245
246 ac->datatype = ANIMCONT_DOPESHEET;
247 ac->data = &saction->ads;
248
249 ac->mode = saction->mode;
250 return true;
251
252 case SACTCONT_TIMELINE: /* Timeline */
253 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
254 saction->ads.source = (ID *)ac->scene;
255
256 /* sync scene's "selected keys only" flag with our "only selected" flag
257 *
258 * XXX: This is a workaround for T55525. We shouldn't really be syncing the flags like this,
259 * but it's a simpler fix for now than also figuring out how the next/prev keyframe
260 * tools should work in the 3D View if we allowed full access to the timeline's
261 * dopesheet filters (i.e. we'd have to figure out where to host those settings,
262 * to be on a scene level like this flag currently is, along with several other unknowns).
263 */
264 if (ac->scene->flag & SCE_KEYS_NO_SELONLY) {
265 saction->ads.filterflag &= ~ADS_FILTER_ONLYSEL;
266 }
267 else {
268 saction->ads.filterflag |= ADS_FILTER_ONLYSEL;
269 }
270
271 ac->datatype = ANIMCONT_TIMELINE;
272 ac->data = &saction->ads;
273
274 ac->mode = saction->mode;
275 return true;
276
277 default: /* unhandled yet */
278 ac->datatype = ANIMCONT_NONE;
279 ac->data = NULL;
280
281 ac->mode = -1;
282 return false;
283 }
284 }
285
286 /* ----------- Private Stuff - Graph Editor ------------- */
287
288 /* Get data being edited in Graph Editor (depending on current 'mode') */
graphedit_get_context(bAnimContext * ac,SpaceGraph * sipo)289 static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo)
290 {
291 /* init dopesheet data if non-existent (i.e. for old files) */
292 if (sipo->ads == NULL) {
293 sipo->ads = MEM_callocN(sizeof(bDopeSheet), "GraphEdit DopeSheet");
294 sipo->ads->source = (ID *)ac->scene;
295 }
296 ac->ads = sipo->ads;
297
298 /* set settings for Graph Editor - "Selected = Editable" */
299 if (sipo->flag & SIPO_SELCUVERTSONLY) {
300 sipo->ads->filterflag |= ADS_FILTER_SELEDIT;
301 }
302 else {
303 sipo->ads->filterflag &= ~ADS_FILTER_SELEDIT;
304 }
305
306 /* sync settings with current view status, then return appropriate data */
307 switch (sipo->mode) {
308 case SIPO_MODE_ANIMATION: /* Animation F-Curve Editor */
309 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
310 sipo->ads->source = (ID *)ac->scene;
311 sipo->ads->filterflag &= ~ADS_FILTER_ONLYDRIVERS;
312
313 ac->datatype = ANIMCONT_FCURVES;
314 ac->data = sipo->ads;
315
316 ac->mode = sipo->mode;
317 return true;
318
319 case SIPO_MODE_DRIVERS: /* Driver F-Curve Editor */
320 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
321 sipo->ads->source = (ID *)ac->scene;
322 sipo->ads->filterflag |= ADS_FILTER_ONLYDRIVERS;
323
324 ac->datatype = ANIMCONT_DRIVERS;
325 ac->data = sipo->ads;
326
327 ac->mode = sipo->mode;
328 return true;
329
330 default: /* unhandled yet */
331 ac->datatype = ANIMCONT_NONE;
332 ac->data = NULL;
333
334 ac->mode = -1;
335 return false;
336 }
337 }
338
339 /* ----------- Private Stuff - NLA Editor ------------- */
340
341 /* Get data being edited in Graph Editor (depending on current 'mode') */
nlaedit_get_context(bAnimContext * ac,SpaceNla * snla)342 static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla)
343 {
344 /* init dopesheet data if non-existent (i.e. for old files) */
345 if (snla->ads == NULL) {
346 snla->ads = MEM_callocN(sizeof(bDopeSheet), "NlaEdit DopeSheet");
347 }
348 ac->ads = snla->ads;
349
350 /* sync settings with current view status, then return appropriate data */
351 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
352 snla->ads->source = (ID *)ac->scene;
353 snla->ads->filterflag |= ADS_FILTER_ONLYNLA;
354
355 ac->datatype = ANIMCONT_NLA;
356 ac->data = snla->ads;
357
358 return true;
359 }
360
361 /* ----------- Public API --------------- */
362
363 /* Obtain current anim-data context,
364 * given that context info from Blender context has already been set:
365 * - AnimContext to write to is provided as pointer to var on stack so that we don't have
366 * allocation/freeing costs (which are not that avoidable with channels).
367 */
ANIM_animdata_context_getdata(bAnimContext * ac)368 bool ANIM_animdata_context_getdata(bAnimContext *ac)
369 {
370 SpaceLink *sl = ac->sl;
371 bool ok = false;
372
373 /* context depends on editor we are currently in */
374 if (sl) {
375 switch (ac->spacetype) {
376 case SPACE_ACTION: {
377 SpaceAction *saction = (SpaceAction *)sl;
378 ok = actedit_get_context(ac, saction);
379 break;
380 }
381 case SPACE_GRAPH: {
382 SpaceGraph *sipo = (SpaceGraph *)sl;
383 ok = graphedit_get_context(ac, sipo);
384 break;
385 }
386 case SPACE_NLA: {
387 SpaceNla *snla = (SpaceNla *)sl;
388 ok = nlaedit_get_context(ac, snla);
389 break;
390 }
391 }
392 }
393
394 /* check if there's any valid data */
395 return (ok && ac->data);
396 }
397
398 /* Obtain current anim-data context from Blender Context info
399 * - AnimContext to write to is provided as pointer to var on stack so that we don't have
400 * allocation/freeing costs (which are not that avoidable with channels).
401 * - Clears data and sets the information from Blender Context which is useful
402 */
ANIM_animdata_get_context(const bContext * C,bAnimContext * ac)403 bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
404 {
405 Main *bmain = CTX_data_main(C);
406 ScrArea *area = CTX_wm_area(C);
407 ARegion *region = CTX_wm_region(C);
408 SpaceLink *sl = CTX_wm_space_data(C);
409 Scene *scene = CTX_data_scene(C);
410
411 /* clear old context info */
412 if (ac == NULL) {
413 return false;
414 }
415 memset(ac, 0, sizeof(bAnimContext));
416
417 /* get useful default context settings from context */
418 ac->bmain = bmain;
419 ac->scene = scene;
420 if (scene) {
421 ac->markers = ED_context_get_markers(C);
422 }
423 ac->view_layer = CTX_data_view_layer(C);
424 ac->depsgraph = CTX_data_depsgraph_pointer(C);
425 ac->obact = (ac->view_layer->basact) ? ac->view_layer->basact->object : NULL;
426 ac->area = area;
427 ac->region = region;
428 ac->sl = sl;
429 ac->spacetype = (area) ? area->spacetype : 0;
430 ac->regiontype = (region) ? region->regiontype : 0;
431
432 /* Initialize default y-scale factor. */
433 animedit_get_yscale_factor(ac);
434
435 /* get data context info */
436 /* XXX: if the below fails, try to grab this info from context instead...
437 * (to allow for scripting). */
438 return ANIM_animdata_context_getdata(ac);
439 }
440
441 /* ************************************************************ */
442 /* Blender Data <-- Filter --> Channels to be operated on */
443
444 /* macros to use before/after getting the sub-channels of some channel,
445 * to abstract away some of the tricky logic involved
446 *
447 * cases:
448 * 1) Graph Edit main area (just data) OR channels visible in Channel List
449 * 2) If not showing channels, we're only interested in the data (Action Editor's editing)
450 * 3) We don't care what data, we just care there is some (so that a collapsed
451 * channel can be kept around). No need to clear channels-flag in order to
452 * keep expander channels with no sub-data out, as those cases should get
453 * dealt with by the recursive detection idiom in place.
454 *
455 * Implementation Note:
456 * YES the _doSubChannels variable is NOT read anywhere. BUT, this is NOT an excuse
457 * to go steamrolling the logic into a single-line expression as from experience,
458 * those are notoriously difficult to read + debug when extending later on. The code
459 * below is purposefully laid out so that each case noted above corresponds clearly to
460 * one case below.
461 */
462 #define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check) \
463 { \
464 int _filter = filter_mode; \
465 short _doSubChannels = 0; \
466 if (!(filter_mode & ANIMFILTER_LIST_VISIBLE) || (expanded_check)) { \
467 _doSubChannels = 1; \
468 } \
469 else if (!(filter_mode & ANIMFILTER_LIST_CHANNELS)) { \
470 _doSubChannels = 2; \
471 } \
472 else { \
473 filter_mode |= ANIMFILTER_TMP_PEEK; \
474 } \
475 \
476 { \
477 (void)_doSubChannels; \
478 }
479 /* ... standard sub-channel filtering can go on here now ... */
480 #define END_ANIMFILTER_SUBCHANNELS \
481 filter_mode = _filter; \
482 } \
483 (void)0
484
485 /* ............................... */
486
487 /* quick macro to test if AnimData is usable */
488 #define ANIMDATA_HAS_KEYS(id) ((id)->adt && (id)->adt->action)
489
490 /* quick macro to test if AnimData is usable for drivers */
491 #define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
492
493 /* quick macro to test if AnimData is usable for NLA */
494 #define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
495
496 /**
497 * Quick macro to test for all three above usability tests, performing the appropriate provided
498 * action for each when the AnimData context is appropriate.
499 *
500 * Priority order for this goes (most important, to least):
501 * AnimData blocks, NLA, Drivers, Keyframes.
502 *
503 * For this to work correctly,
504 * a standard set of data needs to be available within the scope that this
505 *
506 * Gets called in:
507 * - ListBase anim_data;
508 * - bDopeSheet *ads;
509 * - bAnimListElem *ale;
510 * - size_t items;
511 *
512 * - id: ID block which should have an AnimData pointer following it immediately, to use
513 * - adtOk: line or block of code to execute for AnimData-blocks case
514 * (usually #ANIMDATA_ADD_ANIMDATA).
515 * - nlaOk: line or block of code to execute for NLA tracks+strips case
516 * - driversOk: line or block of code to execute for Drivers case
517 * - nlaKeysOk: line or block of code for NLA Strip Keyframes case
518 * - keysOk: line or block of code for Keyframes case
519 *
520 * The checks for the various cases are as follows:
521 * 0) top level: checks for animdata and also that all the F-Curves for the block will be visible
522 * 1) animdata check: for filtering animdata blocks only
523 * 2A) nla tracks: include animdata block's data as there are NLA tracks+strips there
524 * 2B) actions to convert to nla: include animdata block's data as there is an action that can be
525 * converted to a new NLA strip, and the filtering options allow this
526 * 2C) allow non-animated data-blocks to be included so that data-blocks can be added
527 * 3) drivers: include drivers from animdata block (for Drivers mode in Graph Editor)
528 * 4A) nla strip keyframes: these are the per-strip controls for time and influence
529 * 4B) normal keyframes: only when there is an active action
530 */
531 #define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, keysOk) \
532 { \
533 if ((id)->adt) { \
534 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || \
535 !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \
536 if (filter_mode & ANIMFILTER_ANIMDATA) { \
537 adtOk \
538 } \
539 else if (ads->filterflag & ADS_FILTER_ONLYNLA) { \
540 if (ANIMDATA_HAS_NLA(id)) { \
541 nlaOk \
542 } \
543 else if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || ANIMDATA_HAS_KEYS(id)) { \
544 nlaOk \
545 } \
546 } \
547 else if (ads->filterflag & ADS_FILTER_ONLYDRIVERS) { \
548 if (ANIMDATA_HAS_DRIVERS(id)) { \
549 driversOk \
550 } \
551 } \
552 else { \
553 if (ANIMDATA_HAS_NLA(id)) { \
554 nlaKeysOk \
555 } \
556 if (ANIMDATA_HAS_KEYS(id)) { \
557 keysOk \
558 } \
559 } \
560 } \
561 } \
562 } \
563 (void)0
564
565 /* ............................... */
566
567 /**
568 * Add a new animation channel, taking into account the "peek" flag, which is used to just check
569 * whether any channels will be added (but without needing them to actually get created).
570 *
571 * \warning This causes the calling function to return early if we're only "peeking" for channels.
572 *
573 * XXX: ale_statement stuff is really a hack for one special case. It shouldn't really be needed.
574 */
575 #define ANIMCHANNEL_NEW_CHANNEL_FULL( \
576 channel_data, channel_type, owner_id, fcurve_owner_id, ale_statement) \
577 if (filter_mode & ANIMFILTER_TMP_PEEK) { \
578 return 1; \
579 } \
580 { \
581 bAnimListElem *ale = make_new_animlistelem( \
582 channel_data, channel_type, (ID *)owner_id, fcurve_owner_id); \
583 if (ale) { \
584 BLI_addtail(anim_data, ale); \
585 items++; \
586 ale_statement \
587 } \
588 } \
589 (void)0
590
591 #define ANIMCHANNEL_NEW_CHANNEL(channel_data, channel_type, owner_id, fcurve_owner_id) \
592 ANIMCHANNEL_NEW_CHANNEL_FULL(channel_data, channel_type, owner_id, fcurve_owner_id, {})
593
594 /* ............................... */
595
596 /* quick macro to test if an anim-channel representing an AnimData block is suitably active */
597 #define ANIMCHANNEL_ACTIVEOK(ale) \
598 (!(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE))
599
600 /* Quick macro to test if an anim-channel (F-Curve, Group, etc.)
601 * is selected in an acceptable way. */
602 #define ANIMCHANNEL_SELOK(test_func) \
603 (!(filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) || \
604 ((filter_mode & ANIMFILTER_SEL) && test_func) || \
605 ((filter_mode & ANIMFILTER_UNSEL) && test_func == 0))
606
607 /* quick macro to test if an anim-channel (F-Curve) is selected ok for editing purposes
608 * - _SELEDIT means that only selected curves will have visible+editable keyframes
609 *
610 * checks here work as follows:
611 * 1) seledit off - don't need to consider the implications of this option
612 * 2) foredit off - we're not considering editing, so channel is ok still
613 * 3) test_func (i.e. selection test) - only if selected, this test will pass
614 */
615 #define ANIMCHANNEL_SELEDITOK(test_func) \
616 (!(filter_mode & ANIMFILTER_SELEDIT) || !(filter_mode & ANIMFILTER_FOREDIT) || (test_func))
617
618 /* ----------- 'Private' Stuff --------------- */
619
620 /* this function allocates memory for a new bAnimListElem struct for the
621 * provided animation channel-data.
622 */
make_new_animlistelem(void * data,short datatype,ID * owner_id,ID * fcurve_owner_id)623 static bAnimListElem *make_new_animlistelem(void *data,
624 short datatype,
625 ID *owner_id,
626 ID *fcurve_owner_id)
627 {
628 bAnimListElem *ale = NULL;
629
630 /* only allocate memory if there is data to convert */
631 if (data) {
632 /* allocate and set generic data */
633 ale = MEM_callocN(sizeof(bAnimListElem), "bAnimListElem");
634
635 ale->data = data;
636 ale->type = datatype;
637
638 ale->id = owner_id;
639 ale->adt = BKE_animdata_from_id(owner_id);
640 ale->fcurve_owner_id = fcurve_owner_id;
641
642 /* do specifics */
643 switch (datatype) {
644 case ANIMTYPE_SUMMARY: {
645 /* Nothing to include for now... this is just a dummy wrapper around
646 * all the other channels in the DopeSheet, and gets included at the start of the list. */
647 ale->key_data = NULL;
648 ale->datatype = ALE_ALL;
649 break;
650 }
651 case ANIMTYPE_SCENE: {
652 Scene *sce = (Scene *)data;
653
654 ale->flag = sce->flag;
655
656 ale->key_data = sce;
657 ale->datatype = ALE_SCE;
658
659 ale->adt = BKE_animdata_from_id(data);
660 break;
661 }
662 case ANIMTYPE_OBJECT: {
663 Base *base = (Base *)data;
664 Object *ob = base->object;
665
666 ale->flag = ob->flag;
667
668 ale->key_data = ob;
669 ale->datatype = ALE_OB;
670
671 ale->adt = BKE_animdata_from_id(&ob->id);
672 break;
673 }
674 case ANIMTYPE_FILLACTD: {
675 bAction *act = (bAction *)data;
676
677 ale->flag = act->flag;
678
679 ale->key_data = act;
680 ale->datatype = ALE_ACT;
681 break;
682 }
683 case ANIMTYPE_FILLDRIVERS: {
684 AnimData *adt = (AnimData *)data;
685
686 ale->flag = adt->flag;
687
688 /* XXX drivers don't show summary for now. */
689 ale->key_data = NULL;
690 ale->datatype = ALE_NONE;
691 break;
692 }
693 case ANIMTYPE_DSMAT: {
694 Material *ma = (Material *)data;
695 AnimData *adt = ma->adt;
696
697 ale->flag = FILTER_MAT_OBJD(ma);
698
699 ale->key_data = (adt) ? adt->action : NULL;
700 ale->datatype = ALE_ACT;
701
702 ale->adt = BKE_animdata_from_id(data);
703 break;
704 }
705 case ANIMTYPE_DSLAM: {
706 Light *la = (Light *)data;
707 AnimData *adt = la->adt;
708
709 ale->flag = FILTER_LAM_OBJD(la);
710
711 ale->key_data = (adt) ? adt->action : NULL;
712 ale->datatype = ALE_ACT;
713
714 ale->adt = BKE_animdata_from_id(data);
715 break;
716 }
717 case ANIMTYPE_DSCAM: {
718 Camera *ca = (Camera *)data;
719 AnimData *adt = ca->adt;
720
721 ale->flag = FILTER_CAM_OBJD(ca);
722
723 ale->key_data = (adt) ? adt->action : NULL;
724 ale->datatype = ALE_ACT;
725
726 ale->adt = BKE_animdata_from_id(data);
727 break;
728 }
729 case ANIMTYPE_DSCACHEFILE: {
730 CacheFile *cache_file = (CacheFile *)data;
731 AnimData *adt = cache_file->adt;
732
733 ale->flag = FILTER_CACHEFILE_OBJD(cache_file);
734
735 ale->key_data = (adt) ? adt->action : NULL;
736 ale->datatype = ALE_ACT;
737
738 ale->adt = BKE_animdata_from_id(data);
739 break;
740 }
741 case ANIMTYPE_DSCUR: {
742 Curve *cu = (Curve *)data;
743 AnimData *adt = cu->adt;
744
745 ale->flag = FILTER_CUR_OBJD(cu);
746
747 ale->key_data = (adt) ? adt->action : NULL;
748 ale->datatype = ALE_ACT;
749
750 ale->adt = BKE_animdata_from_id(data);
751 break;
752 }
753 case ANIMTYPE_DSARM: {
754 bArmature *arm = (bArmature *)data;
755 AnimData *adt = arm->adt;
756
757 ale->flag = FILTER_ARM_OBJD(arm);
758
759 ale->key_data = (adt) ? adt->action : NULL;
760 ale->datatype = ALE_ACT;
761
762 ale->adt = BKE_animdata_from_id(data);
763 break;
764 }
765 case ANIMTYPE_DSMESH: {
766 Mesh *me = (Mesh *)data;
767 AnimData *adt = me->adt;
768
769 ale->flag = FILTER_MESH_OBJD(me);
770
771 ale->key_data = (adt) ? adt->action : NULL;
772 ale->datatype = ALE_ACT;
773
774 ale->adt = BKE_animdata_from_id(data);
775 break;
776 }
777 case ANIMTYPE_DSLAT: {
778 Lattice *lt = (Lattice *)data;
779 AnimData *adt = lt->adt;
780
781 ale->flag = FILTER_LATTICE_OBJD(lt);
782
783 ale->key_data = (adt) ? adt->action : NULL;
784 ale->datatype = ALE_ACT;
785
786 ale->adt = BKE_animdata_from_id(data);
787 break;
788 }
789 case ANIMTYPE_DSSPK: {
790 Speaker *spk = (Speaker *)data;
791 AnimData *adt = spk->adt;
792
793 ale->flag = FILTER_SPK_OBJD(spk);
794
795 ale->key_data = (adt) ? adt->action : NULL;
796 ale->datatype = ALE_ACT;
797
798 ale->adt = BKE_animdata_from_id(data);
799 break;
800 }
801 case ANIMTYPE_DSHAIR: {
802 Hair *hair = (Hair *)data;
803 AnimData *adt = hair->adt;
804
805 ale->flag = FILTER_HAIR_OBJD(hair);
806
807 ale->key_data = (adt) ? adt->action : NULL;
808 ale->datatype = ALE_ACT;
809
810 ale->adt = BKE_animdata_from_id(data);
811 break;
812 }
813 case ANIMTYPE_DSPOINTCLOUD: {
814 PointCloud *pointcloud = (PointCloud *)data;
815 AnimData *adt = pointcloud->adt;
816
817 ale->flag = FILTER_POINTS_OBJD(pointcloud);
818
819 ale->key_data = (adt) ? adt->action : NULL;
820 ale->datatype = ALE_ACT;
821
822 ale->adt = BKE_animdata_from_id(data);
823 break;
824 }
825 case ANIMTYPE_DSVOLUME: {
826 Volume *volume = (Volume *)data;
827 AnimData *adt = volume->adt;
828
829 ale->flag = FILTER_VOLUME_OBJD(volume);
830
831 ale->key_data = (adt) ? adt->action : NULL;
832 ale->datatype = ALE_ACT;
833
834 ale->adt = BKE_animdata_from_id(data);
835 break;
836 }
837 case ANIMTYPE_DSSIMULATION: {
838 Simulation *simulation = (Simulation *)data;
839 AnimData *adt = simulation->adt;
840
841 ale->flag = FILTER_SIMULATION_OBJD(simulation);
842
843 ale->key_data = (adt) ? adt->action : NULL;
844 ale->datatype = ALE_ACT;
845
846 ale->adt = BKE_animdata_from_id(data);
847 break;
848 }
849 case ANIMTYPE_DSSKEY: {
850 Key *key = (Key *)data;
851 AnimData *adt = key->adt;
852
853 ale->flag = FILTER_SKE_OBJD(key);
854
855 ale->key_data = (adt) ? adt->action : NULL;
856 ale->datatype = ALE_ACT;
857
858 ale->adt = BKE_animdata_from_id(data);
859 break;
860 }
861 case ANIMTYPE_DSWOR: {
862 World *wo = (World *)data;
863 AnimData *adt = wo->adt;
864
865 ale->flag = FILTER_WOR_SCED(wo);
866
867 ale->key_data = (adt) ? adt->action : NULL;
868 ale->datatype = ALE_ACT;
869
870 ale->adt = BKE_animdata_from_id(data);
871 break;
872 }
873 case ANIMTYPE_DSNTREE: {
874 bNodeTree *ntree = (bNodeTree *)data;
875 AnimData *adt = ntree->adt;
876
877 ale->flag = FILTER_NTREE_DATA(ntree);
878
879 ale->key_data = (adt) ? adt->action : NULL;
880 ale->datatype = ALE_ACT;
881
882 ale->adt = BKE_animdata_from_id(data);
883 break;
884 }
885 case ANIMTYPE_DSLINESTYLE: {
886 FreestyleLineStyle *linestyle = (FreestyleLineStyle *)data;
887 AnimData *adt = linestyle->adt;
888
889 ale->flag = FILTER_LS_SCED(linestyle);
890
891 ale->key_data = (adt) ? adt->action : NULL;
892 ale->datatype = ALE_ACT;
893
894 ale->adt = BKE_animdata_from_id(data);
895 break;
896 }
897 case ANIMTYPE_DSPART: {
898 ParticleSettings *part = (ParticleSettings *)ale->data;
899 AnimData *adt = part->adt;
900
901 ale->flag = FILTER_PART_OBJD(part);
902
903 ale->key_data = (adt) ? adt->action : NULL;
904 ale->datatype = ALE_ACT;
905
906 ale->adt = BKE_animdata_from_id(data);
907 break;
908 }
909 case ANIMTYPE_DSTEX: {
910 Tex *tex = (Tex *)data;
911 AnimData *adt = tex->adt;
912
913 ale->flag = FILTER_TEX_DATA(tex);
914
915 ale->key_data = (adt) ? adt->action : NULL;
916 ale->datatype = ALE_ACT;
917
918 ale->adt = BKE_animdata_from_id(data);
919 break;
920 }
921 case ANIMTYPE_DSGPENCIL: {
922 bGPdata *gpd = (bGPdata *)data;
923 AnimData *adt = gpd->adt;
924
925 /* NOTE: we just reuse the same expand filter for this case */
926 ale->flag = EXPANDED_GPD(gpd);
927
928 /* XXX: currently, this is only used for access to its animation data */
929 ale->key_data = (adt) ? adt->action : NULL;
930 ale->datatype = ALE_ACT;
931
932 ale->adt = BKE_animdata_from_id(data);
933 break;
934 }
935 case ANIMTYPE_DSMCLIP: {
936 MovieClip *clip = (MovieClip *)data;
937 AnimData *adt = clip->adt;
938
939 ale->flag = EXPANDED_MCLIP(clip);
940
941 ale->key_data = (adt) ? adt->action : NULL;
942 ale->datatype = ALE_ACT;
943
944 ale->adt = BKE_animdata_from_id(data);
945 break;
946 }
947 case ANIMTYPE_NLACONTROLS: {
948 AnimData *adt = (AnimData *)data;
949
950 ale->flag = adt->flag;
951
952 ale->key_data = NULL;
953 ale->datatype = ALE_NONE;
954 break;
955 }
956 case ANIMTYPE_GROUP: {
957 bActionGroup *agrp = (bActionGroup *)data;
958
959 ale->flag = agrp->flag;
960
961 ale->key_data = NULL;
962 ale->datatype = ALE_GROUP;
963 break;
964 }
965 case ANIMTYPE_FCURVE:
966 case ANIMTYPE_NLACURVE: /* practically the same as ANIMTYPE_FCURVE.
967 * Differences are applied post-creation */
968 {
969 FCurve *fcu = (FCurve *)data;
970
971 ale->flag = fcu->flag;
972
973 ale->key_data = fcu;
974 ale->datatype = ALE_FCURVE;
975 break;
976 }
977 case ANIMTYPE_SHAPEKEY: {
978 KeyBlock *kb = (KeyBlock *)data;
979 Key *key = (Key *)ale->id;
980
981 ale->flag = kb->flag;
982
983 /* whether we have keyframes depends on whether there is a Key block to find it from */
984 if (key) {
985 /* index of shapekey is defined by place in key's list */
986 ale->index = BLI_findindex(&key->block, kb);
987
988 /* the corresponding keyframes are from the animdata */
989 if (ale->adt && ale->adt->action) {
990 bAction *act = ale->adt->action;
991 char *rna_path = BKE_keyblock_curval_rnapath_get(key, kb);
992
993 /* try to find the F-Curve which corresponds to this exactly,
994 * then free the MEM_alloc'd string
995 */
996 if (rna_path) {
997 ale->key_data = (void *)BKE_fcurve_find(&act->curves, rna_path, 0);
998 MEM_freeN(rna_path);
999 }
1000 }
1001 ale->datatype = (ale->key_data) ? ALE_FCURVE : ALE_NONE;
1002 }
1003 break;
1004 }
1005 case ANIMTYPE_GPLAYER: {
1006 bGPDlayer *gpl = (bGPDlayer *)data;
1007
1008 ale->flag = gpl->flag;
1009
1010 ale->key_data = NULL;
1011 ale->datatype = ALE_GPFRAME;
1012 break;
1013 }
1014 case ANIMTYPE_MASKLAYER: {
1015 MaskLayer *masklay = (MaskLayer *)data;
1016
1017 ale->flag = masklay->flag;
1018
1019 ale->key_data = NULL;
1020 ale->datatype = ALE_MASKLAY;
1021 break;
1022 }
1023 case ANIMTYPE_NLATRACK: {
1024 NlaTrack *nlt = (NlaTrack *)data;
1025
1026 ale->flag = nlt->flag;
1027
1028 ale->key_data = &nlt->strips;
1029 ale->datatype = ALE_NLASTRIP;
1030 break;
1031 }
1032 case ANIMTYPE_NLAACTION: {
1033 /* nothing to include for now... nothing editable from NLA-perspective here */
1034 ale->key_data = NULL;
1035 ale->datatype = ALE_NONE;
1036 break;
1037 }
1038 }
1039 }
1040
1041 /* return created datatype */
1042 return ale;
1043 }
1044
1045 /* ----------------------------------------- */
1046
1047 /* 'Only Selected' selected data and/or 'Include Hidden' filtering
1048 * NOTE: when this function returns true, the F-Curve is to be skipped
1049 */
skip_fcurve_selected_data(bDopeSheet * ads,FCurve * fcu,ID * owner_id,int filter_mode)1050 static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id, int filter_mode)
1051 {
1052 if (fcu->grp != NULL && fcu->grp->flag & ADT_CURVES_ALWAYS_VISIBLE) {
1053 return false;
1054 }
1055 /* hidden items should be skipped if we only care about visible data,
1056 * but we aren't interested in hidden stuff */
1057 const bool skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) &&
1058 !(ads->filterflag & ADS_FILTER_INCL_HIDDEN);
1059
1060 if (GS(owner_id->name) == ID_OB) {
1061 Object *ob = (Object *)owner_id;
1062
1063 /* only consider if F-Curve involves pose.bones */
1064 if ((fcu->rna_path) && strstr(fcu->rna_path, "pose.bones")) {
1065 bPoseChannel *pchan;
1066 char *bone_name;
1067
1068 /* get bone-name, and check if this bone is selected */
1069 bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
1070 pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
1071 if (bone_name) {
1072 MEM_freeN(bone_name);
1073 }
1074
1075 /* check whether to continue or skip */
1076 if ((pchan) && (pchan->bone)) {
1077 /* If only visible channels,
1078 * skip if bone not visible unless user wants channels from hidden data too. */
1079 if (skip_hidden) {
1080 bArmature *arm = (bArmature *)ob->data;
1081
1082 /* skipping - not visible on currently visible layers */
1083 if ((arm->layer & pchan->bone->layer) == 0) {
1084 return true;
1085 }
1086 /* skipping - is currently hidden */
1087 if (pchan->bone->flag & BONE_HIDDEN_P) {
1088 return true;
1089 }
1090 }
1091
1092 /* can only add this F-Curve if it is selected */
1093 if (ads->filterflag & ADS_FILTER_ONLYSEL) {
1094 if ((pchan->bone->flag & BONE_SELECTED) == 0) {
1095 return true;
1096 }
1097 }
1098 }
1099 }
1100 }
1101 else if (GS(owner_id->name) == ID_SCE) {
1102 Scene *scene = (Scene *)owner_id;
1103
1104 /* only consider if F-Curve involves sequence_editor.sequences */
1105 if ((fcu->rna_path) && strstr(fcu->rna_path, "sequences_all")) {
1106 Editing *ed = BKE_sequencer_editing_get(scene, false);
1107 Sequence *seq = NULL;
1108 char *seq_name;
1109
1110 if (ed) {
1111 /* get strip name, and check if this strip is selected */
1112 seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
1113 seq = BKE_sequence_get_by_name(ed->seqbasep, seq_name, false);
1114 if (seq_name) {
1115 MEM_freeN(seq_name);
1116 }
1117 }
1118
1119 /* can only add this F-Curve if it is selected */
1120 if (ads->filterflag & ADS_FILTER_ONLYSEL) {
1121 if ((seq == NULL) || (seq->flag & SELECT) == 0) {
1122 return true;
1123 }
1124 }
1125 }
1126 }
1127 else if (GS(owner_id->name) == ID_NT) {
1128 bNodeTree *ntree = (bNodeTree *)owner_id;
1129
1130 /* check for selected nodes */
1131 if ((fcu->rna_path) && strstr(fcu->rna_path, "nodes")) {
1132 bNode *node;
1133 char *node_name;
1134
1135 /* get strip name, and check if this strip is selected */
1136 node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes[");
1137 node = nodeFindNodebyName(ntree, node_name);
1138 if (node_name) {
1139 MEM_freeN(node_name);
1140 }
1141
1142 /* can only add this F-Curve if it is selected */
1143 if (ads->filterflag & ADS_FILTER_ONLYSEL) {
1144 if ((node) && (node->flag & NODE_SELECT) == 0) {
1145 return true;
1146 }
1147 }
1148 }
1149 }
1150
1151 return false;
1152 }
1153
1154 /* Helper for name-based filtering - Perform "partial/fuzzy matches" (as in 80a7efd) */
name_matches_dopesheet_filter(bDopeSheet * ads,char * name)1155 static bool name_matches_dopesheet_filter(bDopeSheet *ads, char *name)
1156 {
1157 if (ads->flag & ADS_FLAG_FUZZY_NAMES) {
1158 /* full fuzzy, multi-word, case insensitive matches */
1159 const size_t str_len = strlen(ads->searchstr);
1160 const int words_max = BLI_string_max_possible_word_count(str_len);
1161
1162 int(*words)[2] = BLI_array_alloca(words, words_max);
1163 const int words_len = BLI_string_find_split_words(
1164 ads->searchstr, str_len, ' ', words, words_max);
1165 bool found = false;
1166
1167 /* match name against all search words */
1168 for (int index = 0; index < words_len; index++) {
1169 if (BLI_strncasestr(name, ads->searchstr + words[index][0], words[index][1])) {
1170 found = true;
1171 break;
1172 }
1173 }
1174
1175 /* if we have a match somewhere, this returns true */
1176 return ((ads->flag & ADS_FLAG_INVERT_FILTER) == 0) ? found : !found;
1177 }
1178 /* fallback/default - just case insensitive, but starts from start of word */
1179 bool found = BLI_strcasestr(name, ads->searchstr) != NULL;
1180 return ((ads->flag & ADS_FLAG_INVERT_FILTER) == 0) ? found : !found;
1181 }
1182
1183 /* (Display-)Name-based F-Curve filtering
1184 * NOTE: when this function returns true, the F-Curve is to be skipped
1185 */
skip_fcurve_with_name(bDopeSheet * ads,FCurve * fcu,eAnim_ChannelType channel_type,void * owner,ID * owner_id)1186 static bool skip_fcurve_with_name(
1187 bDopeSheet *ads, FCurve *fcu, eAnim_ChannelType channel_type, void *owner, ID *owner_id)
1188 {
1189 bAnimListElem ale_dummy = {NULL};
1190 const bAnimChannelType *acf;
1191
1192 /* create a dummy wrapper for the F-Curve, so we can get typeinfo for it */
1193 ale_dummy.type = channel_type;
1194 ale_dummy.owner = owner;
1195 ale_dummy.id = owner_id;
1196 ale_dummy.data = fcu;
1197
1198 /* get type info for channel */
1199 acf = ANIM_channel_get_typeinfo(&ale_dummy);
1200 if (acf && acf->name) {
1201 char name[256]; /* hopefully this will be enough! */
1202
1203 /* get name */
1204 acf->name(&ale_dummy, name);
1205
1206 /* check for partial match with the match string, assuming case insensitive filtering
1207 * if match, this channel shouldn't be ignored!
1208 */
1209 return !name_matches_dopesheet_filter(ads, name);
1210 }
1211
1212 /* just let this go... */
1213 return true;
1214 }
1215
1216 /**
1217 * Check if F-Curve has errors and/or is disabled
1218 *
1219 * \return true if F-Curve has errors/is disabled
1220 */
fcurve_has_errors(FCurve * fcu)1221 static bool fcurve_has_errors(FCurve *fcu)
1222 {
1223 /* F-Curve disabled - path eval error */
1224 if (fcu->flag & FCURVE_DISABLED) {
1225 return true;
1226 }
1227
1228 /* driver? */
1229 if (fcu->driver) {
1230 ChannelDriver *driver = fcu->driver;
1231 DriverVar *dvar;
1232
1233 /* error flag on driver usually means that there is an error
1234 * BUT this may not hold with PyDrivers as this flag gets cleared
1235 * if no critical errors prevent the driver from working...
1236 */
1237 if (driver->flag & DRIVER_FLAG_INVALID) {
1238 return true;
1239 }
1240
1241 /* check variables for other things that need linting... */
1242 /* TODO: maybe it would be more efficient just to have a quick flag for this? */
1243 for (dvar = driver->variables.first; dvar; dvar = dvar->next) {
1244 DRIVER_TARGETS_USED_LOOPER_BEGIN (dvar) {
1245 if (dtar->flag & DTAR_FLAG_INVALID) {
1246 return true;
1247 }
1248 }
1249 DRIVER_TARGETS_LOOPER_END;
1250 }
1251 }
1252
1253 /* no errors found */
1254 return false;
1255 }
1256
1257 /* find the next F-Curve that is usable for inclusion */
animfilter_fcurve_next(bDopeSheet * ads,FCurve * first,eAnim_ChannelType channel_type,int filter_mode,void * owner,ID * owner_id)1258 static FCurve *animfilter_fcurve_next(bDopeSheet *ads,
1259 FCurve *first,
1260 eAnim_ChannelType channel_type,
1261 int filter_mode,
1262 void *owner,
1263 ID *owner_id)
1264 {
1265 bActionGroup *grp = (channel_type == ANIMTYPE_FCURVE) ? owner : NULL;
1266 FCurve *fcu = NULL;
1267
1268 /* Loop over F-Curves - assume that the caller of this has already checked
1269 * that these should be included.
1270 * NOTE: we need to check if the F-Curves belong to the same group,
1271 * as this gets called for groups too...
1272 */
1273 for (fcu = first; ((fcu) && (fcu->grp == grp)); fcu = fcu->next) {
1274 /* special exception for Pose-Channel/Sequence-Strip/Node Based F-Curves:
1275 * - The 'Only Selected' and 'Include Hidden' data filters should be applied to sub-ID data
1276 * which can be independently selected/hidden, such as Pose-Channels, Sequence Strips,
1277 * and Nodes. Since these checks were traditionally done as first check for objects,
1278 * we do the same here.
1279 * - We currently use an 'approximate' method for getting these F-Curves that doesn't require
1280 * carefully checking the entire path.
1281 * - This will also affect things like Drivers, and also works for Bone Constraints.
1282 */
1283 if (ads && owner_id) {
1284 if ((filter_mode & ANIMFILTER_TMP_IGNORE_ONLYSEL) == 0) {
1285 if ((ads->filterflag & ADS_FILTER_ONLYSEL) ||
1286 (ads->filterflag & ADS_FILTER_INCL_HIDDEN) == 0) {
1287 if (skip_fcurve_selected_data(ads, fcu, owner_id, filter_mode)) {
1288 continue;
1289 }
1290 }
1291 }
1292 }
1293
1294 /* only include if visible (Graph Editor check, not channels check) */
1295 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
1296 /* only work with this channel and its subchannels if it is editable */
1297 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
1298 /* Only include this curve if selected in a way consistent
1299 * with the filtering requirements. */
1300 if (ANIMCHANNEL_SELOK(SEL_FCU(fcu)) && ANIMCHANNEL_SELEDITOK(SEL_FCU(fcu))) {
1301 /* only include if this curve is active */
1302 if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
1303 /* name based filtering... */
1304 if (((ads) && (ads->searchstr[0] != '\0')) && (owner_id)) {
1305 if (skip_fcurve_with_name(ads, fcu, channel_type, owner, owner_id)) {
1306 continue;
1307 }
1308 }
1309
1310 /* error-based filtering... */
1311 if ((ads) && (ads->filterflag & ADS_FILTER_ONLY_ERRORS)) {
1312 /* skip if no errors... */
1313 if (fcurve_has_errors(fcu) == false) {
1314 continue;
1315 }
1316 }
1317
1318 /* this F-Curve can be used, so return it */
1319 return fcu;
1320 }
1321 }
1322 }
1323 }
1324 }
1325
1326 /* no (more) F-Curves from the list are suitable... */
1327 return NULL;
1328 }
1329
animfilter_fcurves(ListBase * anim_data,bDopeSheet * ads,FCurve * first,eAnim_ChannelType fcurve_type,int filter_mode,void * owner,ID * owner_id,ID * fcurve_owner_id)1330 static size_t animfilter_fcurves(ListBase *anim_data,
1331 bDopeSheet *ads,
1332 FCurve *first,
1333 eAnim_ChannelType fcurve_type,
1334 int filter_mode,
1335 void *owner,
1336 ID *owner_id,
1337 ID *fcurve_owner_id)
1338 {
1339 FCurve *fcu;
1340 size_t items = 0;
1341
1342 /* Loop over every F-Curve able to be included.
1343 *
1344 * This for-loop works like this:
1345 * 1) The starting F-Curve is assigned to the fcu pointer
1346 * so that we have a starting point to search from.
1347 * 2) The first valid F-Curve to start from (which may include the one given as 'first')
1348 * in the remaining list of F-Curves is found, and verified to be non-null.
1349 * 3) The F-Curve referenced by fcu pointer is added to the list
1350 * 4) The fcu pointer is set to the F-Curve after the one we just added,
1351 * so that we can keep going through the rest of the F-Curve list without an eternal loop.
1352 * Back to step 2 :)
1353 */
1354 for (fcu = first;
1355 ((fcu = animfilter_fcurve_next(ads, fcu, fcurve_type, filter_mode, owner, owner_id)));
1356 fcu = fcu->next) {
1357 if (UNLIKELY(fcurve_type == ANIMTYPE_NLACURVE)) {
1358 /* NLA Control Curve - Basically the same as normal F-Curves,
1359 * except we need to set some stuff differently */
1360 ANIMCHANNEL_NEW_CHANNEL_FULL(fcu, ANIMTYPE_NLACURVE, owner_id, fcurve_owner_id, {
1361 ale->owner = owner; /* strip */
1362 ale->adt = NULL; /* to prevent time mapping from causing problems */
1363 });
1364 }
1365 else {
1366 /* Normal FCurve */
1367 ANIMCHANNEL_NEW_CHANNEL(fcu, ANIMTYPE_FCURVE, owner_id, fcurve_owner_id);
1368 }
1369 }
1370
1371 /* return the number of items added to the list */
1372 return items;
1373 }
1374
animfilter_act_group(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,bAction * act,bActionGroup * agrp,int filter_mode,ID * owner_id)1375 static size_t animfilter_act_group(bAnimContext *ac,
1376 ListBase *anim_data,
1377 bDopeSheet *ads,
1378 bAction *act,
1379 bActionGroup *agrp,
1380 int filter_mode,
1381 ID *owner_id)
1382 {
1383 ListBase tmp_data = {NULL, NULL};
1384 size_t tmp_items = 0;
1385 size_t items = 0;
1386 // int ofilter = filter_mode;
1387
1388 /* if we care about the selection status of the channels,
1389 * but the group isn't expanded (1)...
1390 * (1) this only matters if we actually care about the hierarchy though.
1391 * - Hierarchy matters: this hack should be applied
1392 * - Hierarchy ignored: cases like T21276 won't work properly, unless we skip this hack
1393 */
1394 if (
1395 /* Care about hierarchy but group isn't expanded. */
1396 ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp) == 0) &&
1397 /* Care about selection status. */
1398 (filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL))) {
1399 /* If the group itself isn't selected appropriately,
1400 * we shouldn't consider its children either. */
1401 if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0) {
1402 return 0;
1403 }
1404
1405 /* if we're still here,
1406 * then the selection status of the curves within this group should not matter,
1407 * since this creates too much overhead for animators (i.e. making a slow workflow).
1408 *
1409 * Tools affected by this at time of coding (2010 Feb 09):
1410 * - Inserting keyframes on selected channels only.
1411 * - Pasting keyframes.
1412 * - Creating ghost curves in Graph Editor.
1413 */
1414 filter_mode &= ~(ANIMFILTER_SEL | ANIMFILTER_UNSEL | ANIMFILTER_LIST_VISIBLE);
1415 }
1416
1417 /* add grouped F-Curves */
1418 BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_AGRP(ac, agrp)) {
1419 /* special filter so that we can get just the F-Curves within the active group */
1420 if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
1421 /* for the Graph Editor, curves may be set to not be visible in the view to lessen
1422 * clutter, but to do this, we need to check that the group doesn't have its
1423 * not-visible flag set preventing all its sub-curves to be shown
1424 */
1425 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE)) {
1426 /* group must be editable for its children to be editable (if we care about this) */
1427 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
1428 /* get first F-Curve which can be used here */
1429 FCurve *first_fcu = animfilter_fcurve_next(
1430 ads, agrp->channels.first, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id);
1431
1432 /* filter list, starting from this F-Curve */
1433 tmp_items += animfilter_fcurves(
1434 &tmp_data, ads, first_fcu, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id, &act->id);
1435 }
1436 }
1437 }
1438 }
1439 END_ANIMFILTER_SUBCHANNELS;
1440
1441 /* did we find anything? */
1442 if (tmp_items) {
1443 /* add this group as a channel first */
1444 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1445 /* restore original filter mode so that this next step works ok... */
1446 // filter_mode = ofilter;
1447
1448 /* filter selection of channel specially here again,
1449 * since may be open and not subject to previous test */
1450 if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp))) {
1451 ANIMCHANNEL_NEW_CHANNEL(agrp, ANIMTYPE_GROUP, owner_id, &act->id);
1452 }
1453 }
1454
1455 /* now add the list of collected channels */
1456 BLI_movelisttolist(anim_data, &tmp_data);
1457 BLI_assert(BLI_listbase_is_empty(&tmp_data));
1458 items += tmp_items;
1459 }
1460
1461 /* return the number of items added to the list */
1462 return items;
1463 }
1464
animfilter_action(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,bAction * act,int filter_mode,ID * owner_id)1465 static size_t animfilter_action(bAnimContext *ac,
1466 ListBase *anim_data,
1467 bDopeSheet *ads,
1468 bAction *act,
1469 int filter_mode,
1470 ID *owner_id)
1471 {
1472 bActionGroup *agrp;
1473 FCurve *lastchan = NULL;
1474 size_t items = 0;
1475
1476 /* don't include anything from this action if it is linked in from another file,
1477 * and we're getting stuff for editing...
1478 */
1479 if ((filter_mode & ANIMFILTER_FOREDIT) && ID_IS_LINKED(act)) {
1480 return 0;
1481 }
1482
1483 /* do groups */
1484 /* TODO: do nested groups? */
1485 for (agrp = act->groups.first; agrp; agrp = agrp->next) {
1486 /* store reference to last channel of group */
1487 if (agrp->channels.last) {
1488 lastchan = agrp->channels.last;
1489 }
1490
1491 /* action group's channels */
1492 items += animfilter_act_group(ac, anim_data, ads, act, agrp, filter_mode, owner_id);
1493 }
1494
1495 /* un-grouped F-Curves (only if we're not only considering those channels in the active group) */
1496 if (!(filter_mode & ANIMFILTER_ACTGROUPED)) {
1497 FCurve *firstfcu = (lastchan) ? (lastchan->next) : (act->curves.first);
1498 items += animfilter_fcurves(
1499 anim_data, ads, firstfcu, ANIMTYPE_FCURVE, filter_mode, NULL, owner_id, &act->id);
1500 }
1501
1502 /* return the number of items added to the list */
1503 return items;
1504 }
1505
1506 /* Include NLA-Data for NLA-Editor:
1507 * - When ANIMFILTER_LIST_CHANNELS is used, that means we should be filtering the list for display
1508 * Although the evaluation order is from the first track to the last and then apply the
1509 * Action on top, we present this in the UI as the Active Action followed by the last track
1510 * to the first so that we get the evaluation order presented as per a stack.
1511 * - For normal filtering (i.e. for editing),
1512 * we only need the NLA-tracks but they can be in 'normal' evaluation order, i.e. first to last.
1513 * Otherwise, some tools may get screwed up.
1514 */
animfilter_nla(bAnimContext * UNUSED (ac),ListBase * anim_data,bDopeSheet * ads,AnimData * adt,int filter_mode,ID * owner_id)1515 static size_t animfilter_nla(bAnimContext *UNUSED(ac),
1516 ListBase *anim_data,
1517 bDopeSheet *ads,
1518 AnimData *adt,
1519 int filter_mode,
1520 ID *owner_id)
1521 {
1522 NlaTrack *nlt;
1523 NlaTrack *first = NULL, *next = NULL;
1524 size_t items = 0;
1525
1526 /* if showing channels, include active action */
1527 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1528 /* if NLA action-line filtering is off, don't show unless there are keyframes,
1529 * in order to keep things more compact for doing transforms
1530 */
1531 if (!(ads->filterflag & ADS_FILTER_NLA_NOACT) || (adt->action)) {
1532 /* there isn't really anything editable here, so skip if need editable */
1533 if ((filter_mode & ANIMFILTER_FOREDIT) == 0) {
1534 /* Just add the action track now (this MUST appear for drawing):
1535 * - As AnimData may not have an action,
1536 * we pass a dummy pointer just to get the list elem created,
1537 * then overwrite this with the real value - REVIEW THIS.
1538 */
1539 ANIMCHANNEL_NEW_CHANNEL_FULL((void *)(&adt->action), ANIMTYPE_NLAACTION, owner_id, NULL, {
1540 ale->data = adt->action ? adt->action : NULL;
1541 });
1542 }
1543 }
1544
1545 /* first track to include will be the last one if we're filtering by channels */
1546 first = adt->nla_tracks.last;
1547 }
1548 else {
1549 /* first track to include will the first one (as per normal) */
1550 first = adt->nla_tracks.first;
1551 }
1552
1553 /* loop over NLA Tracks -
1554 * assume that the caller of this has already checked that these should be included */
1555 for (nlt = first; nlt; nlt = next) {
1556 /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
1557 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1558 next = nlt->prev;
1559 }
1560 else {
1561 next = nlt->next;
1562 }
1563
1564 /* only work with this channel and its subchannels if it is editable */
1565 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
1566 /* only include this track if selected in a way consistent with the filtering requirements */
1567 if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) {
1568 /* only include if this track is active */
1569 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
1570 /* name based filtering... */
1571 if (((ads) && (ads->searchstr[0] != '\0')) && (owner_id)) {
1572 bool track_ok = false, strip_ok = false;
1573
1574 /* check if the name of the track, or the strips it has are ok... */
1575 track_ok = name_matches_dopesheet_filter(ads, nlt->name);
1576
1577 if (track_ok == false) {
1578 NlaStrip *strip;
1579 for (strip = nlt->strips.first; strip; strip = strip->next) {
1580 if (name_matches_dopesheet_filter(ads, strip->name)) {
1581 strip_ok = true;
1582 break;
1583 }
1584 }
1585 }
1586
1587 /* skip if both fail this test... */
1588 if (!track_ok && !strip_ok) {
1589 continue;
1590 }
1591 }
1592
1593 /* add the track now that it has passed all our tests */
1594 ANIMCHANNEL_NEW_CHANNEL(nlt, ANIMTYPE_NLATRACK, owner_id, NULL);
1595 }
1596 }
1597 }
1598 }
1599
1600 /* return the number of items added to the list */
1601 return items;
1602 }
1603
1604 /* Include the control FCurves per NLA Strip in the channel list
1605 * NOTE: This is includes the expander too...
1606 */
animfilter_nla_controls(ListBase * anim_data,bDopeSheet * ads,AnimData * adt,int filter_mode,ID * owner_id)1607 static size_t animfilter_nla_controls(
1608 ListBase *anim_data, bDopeSheet *ads, AnimData *adt, int filter_mode, ID *owner_id)
1609 {
1610 ListBase tmp_data = {NULL, NULL};
1611 size_t tmp_items = 0;
1612 size_t items = 0;
1613
1614 /* add control curves from each NLA strip... */
1615 /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */
1616 BEGIN_ANIMFILTER_SUBCHANNELS (((adt->flag & ADT_NLA_SKEYS_COLLAPSED) == 0)) {
1617 NlaTrack *nlt;
1618 NlaStrip *strip;
1619
1620 /* for now, we only go one level deep - so controls on grouped FCurves are not handled */
1621 for (nlt = adt->nla_tracks.first; nlt; nlt = nlt->next) {
1622 for (strip = nlt->strips.first; strip; strip = strip->next) {
1623 /* pass strip as the "owner",
1624 * so that the name lookups (used while filtering) will resolve */
1625 /* NLA tracks are coming from AnimData, so owner of f-curves
1626 * is the same as owner of animation data. */
1627 tmp_items += animfilter_fcurves(&tmp_data,
1628 ads,
1629 strip->fcurves.first,
1630 ANIMTYPE_NLACURVE,
1631 filter_mode,
1632 strip,
1633 owner_id,
1634 owner_id);
1635 }
1636 }
1637 }
1638 END_ANIMFILTER_SUBCHANNELS;
1639
1640 /* did we find anything? */
1641 if (tmp_items) {
1642 /* add the expander as a channel first */
1643 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1644 /* currently these channels cannot be selected, so they should be skipped */
1645 if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) {
1646 ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_NLACONTROLS, owner_id, NULL);
1647 }
1648 }
1649
1650 /* now add the list of collected channels */
1651 BLI_movelisttolist(anim_data, &tmp_data);
1652 BLI_assert(BLI_listbase_is_empty(&tmp_data));
1653 items += tmp_items;
1654 }
1655
1656 /* return the number of items added to the list */
1657 return items;
1658 }
1659
1660 /* determine what animation data from AnimData block should get displayed */
animfilter_block_data(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,ID * id,int filter_mode)1661 static size_t animfilter_block_data(
1662 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *id, int filter_mode)
1663 {
1664 AnimData *adt = BKE_animdata_from_id(id);
1665 size_t items = 0;
1666
1667 /* image object data-blocks have no anim-data so check for NULL */
1668 if (adt) {
1669 IdAdtTemplate *iat = (IdAdtTemplate *)id;
1670
1671 /* NOTE: this macro is used instead of inlining the logic here,
1672 * since this sort of filtering is still needed in a few places in the rest of the code still -
1673 * notably for the few cases where special mode-based
1674 * different types of data expanders are required.
1675 */
1676 ANIMDATA_FILTER_CASES(
1677 iat,
1678 { /* AnimData */
1679 /* specifically filter animdata block */
1680 if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(adt))) {
1681 ANIMCHANNEL_NEW_CHANNEL(adt, ANIMTYPE_ANIMDATA, id, NULL);
1682 }
1683 },
1684 { /* NLA */
1685 items += animfilter_nla(ac, anim_data, ads, adt, filter_mode, id);
1686 },
1687 { /* Drivers */
1688 items += animfilter_fcurves(
1689 anim_data, ads, adt->drivers.first, ANIMTYPE_FCURVE, filter_mode, NULL, id, id);
1690 },
1691 { /* NLA Control Keyframes */
1692 items += animfilter_nla_controls(anim_data, ads, adt, filter_mode, id);
1693 },
1694 { /* Keyframes */
1695 items += animfilter_action(ac, anim_data, ads, adt->action, filter_mode, id);
1696 });
1697 }
1698
1699 return items;
1700 }
1701
1702 /* Include ShapeKey Data for ShapeKey Editor */
animdata_filter_shapekey(bAnimContext * ac,ListBase * anim_data,Key * key,int filter_mode)1703 static size_t animdata_filter_shapekey(bAnimContext *ac,
1704 ListBase *anim_data,
1705 Key *key,
1706 int filter_mode)
1707 {
1708 size_t items = 0;
1709
1710 /* check if channels or only F-Curves */
1711 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1712 KeyBlock *kb;
1713 bDopeSheet *ads = ac->ads;
1714
1715 /* loop through the channels adding ShapeKeys as appropriate */
1716 for (kb = key->block.first; kb; kb = kb->next) {
1717 /* skip the first one, since that's the non-animatable basis */
1718 if (kb == key->block.first) {
1719 continue;
1720 }
1721
1722 /* Skip shapekey if the name doesn't match the filter string. */
1723 if (ads != NULL && ads->searchstr[0] != '\0' &&
1724 name_matches_dopesheet_filter(ads, kb->name) == false) {
1725 continue;
1726 }
1727
1728 /* only work with this channel and its subchannels if it is editable */
1729 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
1730 /* Only include this track if selected in a way consistent
1731 * with the filtering requirements. */
1732 if (ANIMCHANNEL_SELOK(SEL_SHAPEKEY(kb))) {
1733 /* TODO: consider 'active' too? */
1734
1735 /* owner-id here must be key so that the F-Curve can be resolved... */
1736 ANIMCHANNEL_NEW_CHANNEL(kb, ANIMTYPE_SHAPEKEY, key, NULL);
1737 }
1738 }
1739 }
1740 }
1741 else {
1742 /* just use the action associated with the shapekey */
1743 /* TODO: somehow manage to pass dopesheet info down here too? */
1744 if (key->adt) {
1745 if (filter_mode & ANIMFILTER_ANIMDATA) {
1746 if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(key->adt))) {
1747 ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, key, NULL);
1748 }
1749 }
1750 else if (key->adt->action) {
1751 items = animfilter_action(ac, anim_data, NULL, key->adt->action, filter_mode, (ID *)key);
1752 }
1753 }
1754 }
1755
1756 /* return the number of items added to the list */
1757 return items;
1758 }
1759
1760 /* Helper for Grease Pencil - layers within a data-block. */
animdata_filter_gpencil_layers_data(ListBase * anim_data,bDopeSheet * ads,bGPdata * gpd,int filter_mode)1761 static size_t animdata_filter_gpencil_layers_data(ListBase *anim_data,
1762 bDopeSheet *ads,
1763 bGPdata *gpd,
1764 int filter_mode)
1765 {
1766 bGPDlayer *gpl;
1767 size_t items = 0;
1768
1769 /* loop over layers as the conditions are acceptable (top-Down order) */
1770 for (gpl = gpd->layers.last; gpl; gpl = gpl->prev) {
1771 /* only if selected */
1772 if (!ANIMCHANNEL_SELOK(SEL_GPL(gpl))) {
1773 continue;
1774 }
1775
1776 /* only if editable */
1777 if ((filter_mode & ANIMFILTER_FOREDIT) && !EDITABLE_GPL(gpl)) {
1778 continue;
1779 }
1780
1781 /* active... */
1782 if ((filter_mode & ANIMFILTER_ACTIVE) && (gpl->flag & GP_LAYER_ACTIVE) == 0) {
1783 continue;
1784 }
1785
1786 /* skip layer if the name doesn't match the filter string */
1787 if (ads != NULL && ads->searchstr[0] != '\0' &&
1788 name_matches_dopesheet_filter(ads, gpl->info) == false) {
1789 continue;
1790 }
1791
1792 /* Skip empty layers. */
1793 if (BLI_listbase_is_empty(&gpl->frames)) {
1794 continue;
1795 }
1796
1797 /* add to list */
1798 ANIMCHANNEL_NEW_CHANNEL(gpl, ANIMTYPE_GPLAYER, gpd, NULL);
1799 }
1800
1801 return items;
1802 }
1803
1804 /* Helper for Grease Pencil - Grease Pencil data-block - GP Frames. */
animdata_filter_gpencil_data(ListBase * anim_data,bDopeSheet * ads,bGPdata * gpd,int filter_mode)1805 static size_t animdata_filter_gpencil_data(ListBase *anim_data,
1806 bDopeSheet *ads,
1807 bGPdata *gpd,
1808 int filter_mode)
1809 {
1810 size_t items = 0;
1811
1812 /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation),
1813 * for convenience, this will return GP Data-blocks instead.
1814 * This may cause issues down the track, but for now, this will do.
1815 */
1816 if (filter_mode & ANIMFILTER_ANIMDATA) {
1817 /* just add GPD as a channel - this will add everything needed */
1818 ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, gpd, NULL);
1819 }
1820 else {
1821 ListBase tmp_data = {NULL, NULL};
1822 size_t tmp_items = 0;
1823
1824 /* add gpencil animation channels */
1825 BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_GPD(gpd)) {
1826 tmp_items += animdata_filter_gpencil_layers_data(&tmp_data, ads, gpd, filter_mode);
1827 }
1828 END_ANIMFILTER_SUBCHANNELS;
1829
1830 /* did we find anything? */
1831 if (tmp_items) {
1832 /* include data-expand widget first */
1833 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1834 /* add gpd as channel too (if for drawing, and it has layers) */
1835 ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_GPDATABLOCK, NULL, NULL);
1836 }
1837
1838 /* now add the list of collected channels */
1839 BLI_movelisttolist(anim_data, &tmp_data);
1840 BLI_assert(BLI_listbase_is_empty(&tmp_data));
1841 items += tmp_items;
1842 }
1843 }
1844
1845 return items;
1846 }
1847
1848 /**
1849 * Grab all Grease Pencil data-blocks in file.
1850 *
1851 * TODO: should this be amalgamated with the dope-sheet filtering code?
1852 */
animdata_filter_gpencil(bAnimContext * ac,ListBase * anim_data,void * UNUSED (data),int filter_mode)1853 static size_t animdata_filter_gpencil(bAnimContext *ac,
1854 ListBase *anim_data,
1855 void *UNUSED(data),
1856 int filter_mode)
1857 {
1858 bDopeSheet *ads = ac->ads;
1859 size_t items = 0;
1860
1861 ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
1862 Base *base;
1863
1864 /* Include all annotation datablocks. */
1865 if (((ads->filterflag & ADS_FILTER_ONLYSEL) == 0) ||
1866 (ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
1867 LISTBASE_FOREACH (bGPdata *, gpd, &ac->bmain->gpencils) {
1868 if (gpd->flag & GP_DATA_ANNOTATIONS) {
1869 items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode);
1870 }
1871 }
1872 }
1873 /* Objects in the scene */
1874 for (base = view_layer->object_bases.first; base; base = base->next) {
1875 /* Only consider this object if it has got some GP data (saving on all the other tests) */
1876 if (base->object && (base->object->type == OB_GPENCIL)) {
1877 Object *ob = base->object;
1878
1879 /* firstly, check if object can be included, by the following factors:
1880 * - if only visible, must check for layer and also viewport visibility
1881 * --> while tools may demand only visible, user setting takes priority
1882 * as user option controls whether sets of channels get included while
1883 * tool-flag takes into account collapsed/open channels too
1884 * - if only selected, must check if object is selected
1885 * - there must be animation data to edit (this is done recursively as we
1886 * try to add the channels)
1887 */
1888 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
1889 /* Layer visibility - we check both object and base,
1890 * since these may not be in sync yet. */
1891 if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) {
1892 continue;
1893 }
1894
1895 /* outliner restrict-flag */
1896 if (ob->restrictflag & OB_RESTRICT_VIEWPORT) {
1897 continue;
1898 }
1899 }
1900
1901 /* check selection and object type filters */
1902 if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) {
1903 /* only selected should be shown */
1904 continue;
1905 }
1906
1907 /* check if object belongs to the filtering group if option to filter
1908 * objects by the grouped status is on
1909 * - used to ease the process of doing multiple-character choreographies
1910 */
1911 if (ads->filter_grp != NULL) {
1912 if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) {
1913 continue;
1914 }
1915 }
1916
1917 /* finally, include this object's grease pencil data-block. */
1918 /* XXX: Should we store these under expanders per item? */
1919 items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode);
1920 }
1921 }
1922
1923 /* return the number of items added to the list */
1924 return items;
1925 }
1926
1927 /* Helper for Grease Pencil data integrated with main DopeSheet */
animdata_filter_ds_gpencil(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,bGPdata * gpd,int filter_mode)1928 static size_t animdata_filter_ds_gpencil(
1929 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, bGPdata *gpd, int filter_mode)
1930 {
1931 ListBase tmp_data = {NULL, NULL};
1932 size_t tmp_items = 0;
1933 size_t items = 0;
1934
1935 /* add relevant animation channels for Grease Pencil */
1936 BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_GPD(gpd)) {
1937 /* add animation channels */
1938 tmp_items += animfilter_block_data(ac, &tmp_data, ads, &gpd->id, filter_mode);
1939
1940 /* add Grease Pencil layers */
1941
1942 /* TODO: do these need a separate expander?
1943 * XXX: what order should these go in? */
1944 }
1945 END_ANIMFILTER_SUBCHANNELS;
1946
1947 /* did we find anything? */
1948 if (tmp_items) {
1949 /* include data-expand widget first */
1950 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1951 /* check if filtering by active status */
1952 /* XXX: active check here needs checking */
1953 if (ANIMCHANNEL_ACTIVEOK(gpd)) {
1954 ANIMCHANNEL_NEW_CHANNEL(gpd, ANIMTYPE_DSGPENCIL, gpd, NULL);
1955 }
1956 }
1957
1958 /* now add the list of collected channels */
1959 BLI_movelisttolist(anim_data, &tmp_data);
1960 BLI_assert(BLI_listbase_is_empty(&tmp_data));
1961 items += tmp_items;
1962 }
1963
1964 /* return the number of items added to the list */
1965 return items;
1966 }
1967
1968 /* Helper for Cache File data integrated with main DopeSheet */
animdata_filter_ds_cachefile(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,CacheFile * cache_file,int filter_mode)1969 static size_t animdata_filter_ds_cachefile(
1970 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, CacheFile *cache_file, int filter_mode)
1971 {
1972 ListBase tmp_data = {NULL, NULL};
1973 size_t tmp_items = 0;
1974 size_t items = 0;
1975
1976 /* add relevant animation channels for Cache File */
1977 BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_CACHEFILE_OBJD(cache_file)) {
1978 /* add animation channels */
1979 tmp_items += animfilter_block_data(ac, &tmp_data, ads, &cache_file->id, filter_mode);
1980 }
1981 END_ANIMFILTER_SUBCHANNELS;
1982
1983 /* did we find anything? */
1984 if (tmp_items) {
1985 /* include data-expand widget first */
1986 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1987 /* check if filtering by active status */
1988 /* XXX: active check here needs checking */
1989 if (ANIMCHANNEL_ACTIVEOK(cache_file)) {
1990 ANIMCHANNEL_NEW_CHANNEL(cache_file, ANIMTYPE_DSCACHEFILE, cache_file, NULL);
1991 }
1992 }
1993
1994 /* now add the list of collected channels */
1995 BLI_movelisttolist(anim_data, &tmp_data);
1996 BLI_assert(BLI_listbase_is_empty(&tmp_data));
1997 items += tmp_items;
1998 }
1999
2000 /* return the number of items added to the list */
2001 return items;
2002 }
2003
2004 /* Helper for Mask Editing - mask layers */
animdata_filter_mask_data(ListBase * anim_data,Mask * mask,const int filter_mode)2005 static size_t animdata_filter_mask_data(ListBase *anim_data, Mask *mask, const int filter_mode)
2006 {
2007 MaskLayer *masklay_act = BKE_mask_layer_active(mask);
2008 MaskLayer *masklay;
2009 size_t items = 0;
2010
2011 /* loop over layers as the conditions are acceptable */
2012 for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) {
2013 /* only if selected */
2014 if (ANIMCHANNEL_SELOK(SEL_MASKLAY(masklay))) {
2015 /* only if editable */
2016 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_MASK(masklay)) {
2017 /* active... */
2018 if (!(filter_mode & ANIMFILTER_ACTIVE) || (masklay_act == masklay)) {
2019 /* add to list */
2020 ANIMCHANNEL_NEW_CHANNEL(masklay, ANIMTYPE_MASKLAYER, mask, NULL);
2021 }
2022 }
2023 }
2024 }
2025
2026 return items;
2027 }
2028
2029 /* Grab all mask data */
animdata_filter_mask(Main * bmain,ListBase * anim_data,void * UNUSED (data),int filter_mode)2030 static size_t animdata_filter_mask(Main *bmain,
2031 ListBase *anim_data,
2032 void *UNUSED(data),
2033 int filter_mode)
2034 {
2035 Mask *mask;
2036 size_t items = 0;
2037
2038 /* For now, grab mask data-blocks directly from main. */
2039 /* XXX: this is not good... */
2040 for (mask = bmain->masks.first; mask; mask = mask->id.next) {
2041 ListBase tmp_data = {NULL, NULL};
2042 size_t tmp_items = 0;
2043
2044 /* only show if mask is used by something... */
2045 if (ID_REAL_USERS(mask) < 1) {
2046 continue;
2047 }
2048
2049 /* add mask animation channels */
2050 BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_MASK(mask)) {
2051 tmp_items += animdata_filter_mask_data(&tmp_data, mask, filter_mode);
2052 }
2053 END_ANIMFILTER_SUBCHANNELS;
2054
2055 /* did we find anything? */
2056 if (tmp_items) {
2057 /* include data-expand widget first */
2058 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2059 /* add mask data-block as channel too (if for drawing, and it has layers) */
2060 ANIMCHANNEL_NEW_CHANNEL(mask, ANIMTYPE_MASKDATABLOCK, NULL, NULL);
2061 }
2062
2063 /* now add the list of collected channels */
2064 BLI_movelisttolist(anim_data, &tmp_data);
2065 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2066 items += tmp_items;
2067 }
2068 }
2069
2070 /* return the number of items added to the list */
2071 return items;
2072 }
2073
2074 /* NOTE: owner_id is scene, material, or texture block,
2075 * which is the direct owner of the node tree in question. */
animdata_filter_ds_nodetree_group(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,ID * owner_id,bNodeTree * ntree,int filter_mode)2076 static size_t animdata_filter_ds_nodetree_group(bAnimContext *ac,
2077 ListBase *anim_data,
2078 bDopeSheet *ads,
2079 ID *owner_id,
2080 bNodeTree *ntree,
2081 int filter_mode)
2082 {
2083 ListBase tmp_data = {NULL, NULL};
2084 size_t tmp_items = 0;
2085 size_t items = 0;
2086
2087 /* add nodetree animation channels */
2088 BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_NTREE_DATA(ntree)) {
2089 /* animation data filtering */
2090 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ntree, filter_mode);
2091 }
2092 END_ANIMFILTER_SUBCHANNELS;
2093
2094 /* did we find anything? */
2095 if (tmp_items) {
2096 /* include data-expand widget first */
2097 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2098 /* check if filtering by active status */
2099 if (ANIMCHANNEL_ACTIVEOK(ntree)) {
2100 ANIMCHANNEL_NEW_CHANNEL(ntree, ANIMTYPE_DSNTREE, owner_id, NULL);
2101 }
2102 }
2103
2104 /* now add the list of collected channels */
2105 BLI_movelisttolist(anim_data, &tmp_data);
2106 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2107 items += tmp_items;
2108 }
2109
2110 /* return the number of items added to the list */
2111 return items;
2112 }
2113
animdata_filter_ds_nodetree(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,ID * owner_id,bNodeTree * ntree,int filter_mode)2114 static size_t animdata_filter_ds_nodetree(bAnimContext *ac,
2115 ListBase *anim_data,
2116 bDopeSheet *ads,
2117 ID *owner_id,
2118 bNodeTree *ntree,
2119 int filter_mode)
2120 {
2121 bNode *node;
2122 size_t items = 0;
2123
2124 items += animdata_filter_ds_nodetree_group(ac, anim_data, ads, owner_id, ntree, filter_mode);
2125
2126 for (node = ntree->nodes.first; node; node = node->next) {
2127 if (node->type == NODE_GROUP) {
2128 if (node->id) {
2129 if ((ads->filterflag & ADS_FILTER_ONLYSEL) && (node->flag & NODE_SELECT) == 0) {
2130 continue;
2131 }
2132 /* Recurse into the node group */
2133 items += animdata_filter_ds_nodetree(ac,
2134 anim_data,
2135 ads,
2136 owner_id,
2137 (bNodeTree *)node->id,
2138 filter_mode | ANIMFILTER_TMP_IGNORE_ONLYSEL);
2139 }
2140 }
2141 }
2142
2143 return items;
2144 }
2145
animdata_filter_ds_linestyle(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Scene * sce,int filter_mode)2146 static size_t animdata_filter_ds_linestyle(
2147 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
2148 {
2149 ViewLayer *view_layer;
2150 FreestyleLineSet *lineset;
2151 size_t items = 0;
2152
2153 for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
2154 for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
2155 if (lineset->linestyle) {
2156 lineset->linestyle->id.tag |= LIB_TAG_DOIT;
2157 }
2158 }
2159 }
2160
2161 for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) {
2162 /* skip render layers without Freestyle enabled */
2163 if ((view_layer->flag & VIEW_LAYER_FREESTYLE) == 0) {
2164 continue;
2165 }
2166
2167 /* loop over linesets defined in the render layer */
2168 for (lineset = view_layer->freestyle_config.linesets.first; lineset; lineset = lineset->next) {
2169 FreestyleLineStyle *linestyle = lineset->linestyle;
2170 ListBase tmp_data = {NULL, NULL};
2171 size_t tmp_items = 0;
2172
2173 if ((linestyle == NULL) || !(linestyle->id.tag & LIB_TAG_DOIT)) {
2174 continue;
2175 }
2176 linestyle->id.tag &= ~LIB_TAG_DOIT;
2177
2178 /* add scene-level animation channels */
2179 BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_LS_SCED(linestyle)) {
2180 /* animation data filtering */
2181 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)linestyle, filter_mode);
2182 }
2183 END_ANIMFILTER_SUBCHANNELS;
2184
2185 /* did we find anything? */
2186 if (tmp_items) {
2187 /* include anim-expand widget first */
2188 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2189 /* check if filtering by active status */
2190 if (ANIMCHANNEL_ACTIVEOK(linestyle)) {
2191 ANIMCHANNEL_NEW_CHANNEL(linestyle, ANIMTYPE_DSLINESTYLE, sce, NULL);
2192 }
2193 }
2194
2195 /* now add the list of collected channels */
2196 BLI_movelisttolist(anim_data, &tmp_data);
2197 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2198 items += tmp_items;
2199 }
2200 }
2201 }
2202
2203 /* return the number of items added to the list */
2204 return items;
2205 }
2206
animdata_filter_ds_texture(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Tex * tex,ID * owner_id,int filter_mode)2207 static size_t animdata_filter_ds_texture(bAnimContext *ac,
2208 ListBase *anim_data,
2209 bDopeSheet *ads,
2210 Tex *tex,
2211 ID *owner_id,
2212 int filter_mode)
2213 {
2214 ListBase tmp_data = {NULL, NULL};
2215 size_t tmp_items = 0;
2216 size_t items = 0;
2217
2218 /* add texture's animation data to temp collection */
2219 BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_TEX_DATA(tex)) {
2220 /* texture animdata */
2221 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)tex, filter_mode);
2222
2223 /* nodes */
2224 if ((tex->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2225 /* owner_id as id instead of texture,
2226 * since it'll otherwise be impossible to track the depth. */
2227
2228 /* FIXME: perhaps as a result, textures should NOT be included under materials,
2229 * but under their own section instead so that free-floating textures can also be animated.
2230 */
2231 tmp_items += animdata_filter_ds_nodetree(
2232 ac, &tmp_data, ads, (ID *)tex, tex->nodetree, filter_mode);
2233 }
2234 }
2235 END_ANIMFILTER_SUBCHANNELS;
2236
2237 /* did we find anything? */
2238 if (tmp_items) {
2239 /* include texture-expand widget? */
2240 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2241 /* check if filtering by active status */
2242 if (ANIMCHANNEL_ACTIVEOK(tex)) {
2243 ANIMCHANNEL_NEW_CHANNEL(tex, ANIMTYPE_DSTEX, owner_id, NULL);
2244 }
2245 }
2246
2247 /* now add the list of collected channels */
2248 BLI_movelisttolist(anim_data, &tmp_data);
2249 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2250 items += tmp_items;
2251 }
2252
2253 /* return the number of items added to the list */
2254 return items;
2255 }
2256
2257 /* NOTE: owner_id is the direct owner of the texture stack in question
2258 * It used to be Material/Light/World before the Blender Internal removal for 2.8
2259 */
animdata_filter_ds_textures(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,ID * owner_id,int filter_mode)2260 static size_t animdata_filter_ds_textures(
2261 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, ID *owner_id, int filter_mode)
2262 {
2263 MTex **mtex = NULL;
2264 size_t items = 0;
2265 int a = 0;
2266
2267 /* get datatype specific data first */
2268 if (owner_id == NULL) {
2269 return 0;
2270 }
2271
2272 switch (GS(owner_id->name)) {
2273 case ID_PA: {
2274 ParticleSettings *part = (ParticleSettings *)owner_id;
2275 mtex = (MTex **)(&part->mtex);
2276 break;
2277 }
2278 default: {
2279 /* invalid/unsupported option */
2280 if (G.debug & G_DEBUG) {
2281 printf("ERROR: Unsupported owner_id (i.e. texture stack) for filter textures - %s\n",
2282 owner_id->name);
2283 }
2284 return 0;
2285 }
2286 }
2287
2288 /* Firstly check that we actually have some textures,
2289 * by gathering all textures in a temp list. */
2290 for (a = 0; a < MAX_MTEX; a++) {
2291 Tex *tex = (mtex[a]) ? mtex[a]->tex : NULL;
2292
2293 /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */
2294 if (tex == NULL) {
2295 continue;
2296 }
2297
2298 /* add texture's anim channels */
2299 items += animdata_filter_ds_texture(ac, anim_data, ads, tex, owner_id, filter_mode);
2300 }
2301
2302 /* return the number of items added to the list */
2303 return items;
2304 }
2305
animdata_filter_ds_material(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Material * ma,int filter_mode)2306 static size_t animdata_filter_ds_material(
2307 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Material *ma, int filter_mode)
2308 {
2309 ListBase tmp_data = {NULL, NULL};
2310 size_t tmp_items = 0;
2311 size_t items = 0;
2312
2313 /* add material's animation data to temp collection */
2314 BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_MAT_OBJD(ma)) {
2315 /* material's animation data */
2316 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ma, filter_mode);
2317
2318 /* nodes */
2319 if ((ma->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2320 tmp_items += animdata_filter_ds_nodetree(
2321 ac, &tmp_data, ads, (ID *)ma, ma->nodetree, filter_mode);
2322 }
2323 }
2324 END_ANIMFILTER_SUBCHANNELS;
2325
2326 /* did we find anything? */
2327 if (tmp_items) {
2328 /* include material-expand widget first */
2329 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2330 /* check if filtering by active status */
2331 if (ANIMCHANNEL_ACTIVEOK(ma)) {
2332 ANIMCHANNEL_NEW_CHANNEL(ma, ANIMTYPE_DSMAT, ma, NULL);
2333 }
2334 }
2335
2336 /* now add the list of collected channels */
2337 BLI_movelisttolist(anim_data, &tmp_data);
2338 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2339 items += tmp_items;
2340 }
2341
2342 return items;
2343 }
2344
animdata_filter_ds_materials(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2345 static size_t animdata_filter_ds_materials(
2346 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2347 {
2348 size_t items = 0;
2349 int a = 0;
2350
2351 /* First pass: take the materials referenced via the Material slots of the object. */
2352 for (a = 1; a <= ob->totcol; a++) {
2353 Material *ma = BKE_object_material_get(ob, a);
2354
2355 /* if material is valid, try to add relevant contents from here */
2356 if (ma) {
2357 /* add channels */
2358 items += animdata_filter_ds_material(ac, anim_data, ads, ma, filter_mode);
2359 }
2360 }
2361
2362 /* return the number of items added to the list */
2363 return items;
2364 }
2365
2366 /* ............ */
2367
2368 /* Temporary context for modifier linked-data channel extraction */
2369 typedef struct tAnimFilterModifiersContext {
2370 bAnimContext *ac; /* anim editor context */
2371 bDopeSheet *ads; /* dopesheet filtering settings */
2372
2373 ListBase tmp_data; /* list of channels created (but not yet added to the main list) */
2374 size_t items; /* number of channels created */
2375
2376 int filter_mode; /* flags for stuff we want to filter */
2377 } tAnimFilterModifiersContext;
2378
2379 /* dependency walker callback for modifier dependencies */
animfilter_modifier_idpoin_cb(void * afm_ptr,Object * ob,ID ** idpoin,int UNUSED (cb_flag))2380 static void animfilter_modifier_idpoin_cb(void *afm_ptr,
2381 Object *ob,
2382 ID **idpoin,
2383 int UNUSED(cb_flag))
2384 {
2385 tAnimFilterModifiersContext *afm = (tAnimFilterModifiersContext *)afm_ptr;
2386 ID *owner_id = &ob->id;
2387 ID *id = *idpoin;
2388
2389 /* NOTE: the walker only guarantees to give us all the ID-ptr *slots*,
2390 * not just the ones which are actually used, so be careful!
2391 */
2392 if (id == NULL) {
2393 return;
2394 }
2395
2396 /* check if this is something we're interested in... */
2397 switch (GS(id->name)) {
2398 case ID_TE: /* Textures */
2399 {
2400 Tex *tex = (Tex *)id;
2401 if (!(afm->ads->filterflag & ADS_FILTER_NOTEX)) {
2402 afm->items += animdata_filter_ds_texture(
2403 afm->ac, &afm->tmp_data, afm->ads, tex, owner_id, afm->filter_mode);
2404 }
2405 break;
2406 }
2407
2408 /* TODO: images? */
2409 default:
2410 break;
2411 }
2412 }
2413
2414 /* animation linked to data used by modifiers
2415 * NOTE: strictly speaking, modifier animation is already included under Object level
2416 * but for some modifiers (e.g. Displace), there can be linked data that has settings
2417 * which would be nice to animate (i.e. texture parameters) but which are not actually
2418 * attached to any other objects/materials/etc. in the scene
2419 */
2420 /* TODO: do we want an expander for this? */
animdata_filter_ds_modifiers(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2421 static size_t animdata_filter_ds_modifiers(
2422 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2423 {
2424 tAnimFilterModifiersContext afm = {NULL};
2425 size_t items = 0;
2426
2427 /* 1) create a temporary "context" containing all the info we have here to pass to the callback
2428 * use to walk through the dependencies of the modifiers
2429 *
2430 * Assumes that all other unspecified values (i.e. accumulation buffers)
2431 * are zero'd out properly!
2432 */
2433 afm.ac = ac;
2434 afm.ads = ads;
2435 afm.filter_mode = filter_mode;
2436
2437 /* 2) walk over dependencies */
2438 BKE_modifiers_foreach_ID_link(ob, animfilter_modifier_idpoin_cb, &afm);
2439
2440 /* 3) extract data from the context, merging it back into the standard list */
2441 if (afm.items) {
2442 /* now add the list of collected channels */
2443 BLI_movelisttolist(anim_data, &afm.tmp_data);
2444 BLI_assert(BLI_listbase_is_empty(&afm.tmp_data));
2445 items += afm.items;
2446 }
2447
2448 return items;
2449 }
2450
2451 /* ............ */
2452
animdata_filter_ds_particles(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2453 static size_t animdata_filter_ds_particles(
2454 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2455 {
2456 ParticleSystem *psys;
2457 size_t items = 0;
2458
2459 for (psys = ob->particlesystem.first; psys; psys = psys->next) {
2460 ListBase tmp_data = {NULL, NULL};
2461 size_t tmp_items = 0;
2462
2463 /* Note that when psys->part->adt is NULL the textures can still be
2464 * animated. */
2465 if (psys->part == NULL) {
2466 continue;
2467 }
2468
2469 /* add particle-system's animation data to temp collection */
2470 BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_PART_OBJD(psys->part)) {
2471 /* particle system's animation data */
2472 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)psys->part, filter_mode);
2473
2474 /* textures */
2475 if (!(ads->filterflag & ADS_FILTER_NOTEX)) {
2476 tmp_items += animdata_filter_ds_textures(
2477 ac, &tmp_data, ads, (ID *)psys->part, filter_mode);
2478 }
2479 }
2480 END_ANIMFILTER_SUBCHANNELS;
2481
2482 /* did we find anything? */
2483 if (tmp_items) {
2484 /* include particle-expand widget first */
2485 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2486 /* check if filtering by active status */
2487 if (ANIMCHANNEL_ACTIVEOK(psys->part)) {
2488 ANIMCHANNEL_NEW_CHANNEL(psys->part, ANIMTYPE_DSPART, psys->part, NULL);
2489 }
2490 }
2491
2492 /* now add the list of collected channels */
2493 BLI_movelisttolist(anim_data, &tmp_data);
2494 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2495 items += tmp_items;
2496 }
2497 }
2498
2499 /* return the number of items added to the list */
2500 return items;
2501 }
2502
animdata_filter_ds_obdata(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2503 static size_t animdata_filter_ds_obdata(
2504 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2505 {
2506 ListBase tmp_data = {NULL, NULL};
2507 size_t tmp_items = 0;
2508 size_t items = 0;
2509
2510 IdAdtTemplate *iat = ob->data;
2511 short type = 0, expanded = 0;
2512
2513 /* get settings based on data type */
2514 switch (ob->type) {
2515 case OB_CAMERA: /* ------- Camera ------------ */
2516 {
2517 Camera *ca = (Camera *)ob->data;
2518
2519 if (ads->filterflag & ADS_FILTER_NOCAM) {
2520 return 0;
2521 }
2522
2523 type = ANIMTYPE_DSCAM;
2524 expanded = FILTER_CAM_OBJD(ca);
2525 break;
2526 }
2527 case OB_LAMP: /* ---------- Light ----------- */
2528 {
2529 Light *la = (Light *)ob->data;
2530
2531 if (ads->filterflag & ADS_FILTER_NOLAM) {
2532 return 0;
2533 }
2534
2535 type = ANIMTYPE_DSLAM;
2536 expanded = FILTER_LAM_OBJD(la);
2537 break;
2538 }
2539 case OB_CURVE: /* ------- Curve ---------- */
2540 case OB_SURF: /* ------- Nurbs Surface ---------- */
2541 case OB_FONT: /* ------- Text Curve ---------- */
2542 {
2543 Curve *cu = (Curve *)ob->data;
2544
2545 if (ads->filterflag & ADS_FILTER_NOCUR) {
2546 return 0;
2547 }
2548
2549 type = ANIMTYPE_DSCUR;
2550 expanded = FILTER_CUR_OBJD(cu);
2551 break;
2552 }
2553 case OB_MBALL: /* ------- MetaBall ---------- */
2554 {
2555 MetaBall *mb = (MetaBall *)ob->data;
2556
2557 if (ads->filterflag & ADS_FILTER_NOMBA) {
2558 return 0;
2559 }
2560
2561 type = ANIMTYPE_DSMBALL;
2562 expanded = FILTER_MBALL_OBJD(mb);
2563 break;
2564 }
2565 case OB_ARMATURE: /* ------- Armature ---------- */
2566 {
2567 bArmature *arm = (bArmature *)ob->data;
2568
2569 if (ads->filterflag & ADS_FILTER_NOARM) {
2570 return 0;
2571 }
2572
2573 type = ANIMTYPE_DSARM;
2574 expanded = FILTER_ARM_OBJD(arm);
2575 break;
2576 }
2577 case OB_MESH: /* ------- Mesh ---------- */
2578 {
2579 Mesh *me = (Mesh *)ob->data;
2580
2581 if (ads->filterflag & ADS_FILTER_NOMESH) {
2582 return 0;
2583 }
2584
2585 type = ANIMTYPE_DSMESH;
2586 expanded = FILTER_MESH_OBJD(me);
2587 break;
2588 }
2589 case OB_LATTICE: /* ---- Lattice ---- */
2590 {
2591 Lattice *lt = (Lattice *)ob->data;
2592
2593 if (ads->filterflag & ADS_FILTER_NOLAT) {
2594 return 0;
2595 }
2596
2597 type = ANIMTYPE_DSLAT;
2598 expanded = FILTER_LATTICE_OBJD(lt);
2599 break;
2600 }
2601 case OB_SPEAKER: /* ---------- Speaker ----------- */
2602 {
2603 Speaker *spk = (Speaker *)ob->data;
2604
2605 type = ANIMTYPE_DSSPK;
2606 expanded = FILTER_SPK_OBJD(spk);
2607 break;
2608 }
2609 case OB_HAIR: /* ---------- Hair ----------- */
2610 {
2611 Hair *hair = (Hair *)ob->data;
2612
2613 if (ads->filterflag2 & ADS_FILTER_NOHAIR) {
2614 return 0;
2615 }
2616
2617 type = ANIMTYPE_DSHAIR;
2618 expanded = FILTER_HAIR_OBJD(hair);
2619 break;
2620 }
2621 case OB_POINTCLOUD: /* ---------- PointCloud ----------- */
2622 {
2623 PointCloud *pointcloud = (PointCloud *)ob->data;
2624
2625 if (ads->filterflag2 & ADS_FILTER_NOPOINTCLOUD) {
2626 return 0;
2627 }
2628
2629 type = ANIMTYPE_DSPOINTCLOUD;
2630 expanded = FILTER_POINTS_OBJD(pointcloud);
2631 break;
2632 }
2633 case OB_VOLUME: /* ---------- Volume ----------- */
2634 {
2635 Volume *volume = (Volume *)ob->data;
2636
2637 if (ads->filterflag2 & ADS_FILTER_NOVOLUME) {
2638 return 0;
2639 }
2640
2641 type = ANIMTYPE_DSVOLUME;
2642 expanded = FILTER_VOLUME_OBJD(volume);
2643 break;
2644 }
2645 }
2646
2647 /* add object data animation channels */
2648 BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
2649 /* animation data filtering */
2650 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)iat, filter_mode);
2651
2652 /* sub-data filtering... */
2653 switch (ob->type) {
2654 case OB_LAMP: /* light - textures + nodetree */
2655 {
2656 Light *la = ob->data;
2657 bNodeTree *ntree = la->nodetree;
2658
2659 /* nodetree */
2660 if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2661 tmp_items += animdata_filter_ds_nodetree(
2662 ac, &tmp_data, ads, &la->id, ntree, filter_mode);
2663 }
2664 break;
2665 }
2666 }
2667 }
2668 END_ANIMFILTER_SUBCHANNELS;
2669
2670 /* did we find anything? */
2671 if (tmp_items) {
2672 /* include data-expand widget first */
2673 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2674 /* check if filtering by active status */
2675 if (ANIMCHANNEL_ACTIVEOK(iat)) {
2676 ANIMCHANNEL_NEW_CHANNEL(iat, type, iat, NULL);
2677 }
2678 }
2679
2680 /* now add the list of collected channels */
2681 BLI_movelisttolist(anim_data, &tmp_data);
2682 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2683 items += tmp_items;
2684 }
2685
2686 /* return the number of items added to the list */
2687 return items;
2688 }
2689
2690 /* shapekey-level animation */
animdata_filter_ds_keyanim(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,Key * key,int filter_mode)2691 static size_t animdata_filter_ds_keyanim(
2692 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, Key *key, int filter_mode)
2693 {
2694 ListBase tmp_data = {NULL, NULL};
2695 size_t tmp_items = 0;
2696 size_t items = 0;
2697
2698 /* add shapekey-level animation channels */
2699 BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_SKE_OBJD(key)) {
2700 /* animation data filtering */
2701 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)key, filter_mode);
2702 }
2703 END_ANIMFILTER_SUBCHANNELS;
2704
2705 /* did we find anything? */
2706 if (tmp_items) {
2707 /* include key-expand widget first */
2708 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2709 if (ANIMCHANNEL_ACTIVEOK(key)) {
2710 ANIMCHANNEL_NEW_CHANNEL(key, ANIMTYPE_DSSKEY, ob, NULL);
2711 }
2712 }
2713
2714 /* now add the list of collected channels */
2715 BLI_movelisttolist(anim_data, &tmp_data);
2716 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2717 items += tmp_items;
2718 }
2719
2720 /* return the number of items added to the list */
2721 return items;
2722 }
2723
2724 /* object-level animation */
animdata_filter_ds_obanim(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Object * ob,int filter_mode)2725 static size_t animdata_filter_ds_obanim(
2726 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Object *ob, int filter_mode)
2727 {
2728 ListBase tmp_data = {NULL, NULL};
2729 size_t tmp_items = 0;
2730 size_t items = 0;
2731
2732 AnimData *adt = ob->adt;
2733 short type = 0, expanded = 1;
2734 void *cdata = NULL;
2735
2736 /* determine the type of expander channels to use */
2737 /* this is the best way to do this for now... */
2738 ANIMDATA_FILTER_CASES(
2739 ob, /* Some useless long comment to prevent wrapping by old clang-format versions... */
2740 {/* AnimData - no channel, but consider data */},
2741 {/* NLA - no channel, but consider data */},
2742 { /* Drivers */
2743 type = ANIMTYPE_FILLDRIVERS;
2744 cdata = adt;
2745 expanded = EXPANDED_DRVD(adt);
2746 },
2747 {/* NLA Strip Controls - no dedicated channel for now (XXX) */},
2748 { /* Keyframes */
2749 type = ANIMTYPE_FILLACTD;
2750 cdata = adt->action;
2751 expanded = EXPANDED_ACTC(adt->action);
2752 });
2753
2754 /* add object-level animation channels */
2755 BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
2756 /* animation data filtering */
2757 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)ob, filter_mode);
2758 }
2759 END_ANIMFILTER_SUBCHANNELS;
2760
2761 /* did we find anything? */
2762 if (tmp_items) {
2763 /* include anim-expand widget first */
2764 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2765 if (type != ANIMTYPE_NONE) {
2766 /* NOTE: active-status (and the associated checks) don't apply here... */
2767 ANIMCHANNEL_NEW_CHANNEL(cdata, type, ob, NULL);
2768 }
2769 }
2770
2771 /* now add the list of collected channels */
2772 BLI_movelisttolist(anim_data, &tmp_data);
2773 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2774 items += tmp_items;
2775 }
2776
2777 /* return the number of items added to the list */
2778 return items;
2779 }
2780
2781 /* get animation channels from object2 */
animdata_filter_dopesheet_ob(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Base * base,int filter_mode)2782 static size_t animdata_filter_dopesheet_ob(
2783 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Base *base, int filter_mode)
2784 {
2785 ListBase tmp_data = {NULL, NULL};
2786 Object *ob = base->object;
2787 size_t tmp_items = 0;
2788 size_t items = 0;
2789
2790 /* filter data contained under object first */
2791 BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_OBJC(ob)) {
2792 Key *key = BKE_key_from_object(ob);
2793
2794 /* object-level animation */
2795 if ((ob->adt) && !(ads->filterflag & ADS_FILTER_NOOBJ)) {
2796 tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ads, ob, filter_mode);
2797 }
2798
2799 /* particle deflector textures */
2800 if (ob->pd != NULL && ob->pd->tex != NULL && !(ads->filterflag & ADS_FILTER_NOTEX)) {
2801 tmp_items += animdata_filter_ds_texture(
2802 ac, &tmp_data, ads, ob->pd->tex, &ob->id, filter_mode);
2803 }
2804
2805 /* shape-key */
2806 if ((key && key->adt) && !(ads->filterflag & ADS_FILTER_NOSHAPEKEYS)) {
2807 tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ads, ob, key, filter_mode);
2808 }
2809
2810 /* modifiers */
2811 if ((ob->modifiers.first) && !(ads->filterflag & ADS_FILTER_NOMODIFIERS)) {
2812 tmp_items += animdata_filter_ds_modifiers(ac, &tmp_data, ads, ob, filter_mode);
2813 }
2814
2815 /* materials */
2816 if ((ob->totcol) && !(ads->filterflag & ADS_FILTER_NOMAT)) {
2817 tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ads, ob, filter_mode);
2818 }
2819
2820 /* object data */
2821 if (ob->data) {
2822 tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ads, ob, filter_mode);
2823 }
2824
2825 /* particles */
2826 if ((ob->particlesystem.first) && !(ads->filterflag & ADS_FILTER_NOPART)) {
2827 tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ads, ob, filter_mode);
2828 }
2829
2830 /* grease pencil */
2831 if ((ob->type == OB_GPENCIL) && (ob->data) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
2832 tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, ob->data, filter_mode);
2833 }
2834 }
2835 END_ANIMFILTER_SUBCHANNELS;
2836
2837 /* if we collected some channels, add these to the new list... */
2838 if (tmp_items) {
2839 /* firstly add object expander if required */
2840 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2841 /* check if filtering by selection */
2842 /* XXX: double-check on this -
2843 * most of the time, a lot of tools need to filter out these channels! */
2844 if (ANIMCHANNEL_SELOK((base->flag & BASE_SELECTED))) {
2845 /* check if filtering by active status */
2846 if (ANIMCHANNEL_ACTIVEOK(ob)) {
2847 ANIMCHANNEL_NEW_CHANNEL(base, ANIMTYPE_OBJECT, ob, NULL);
2848 }
2849 }
2850 }
2851
2852 /* now add the list of collected channels */
2853 BLI_movelisttolist(anim_data, &tmp_data);
2854 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2855 items += tmp_items;
2856 }
2857
2858 /* return the number of items added */
2859 return items;
2860 }
2861
animdata_filter_ds_world(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Scene * sce,World * wo,int filter_mode)2862 static size_t animdata_filter_ds_world(
2863 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, World *wo, int filter_mode)
2864 {
2865 ListBase tmp_data = {NULL, NULL};
2866 size_t tmp_items = 0;
2867 size_t items = 0;
2868
2869 /* add world animation channels */
2870 BEGIN_ANIMFILTER_SUBCHANNELS (FILTER_WOR_SCED(wo)) {
2871 /* animation data filtering */
2872 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)wo, filter_mode);
2873
2874 /* nodes */
2875 if ((wo->nodetree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2876 tmp_items += animdata_filter_ds_nodetree(
2877 ac, &tmp_data, ads, (ID *)wo, wo->nodetree, filter_mode);
2878 }
2879 }
2880 END_ANIMFILTER_SUBCHANNELS;
2881
2882 /* did we find anything? */
2883 if (tmp_items) {
2884 /* include data-expand widget first */
2885 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2886 /* check if filtering by active status */
2887 if (ANIMCHANNEL_ACTIVEOK(wo)) {
2888 ANIMCHANNEL_NEW_CHANNEL(wo, ANIMTYPE_DSWOR, sce, NULL);
2889 }
2890 }
2891
2892 /* now add the list of collected channels */
2893 BLI_movelisttolist(anim_data, &tmp_data);
2894 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2895 items += tmp_items;
2896 }
2897
2898 /* return the number of items added to the list */
2899 return items;
2900 }
2901
animdata_filter_ds_scene(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Scene * sce,int filter_mode)2902 static size_t animdata_filter_ds_scene(
2903 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
2904 {
2905 ListBase tmp_data = {NULL, NULL};
2906 size_t tmp_items = 0;
2907 size_t items = 0;
2908
2909 AnimData *adt = sce->adt;
2910 short type = 0, expanded = 1;
2911 void *cdata = NULL;
2912
2913 /* determine the type of expander channels to use */
2914 /* this is the best way to do this for now... */
2915 ANIMDATA_FILTER_CASES(
2916 sce, /* Some useless long comment to prevent wrapping by old clang-format versions... */
2917 {/* AnimData - no channel, but consider data */},
2918 {/* NLA - no channel, but consider data */},
2919 { /* Drivers */
2920 type = ANIMTYPE_FILLDRIVERS;
2921 cdata = adt;
2922 expanded = EXPANDED_DRVD(adt);
2923 },
2924 {/* NLA Strip Controls - no dedicated channel for now (XXX) */},
2925 { /* Keyframes */
2926 type = ANIMTYPE_FILLACTD;
2927 cdata = adt->action;
2928 expanded = EXPANDED_ACTC(adt->action);
2929 });
2930
2931 /* add scene-level animation channels */
2932 BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
2933 /* animation data filtering */
2934 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)sce, filter_mode);
2935 }
2936 END_ANIMFILTER_SUBCHANNELS;
2937
2938 /* did we find anything? */
2939 if (tmp_items) {
2940 /* include anim-expand widget first */
2941 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2942 if (type != ANIMTYPE_NONE) {
2943 /* NOTE: active-status (and the associated checks) don't apply here... */
2944 ANIMCHANNEL_NEW_CHANNEL(cdata, type, sce, NULL);
2945 }
2946 }
2947
2948 /* now add the list of collected channels */
2949 BLI_movelisttolist(anim_data, &tmp_data);
2950 BLI_assert(BLI_listbase_is_empty(&tmp_data));
2951 items += tmp_items;
2952 }
2953
2954 /* return the number of items added to the list */
2955 return items;
2956 }
2957
animdata_filter_dopesheet_scene(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,Scene * sce,int filter_mode)2958 static size_t animdata_filter_dopesheet_scene(
2959 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, Scene *sce, int filter_mode)
2960 {
2961 ListBase tmp_data = {NULL, NULL};
2962 size_t tmp_items = 0;
2963 size_t items = 0;
2964
2965 /* filter data contained under object first */
2966 BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_SCEC(sce)) {
2967 bNodeTree *ntree = sce->nodetree;
2968 bGPdata *gpd = sce->gpd;
2969 World *wo = sce->world;
2970
2971 /* Action, Drivers, or NLA for Scene */
2972 if ((ads->filterflag & ADS_FILTER_NOSCE) == 0) {
2973 tmp_items += animdata_filter_ds_scene(ac, &tmp_data, ads, sce, filter_mode);
2974 }
2975
2976 /* world */
2977 if ((wo) && !(ads->filterflag & ADS_FILTER_NOWOR)) {
2978 tmp_items += animdata_filter_ds_world(ac, &tmp_data, ads, sce, wo, filter_mode);
2979 }
2980
2981 /* nodetree */
2982 if ((ntree) && !(ads->filterflag & ADS_FILTER_NONTREE)) {
2983 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, ads, (ID *)sce, ntree, filter_mode);
2984 }
2985
2986 /* line styles */
2987 if ((ads->filterflag & ADS_FILTER_NOLINESTYLE) == 0) {
2988 tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, ads, sce, filter_mode);
2989 }
2990
2991 /* grease pencil */
2992 if ((gpd) && !(ads->filterflag & ADS_FILTER_NOGPENCIL)) {
2993 tmp_items += animdata_filter_ds_gpencil(ac, &tmp_data, ads, gpd, filter_mode);
2994 }
2995
2996 /* TODO: one day, when sequencer becomes its own datatype,
2997 * perhaps it should be included here. */
2998 }
2999 END_ANIMFILTER_SUBCHANNELS;
3000
3001 /* if we collected some channels, add these to the new list... */
3002 if (tmp_items) {
3003 /* firstly add object expander if required */
3004 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3005 /* check if filtering by selection */
3006 if (ANIMCHANNEL_SELOK((sce->flag & SCE_DS_SELECTED))) {
3007 /* NOTE: active-status doesn't matter for this! */
3008 ANIMCHANNEL_NEW_CHANNEL(sce, ANIMTYPE_SCENE, sce, NULL);
3009 }
3010 }
3011
3012 /* now add the list of collected channels */
3013 BLI_movelisttolist(anim_data, &tmp_data);
3014 BLI_assert(BLI_listbase_is_empty(&tmp_data));
3015 items += tmp_items;
3016 }
3017
3018 /* return the number of items added */
3019 return items;
3020 }
3021
animdata_filter_ds_movieclip(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,MovieClip * clip,int filter_mode)3022 static size_t animdata_filter_ds_movieclip(
3023 bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, MovieClip *clip, int filter_mode)
3024 {
3025 ListBase tmp_data = {NULL, NULL};
3026 size_t tmp_items = 0;
3027 size_t items = 0;
3028 /* add world animation channels */
3029 BEGIN_ANIMFILTER_SUBCHANNELS (EXPANDED_MCLIP(clip)) {
3030 /* animation data filtering */
3031 tmp_items += animfilter_block_data(ac, &tmp_data, ads, (ID *)clip, filter_mode);
3032 }
3033 END_ANIMFILTER_SUBCHANNELS;
3034 /* did we find anything? */
3035 if (tmp_items) {
3036 /* include data-expand widget first */
3037 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3038 /* check if filtering by active status */
3039 if (ANIMCHANNEL_ACTIVEOK(clip)) {
3040 ANIMCHANNEL_NEW_CHANNEL(clip, ANIMTYPE_DSMCLIP, clip, NULL);
3041 }
3042 }
3043 /* now add the list of collected channels */
3044 BLI_movelisttolist(anim_data, &tmp_data);
3045 BLI_assert(BLI_listbase_is_empty(&tmp_data));
3046 items += tmp_items;
3047 }
3048 /* return the number of items added to the list */
3049 return items;
3050 }
3051
animdata_filter_dopesheet_movieclips(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,int filter_mode)3052 static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac,
3053 ListBase *anim_data,
3054 bDopeSheet *ads,
3055 int filter_mode)
3056 {
3057 size_t items = 0;
3058 MovieClip *clip;
3059 for (clip = ac->bmain->movieclips.first; clip != NULL; clip = clip->id.next) {
3060 /* only show if gpd is used by something... */
3061 if (ID_REAL_USERS(clip) < 1) {
3062 continue;
3063 }
3064 items += animdata_filter_ds_movieclip(ac, anim_data, ads, clip, filter_mode);
3065 }
3066 /* return the number of items added to the list */
3067 return items;
3068 }
3069
3070 /* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */
animdata_filter_base_is_ok(bDopeSheet * ads,Base * base,int filter_mode)3071 static bool animdata_filter_base_is_ok(bDopeSheet *ads, Base *base, int filter_mode)
3072 {
3073 Object *ob = base->object;
3074
3075 if (base->object == NULL) {
3076 return false;
3077 }
3078
3079 /* firstly, check if object can be included, by the following factors:
3080 * - if only visible, must check for layer and also viewport visibility
3081 * --> while tools may demand only visible, user setting takes priority
3082 * as user option controls whether sets of channels get included while
3083 * tool-flag takes into account collapsed/open channels too
3084 * - if only selected, must check if object is selected
3085 * - there must be animation data to edit (this is done recursively as we
3086 * try to add the channels)
3087 */
3088 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
3089 /* layer visibility - we check both object and base, since these may not be in sync yet */
3090 if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0 || (base->flag & BASE_VISIBLE_VIEWLAYER) == 0) {
3091 return false;
3092 }
3093
3094 /* outliner restrict-flag */
3095 if (ob->restrictflag & OB_RESTRICT_VIEWPORT) {
3096 return false;
3097 }
3098 }
3099
3100 /* if only F-Curves with visible flags set can be shown, check that
3101 * data-block hasn't been set to invisible.
3102 */
3103 if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
3104 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) {
3105 return false;
3106 }
3107 }
3108
3109 /* Pinned curves are visible regardless of selection flags. */
3110 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
3111 return true;
3112 }
3113
3114 /* Special case.
3115 * We don't do recursive checks for pin, but we need to deal with tricky
3116 * setup like animated camera lens without animated camera location.
3117 * Without such special handle here we wouldn't be able to bin such
3118 * camera data only animation to the editor.
3119 */
3120 if (ob->adt == NULL && ob->data != NULL) {
3121 AnimData *data_adt = BKE_animdata_from_id(ob->data);
3122 if (data_adt != NULL && (data_adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
3123 return true;
3124 }
3125 }
3126
3127 /* check selection and object type filters */
3128 if ((ads->filterflag & ADS_FILTER_ONLYSEL) &&
3129 !((base->flag & BASE_SELECTED) /*|| (base == sce->basact)*/)) {
3130 /* only selected should be shown */
3131 return false;
3132 }
3133
3134 /* check if object belongs to the filtering group if option to filter
3135 * objects by the grouped status is on
3136 * - used to ease the process of doing multiple-character choreographies
3137 */
3138 if (ads->filter_grp != NULL) {
3139 if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) {
3140 return false;
3141 }
3142 }
3143
3144 /* no reason to exclude this object... */
3145 return true;
3146 }
3147
3148 /* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */
ds_base_sorting_cmp(const void * base1_ptr,const void * base2_ptr)3149 static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr)
3150 {
3151 const Base *b1 = *((const Base **)base1_ptr);
3152 const Base *b2 = *((const Base **)base2_ptr);
3153
3154 return strcmp(b1->object->id.name + 2, b2->object->id.name + 2);
3155 }
3156
3157 /* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */
animdata_filter_ds_sorted_bases(bDopeSheet * ads,ViewLayer * view_layer,int filter_mode,size_t * r_usable_bases)3158 static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads,
3159 ViewLayer *view_layer,
3160 int filter_mode,
3161 size_t *r_usable_bases)
3162 {
3163 /* Create an array with space for all the bases, but only containing the usable ones */
3164 size_t tot_bases = BLI_listbase_count(&view_layer->object_bases);
3165 size_t num_bases = 0;
3166
3167 Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases");
3168 LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
3169 if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
3170 sorted_bases[num_bases++] = base;
3171 }
3172 }
3173
3174 /* Sort this list of pointers (based on the names) */
3175 qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp);
3176
3177 /* Return list of sorted bases */
3178 *r_usable_bases = num_bases;
3179 return sorted_bases;
3180 }
3181
3182 /* TODO: implement pinning...
3183 * (if and when pinning is done, what we need to do is to provide freeing mechanisms -
3184 * to protect against data that was deleted). */
animdata_filter_dopesheet(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,int filter_mode)3185 static size_t animdata_filter_dopesheet(bAnimContext *ac,
3186 ListBase *anim_data,
3187 bDopeSheet *ads,
3188 int filter_mode)
3189 {
3190 Scene *scene = (Scene *)ads->source;
3191 ViewLayer *view_layer = (ViewLayer *)ac->view_layer;
3192 size_t items = 0;
3193
3194 /* check that we do indeed have a scene */
3195 if ((ads->source == NULL) || (GS(ads->source->name) != ID_SCE)) {
3196 printf("Dope Sheet Error: No scene!\n");
3197 if (G.debug & G_DEBUG) {
3198 printf("\tPointer = %p, Name = '%s'\n",
3199 (void *)ads->source,
3200 (ads->source) ? ads->source->name : NULL);
3201 }
3202 return 0;
3203 }
3204
3205 /* augment the filter-flags with settings based on the dopesheet filterflags
3206 * so that some temp settings can get added automagically...
3207 */
3208 if (ads->filterflag & ADS_FILTER_SELEDIT) {
3209 /* only selected F-Curves should get their keyframes considered for editability */
3210 filter_mode |= ANIMFILTER_SELEDIT;
3211 }
3212
3213 /* Cache files level animations (frame duration and such). */
3214 if (!(ads->filterflag2 & ADS_FILTER_NOCACHEFILES) && !(ads->filterflag & ADS_FILTER_ONLYSEL)) {
3215 CacheFile *cache_file = ac->bmain->cachefiles.first;
3216 for (; cache_file; cache_file = cache_file->id.next) {
3217 items += animdata_filter_ds_cachefile(ac, anim_data, ads, cache_file, filter_mode);
3218 }
3219 }
3220
3221 /* movie clip's animation */
3222 if (!(ads->filterflag2 & ADS_FILTER_NOMOVIECLIPS) && !(ads->filterflag & ADS_FILTER_ONLYSEL)) {
3223 items += animdata_filter_dopesheet_movieclips(ac, anim_data, ads, filter_mode);
3224 }
3225
3226 /* Scene-linked animation - e.g. world, compositing nodes, scene anim
3227 * (including sequencer currently). */
3228 items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode);
3229
3230 /* If filtering for channel drawing, we want the objects in alphabetical order,
3231 * to make it easier to predict where items are in the hierarchy
3232 * - This order only really matters
3233 * if we need to show all channels in the list (e.g. for drawing).
3234 * (XXX: What about lingering "active" flags? The order may now become unpredictable)
3235 * - Don't do this if this behavior has been turned off (i.e. due to it being too slow)
3236 * - Don't do this if there's just a single object
3237 */
3238 if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) &&
3239 (view_layer->object_bases.first != view_layer->object_bases.last)) {
3240 /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */
3241 /* TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort... */
3242 Base **sorted_bases;
3243 size_t num_bases;
3244
3245 sorted_bases = animdata_filter_ds_sorted_bases(ads, view_layer, filter_mode, &num_bases);
3246 if (sorted_bases) {
3247 /* Add the necessary channels for these bases... */
3248 for (size_t i = 0; i < num_bases; i++) {
3249 items += animdata_filter_dopesheet_ob(ac, anim_data, ads, sorted_bases[i], filter_mode);
3250 }
3251
3252 /* TODO: store something to validate whether any changes are needed? */
3253
3254 /* free temporary data */
3255 MEM_freeN(sorted_bases);
3256 }
3257 }
3258 else {
3259 /* Filter and add contents of each base (i.e. object) without them sorting first
3260 * NOTE: This saves performance in cases where order doesn't matter
3261 */
3262 LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
3263 if (animdata_filter_base_is_ok(ads, base, filter_mode)) {
3264 /* since we're still here, this object should be usable */
3265 items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode);
3266 }
3267 }
3268 }
3269
3270 /* return the number of items in the list */
3271 return items;
3272 }
3273
3274 /* Summary track for DopeSheet/Action Editor
3275 * - return code is whether the summary lets the other channels get drawn
3276 */
animdata_filter_dopesheet_summary(bAnimContext * ac,ListBase * anim_data,int filter_mode,size_t * items)3277 static short animdata_filter_dopesheet_summary(bAnimContext *ac,
3278 ListBase *anim_data,
3279 int filter_mode,
3280 size_t *items)
3281 {
3282 bDopeSheet *ads = NULL;
3283
3284 /* get the DopeSheet information to use
3285 * - we should only need to deal with the DopeSheet/Action Editor,
3286 * since all the other Animation Editors won't have this concept
3287 * being applicable.
3288 */
3289 if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) {
3290 SpaceAction *saction = (SpaceAction *)ac->sl;
3291 ads = &saction->ads;
3292 }
3293 else {
3294 /* invalid space type - skip this summary channels */
3295 return 1;
3296 }
3297
3298 /* dopesheet summary
3299 * - only for drawing and/or selecting keyframes in channels, but not for real editing
3300 * - only useful for DopeSheet/Action/etc. editors where it is actually useful
3301 */
3302 if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ads->filterflag & ADS_FILTER_SUMMARY)) {
3303 bAnimListElem *ale = make_new_animlistelem(ac, ANIMTYPE_SUMMARY, NULL, NULL);
3304 if (ale) {
3305 BLI_addtail(anim_data, ale);
3306 (*items)++;
3307 }
3308
3309 /* If summary is collapsed, don't show other channels beneath this - this check is put inside
3310 * the summary check so that it doesn't interfere with normal operation.
3311 */
3312 if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED) {
3313 return 0;
3314 }
3315 }
3316
3317 /* the other channels beneath this can be shown */
3318 return 1;
3319 }
3320
3321 /* ......................... */
3322
3323 /* filter data associated with a channel - usually for handling summary-channels in DopeSheet */
animdata_filter_animchan(bAnimContext * ac,ListBase * anim_data,bDopeSheet * ads,bAnimListElem * channel,int filter_mode)3324 static size_t animdata_filter_animchan(bAnimContext *ac,
3325 ListBase *anim_data,
3326 bDopeSheet *ads,
3327 bAnimListElem *channel,
3328 int filter_mode)
3329 {
3330 size_t items = 0;
3331
3332 /* data to filter depends on channel type */
3333 /* NOTE: only common channel-types have been handled for now. More can be added as necessary */
3334 switch (channel->type) {
3335 case ANIMTYPE_SUMMARY:
3336 items += animdata_filter_dopesheet(ac, anim_data, ads, filter_mode);
3337 break;
3338
3339 case ANIMTYPE_SCENE:
3340 items += animdata_filter_dopesheet_scene(ac, anim_data, ads, channel->data, filter_mode);
3341 break;
3342
3343 case ANIMTYPE_OBJECT:
3344 items += animdata_filter_dopesheet_ob(ac, anim_data, ads, channel->data, filter_mode);
3345 break;
3346
3347 case ANIMTYPE_DSCACHEFILE:
3348 items += animdata_filter_ds_cachefile(ac, anim_data, ads, channel->data, filter_mode);
3349 break;
3350
3351 case ANIMTYPE_ANIMDATA:
3352 items += animfilter_block_data(ac, anim_data, ads, channel->id, filter_mode);
3353 break;
3354
3355 default:
3356 printf("ERROR: Unsupported channel type (%d) in animdata_filter_animchan()\n",
3357 channel->type);
3358 break;
3359 }
3360
3361 return items;
3362 }
3363
3364 /* ----------- Cleanup API --------------- */
3365
3366 /* Remove entries with invalid types in animation channel list */
animdata_filter_remove_invalid(ListBase * anim_data)3367 static size_t animdata_filter_remove_invalid(ListBase *anim_data)
3368 {
3369 bAnimListElem *ale, *next;
3370 size_t items = 0;
3371
3372 /* only keep entries with valid types */
3373 for (ale = anim_data->first; ale; ale = next) {
3374 next = ale->next;
3375
3376 if (ale->type == ANIMTYPE_NONE) {
3377 BLI_freelinkN(anim_data, ale);
3378 }
3379 else {
3380 items++;
3381 }
3382 }
3383
3384 return items;
3385 }
3386
3387 /* Remove duplicate entries in animation channel list */
animdata_filter_remove_duplis(ListBase * anim_data)3388 static size_t animdata_filter_remove_duplis(ListBase *anim_data)
3389 {
3390 bAnimListElem *ale, *next;
3391 GSet *gs;
3392 size_t items = 0;
3393
3394 /* build new hashtable to efficiently store and retrieve which entries have been
3395 * encountered already while searching
3396 */
3397 gs = BLI_gset_ptr_new(__func__);
3398
3399 /* loop through items, removing them from the list if a similar item occurs already */
3400 for (ale = anim_data->first; ale; ale = next) {
3401 next = ale->next;
3402
3403 /* check if hash has any record of an entry like this
3404 * - just use ale->data for now, though it would be nicer to involve
3405 * ale->type in combination too to capture corner cases
3406 * (where same data performs differently)
3407 */
3408 if (BLI_gset_add(gs, ale->data)) {
3409 /* this entry is 'unique' and can be kept */
3410 items++;
3411 }
3412 else {
3413 /* this entry isn't needed anymore */
3414 BLI_freelinkN(anim_data, ale);
3415 }
3416 }
3417
3418 /* free the hash... */
3419 BLI_gset_free(gs, NULL);
3420
3421 /* return the number of items still in the list */
3422 return items;
3423 }
3424
3425 /* ----------- Public API --------------- */
3426
3427 /**
3428 * This function filters the active data source to leave only animation channels suitable for
3429 * usage by the caller. It will return the length of the list
3430 *
3431 * \param anim_data: Is a pointer to a #ListBase,
3432 * to which the filtered animation channels will be placed for use.
3433 * \param filter_mode: how should the data be filtered - bit-mapping accessed flags.
3434 */
ANIM_animdata_filter(bAnimContext * ac,ListBase * anim_data,eAnimFilter_Flags filter_mode,void * data,eAnimCont_Types datatype)3435 size_t ANIM_animdata_filter(bAnimContext *ac,
3436 ListBase *anim_data,
3437 eAnimFilter_Flags filter_mode,
3438 void *data,
3439 eAnimCont_Types datatype)
3440 {
3441 size_t items = 0;
3442
3443 /* only filter data if there's somewhere to put it */
3444 if (data && anim_data) {
3445 /* firstly filter the data */
3446 switch (datatype) {
3447 /* Action-Editing Modes */
3448 case ANIMCONT_ACTION: /* 'Action Editor' */
3449 {
3450 Object *obact = ac->obact;
3451 SpaceAction *saction = (SpaceAction *)ac->sl;
3452 bDopeSheet *ads = (saction) ? &saction->ads : NULL;
3453
3454 /* specially check for AnimData filter, see T36687. */
3455 if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) {
3456 /* all channels here are within the same AnimData block, hence this special case */
3457 if (LIKELY(obact->adt)) {
3458 ANIMCHANNEL_NEW_CHANNEL(obact->adt, ANIMTYPE_ANIMDATA, (ID *)obact, NULL);
3459 }
3460 }
3461 else {
3462 /* The check for the DopeSheet summary is included here
3463 * since the summary works here too. */
3464 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3465 items += animfilter_action(ac, anim_data, ads, data, filter_mode, (ID *)obact);
3466 }
3467 }
3468
3469 break;
3470 }
3471 case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
3472 {
3473 Key *key = (Key *)data;
3474
3475 /* specially check for AnimData filter, see T36687. */
3476 if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) {
3477 /* all channels here are within the same AnimData block, hence this special case */
3478 if (LIKELY(key->adt)) {
3479 ANIMCHANNEL_NEW_CHANNEL(key->adt, ANIMTYPE_ANIMDATA, (ID *)key, NULL);
3480 }
3481 }
3482 else {
3483 /* The check for the DopeSheet summary is included here
3484 * since the summary works here too. */
3485 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3486 items = animdata_filter_shapekey(ac, anim_data, key, filter_mode);
3487 }
3488 }
3489
3490 break;
3491 }
3492
3493 /* Modes for Specialty Data Types (i.e. not keyframes) */
3494 case ANIMCONT_GPENCIL: {
3495 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3496 items = animdata_filter_gpencil(ac, anim_data, data, filter_mode);
3497 }
3498 break;
3499 }
3500 case ANIMCONT_MASK: {
3501 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3502 items = animdata_filter_mask(ac->bmain, anim_data, data, filter_mode);
3503 }
3504 break;
3505 }
3506
3507 /* DopeSheet Based Modes */
3508 case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */
3509 {
3510 /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
3511 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3512 items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
3513 }
3514 break;
3515 }
3516 case ANIMCONT_FCURVES: /* Graph Editor -> F-Curves/Animation Editing */
3517 case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */
3518 case ANIMCONT_NLA: /* NLA Editor */
3519 {
3520 /* all of these editors use the basic DopeSheet data for filtering options,
3521 * but don't have all the same features */
3522 items = animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
3523 break;
3524 }
3525
3526 /* Timeline Mode - Basically the same as dopesheet,
3527 * except we only have the summary for now */
3528 case ANIMCONT_TIMELINE: {
3529 /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
3530 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3531 items += animdata_filter_dopesheet(ac, anim_data, data, filter_mode);
3532 }
3533 break;
3534 }
3535
3536 /* Special/Internal Use */
3537 case ANIMCONT_CHANNEL: /* animation channel */
3538 {
3539 bDopeSheet *ads = ac->ads;
3540
3541 /* based on the channel type, filter relevant data for this */
3542 items = animdata_filter_animchan(ac, anim_data, ads, data, filter_mode);
3543 break;
3544 }
3545
3546 /* unhandled */
3547 default: {
3548 printf("ANIM_animdata_filter() - Invalid datatype argument %u\n", datatype);
3549 break;
3550 }
3551 }
3552
3553 /* remove any 'weedy' entries */
3554 items = animdata_filter_remove_invalid(anim_data);
3555
3556 /* remove duplicates (if required) */
3557 if (filter_mode & ANIMFILTER_NODUPLIS) {
3558 items = animdata_filter_remove_duplis(anim_data);
3559 }
3560 }
3561
3562 /* return the number of items in the list */
3563 return items;
3564 }
3565
3566 /* ************************************************************ */
3567