Blender V4.5
anim_filter.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2008 Blender Authors, Joshua Leung. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9/* This file contains a system used to provide a layer of abstraction between sources
10 * of animation data and tools in Animation Editors. The method used here involves
11 * generating a list of edit structures which enable tools to naively perform the actions
12 * they require without all the boiler-plate associated with loops within loops and checking
13 * for cases to ignore.
14 *
15 * While this is primarily used for the Action/Dopesheet Editor (and its accessory modes),
16 * the Graph Editor also uses this for its channel list and for determining which curves
17 * are being edited. Likewise, the NLA Editor also uses this for its channel list and in
18 * its operators.
19 *
20 * NOTE: much of the original system this was based on was built before the creation of the RNA
21 * system. In future, it would be interesting to replace some parts of this code with RNA queries,
22 * however, RNA does not eliminate some of the boiler-plate reduction benefits presented by this
23 * system, so if any such work does occur, it should only be used for the internals used here...
24 *
25 * -- Joshua Leung, Dec 2008 (Last revision July 2009)
26 */
27
28#include <cstring>
29
30#include "DNA_anim_types.h"
31#include "DNA_armature_types.h"
32#include "DNA_cachefile_types.h"
33#include "DNA_camera_types.h"
34#include "DNA_curves_types.h"
37#include "DNA_key_types.h"
38#include "DNA_lattice_types.h"
39#include "DNA_layer_types.h"
40#include "DNA_light_types.h"
42#include "DNA_linestyle_types.h"
43#include "DNA_mask_types.h"
44#include "DNA_material_types.h"
45#include "DNA_mesh_types.h"
46#include "DNA_meta_types.h"
47#include "DNA_movieclip_types.h"
48#include "DNA_node_types.h"
50#include "DNA_object_types.h"
51#include "DNA_particle_types.h"
53#include "DNA_scene_types.h"
54#include "DNA_screen_types.h"
55#include "DNA_sequence_types.h"
56#include "DNA_space_types.h"
57#include "DNA_speaker_types.h"
58#include "DNA_userdef_types.h"
59#include "DNA_volume_types.h"
60#include "DNA_world_types.h"
61
62#include "MEM_guardedalloc.h"
63
64#include "BLI_alloca.h"
65#include "BLI_ghash.h"
66#include "BLI_listbase.h"
67#include "BLI_string.h"
68#include "BLI_utildefines.h"
69
70#include "BKE_action.hh"
71#include "BKE_anim_data.hh"
72#include "BKE_collection.hh"
73#include "BKE_context.hh"
74#include "BKE_fcurve.hh"
75#include "BKE_fcurve_driver.h"
76#include "BKE_global.hh"
77#include "BKE_grease_pencil.hh"
78#include "BKE_key.hh"
79#include "BKE_layer.hh"
80#include "BKE_library.hh"
81#include "BKE_main.hh"
82#include "BKE_mask.h"
83#include "BKE_material.hh"
84#include "BKE_modifier.hh"
85#include "BKE_node.hh"
86#include "BKE_node_runtime.hh"
87
88#include "ED_anim_api.hh"
89#include "ED_markers.hh"
90
91#include "SEQ_sequencer.hh"
92#include "SEQ_utils.hh"
93
94#include "ANIM_action.hh"
95#include "ANIM_armature.hh"
97
98#include "anim_intern.hh"
99
100using namespace blender;
101
102/* ************************************************************ */
103/* Blender Context <-> Animation Context mapping */
104
105/* ----------- Private Stuff - Action Editor ------------- */
106
107/* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */
108/* NOTE: there's a similar function in `key.cc` #BKE_key_from_object. */
110{
111 Scene *scene = ac->scene;
112 ViewLayer *view_layer = ac->view_layer;
113 Object *ob;
114
115 BKE_view_layer_synced_ensure(scene, view_layer);
116 ob = BKE_view_layer_active_object_get(view_layer);
117 if (ob == nullptr) {
118 return nullptr;
119 }
120
121 /* XXX pinning is not available in 'ShapeKey' mode... */
122 // if (saction->pin) { return nullptr; }
123
124 /* shapekey data is stored with geometry data */
125 return BKE_key_from_object(ob);
126}
127
128/* Get data being edited in Action Editor (depending on current 'mode') */
130{
131 /* get dopesheet */
132 ac->ads = &saction->ads;
133 ac->dopesheet_mode = eAnimEdit_Context(saction->mode);
134
135 /* sync settings with current view status, then return appropriate data */
136 switch (saction->mode) {
137 case SACTCONT_ACTION: /* 'Action Editor' */
138 /* if not pinned, sync with active object */
139 if (/* `saction->pin == 0` */ true) {
140 if (ac->obact && ac->obact->adt) {
141 saction->action = ac->obact->adt->action;
142 }
143 else {
144 saction->action = nullptr;
145 }
146 }
147
149 ac->data = saction->action;
150
151 return true;
152
153 case SACTCONT_SHAPEKEY: /* 'ShapeKey Editor' */
155 ac->data = actedit_get_shapekeys(ac);
156
157 /* if not pinned, sync with active object */
158 if (/* `saction->pin == 0` */ true) {
159 Key *key = static_cast<Key *>(ac->data);
160
161 if (key && key->adt) {
162 saction->action = key->adt->action;
163 }
164 else {
165 saction->action = nullptr;
166 }
167 }
168 return true;
169
170 case SACTCONT_GPENCIL: /* Grease Pencil */ /* XXX review how this mode is handled... */
171 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
172 saction->ads.source = reinterpret_cast<ID *>(ac->scene);
173
175 ac->data = &saction->ads;
176 return true;
177
178 case SACTCONT_CACHEFILE: /* Cache File */ /* XXX review how this mode is handled... */
179 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
180 saction->ads.source = reinterpret_cast<ID *>(ac->scene);
181
183 ac->data = &saction->ads;
184 return true;
185
186 case SACTCONT_MASK: /* Mask */ /* XXX: review how this mode is handled. */
187 {
188 /* TODO: other methods to get the mask. */
189#if 0
190 Strip *strip = SEQ_select_active_get(ac->scene);
191 MovieClip *clip = ac->scene->clip;
192 struct Mask *mask = strip ? strip->mask : nullptr;
193#endif
194
195 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
196 saction->ads.source = reinterpret_cast<ID *>(ac->scene);
197
199 ac->data = &saction->ads;
200 return true;
201 }
202
203 case SACTCONT_DOPESHEET: /* DopeSheet */
204 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
205 saction->ads.source = reinterpret_cast<ID *>(ac->scene);
206
208 ac->data = &saction->ads;
209 return true;
210
211 case SACTCONT_TIMELINE: /* Timeline */
212 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
213 saction->ads.source = reinterpret_cast<ID *>(ac->scene);
214
215 /* sync scene's "selected keys only" flag with our "only selected" flag
216 *
217 * XXX: This is a workaround for #55525. We shouldn't really be syncing the flags like this,
218 * but it's a simpler fix for now than also figuring out how the next/prev keyframe
219 * tools should work in the 3D View if we allowed full access to the timeline's
220 * dopesheet filters (i.e. we'd have to figure out where to host those settings,
221 * to be on a scene level like this flag currently is, along with several other unknowns).
222 */
223 if (ac->scene->flag & SCE_KEYS_NO_SELONLY) {
225 }
226 else {
228 }
229
231 ac->data = &saction->ads;
232 return true;
233
234 default: /* unhandled yet */
236 ac->data = nullptr;
237 return false;
238 }
239}
240
241/* ----------- Private Stuff - Graph Editor ------------- */
242
243/* Get data being edited in Graph Editor (depending on current 'mode') */
245{
246 /* init dopesheet data if non-existent (i.e. for old files) */
247 if (sipo->ads == nullptr) {
248 sipo->ads = MEM_callocN<bDopeSheet>("GraphEdit DopeSheet");
249 sipo->ads->source = reinterpret_cast<ID *>(ac->scene);
250 }
251 ac->ads = sipo->ads;
253
254 /* set settings for Graph Editor - "Selected = Editable" */
255 if (U.animation_flag & USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS) {
257 }
258 else {
260 }
261
262 /* sync settings with current view status, then return appropriate data */
263 switch (sipo->mode) {
264 case SIPO_MODE_ANIMATION: /* Animation F-Curve Editor */
265 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
266 sipo->ads->source = reinterpret_cast<ID *>(ac->scene);
268
270 ac->data = sipo->ads;
271 return true;
272
273 case SIPO_MODE_DRIVERS: /* Driver F-Curve Editor */
274 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
275 sipo->ads->source = reinterpret_cast<ID *>(ac->scene);
277
279 ac->data = sipo->ads;
280 return true;
281
282 default: /* unhandled yet */
284 ac->data = nullptr;
285 return false;
286 }
287}
288
289/* ----------- Private Stuff - NLA Editor ------------- */
290
291/* Get data being edited in Graph Editor (depending on current 'mode') */
293{
294 /* init dopesheet data if non-existent (i.e. for old files) */
295 if (snla->ads == nullptr) {
296 snla->ads = MEM_callocN<bDopeSheet>("NlaEdit DopeSheet");
297 }
298 ac->ads = snla->ads;
299
300 /* sync settings with current view status, then return appropriate data */
301 /* update scene-pointer (no need to check for pinning yet, as not implemented) */
302 snla->ads->source = reinterpret_cast<ID *>(ac->scene);
304
306 ac->data = snla->ads;
307
308 return true;
309}
310
311/* ----------- Public API --------------- */
312
314{
315 SpaceLink *sl = ac->sl;
316 bool ok = false;
317
318 /* context depends on editor we are currently in */
319 if (sl) {
320 switch (ac->spacetype) {
321 case SPACE_ACTION: {
322 SpaceAction *saction = reinterpret_cast<SpaceAction *>(sl);
323 ok = actedit_get_context(ac, saction);
324 break;
325 }
326 case SPACE_GRAPH: {
327 SpaceGraph *sipo = reinterpret_cast<SpaceGraph *>(sl);
328 ok = graphedit_get_context(ac, sipo);
329 break;
330 }
331 case SPACE_NLA: {
332 SpaceNla *snla = reinterpret_cast<SpaceNla *>(sl);
333 ok = nlaedit_get_context(ac, snla);
334 break;
335 }
336 case SPACE_EMPTY:
337 case SPACE_VIEW3D:
338 case SPACE_OUTLINER:
339 case SPACE_PROPERTIES:
340 case SPACE_FILE:
341 case SPACE_IMAGE:
342 case SPACE_INFO:
343 case SPACE_SEQ:
344 case SPACE_TEXT:
345 case SPACE_SCRIPT:
346 case SPACE_NODE:
347 case SPACE_CONSOLE:
348 case SPACE_USERPREF:
349 case SPACE_CLIP:
350 case SPACE_TOPBAR:
351 case SPACE_STATUSBAR:
353 break;
354 }
355 }
356
357 /* check if there's any valid data */
358 return (ok && ac->data);
359}
360
362{
363 Main *bmain = CTX_data_main(C);
364 ScrArea *area = CTX_wm_area(C);
365 ARegion *region = CTX_wm_region(C);
367 Scene *scene = CTX_data_scene(C);
368
369 /* clear old context info */
370 if (ac == nullptr) {
371 return false;
372 }
373 memset(ac, 0, sizeof(bAnimContext));
374
375 /* get useful default context settings from context */
376 ac->bmain = bmain;
377 ac->scene = scene;
379 if (scene) {
382 }
385 ac->area = area;
386 ac->region = region;
387 ac->sl = sl;
388 ac->spacetype = eSpace_Type((area) ? area->spacetype : 0);
389 ac->regiontype = eRegion_Type((region) ? region->regiontype : 0);
390
391 /* get data context info */
392 /* XXX: if the below fails, try to grab this info from context instead...
393 * (to allow for scripting). */
395}
396
401
402/* ************************************************************ */
403/* Blender Data <-- Filter --> Channels to be operated on */
404
405/* macros to use before/after getting the sub-channels of some channel,
406 * to abstract away some of the tricky logic involved
407 *
408 * cases:
409 * 1) Graph Edit main area (just data) OR channels visible in Channel List
410 * 2) If not showing channels, we're only interested in the data (Action Editor's editing)
411 * 3) We don't care what data, we just care there is some (so that a collapsed
412 * channel can be kept around). No need to clear channels-flag in order to
413 * keep expander channels with no sub-data out, as those cases should get
414 * dealt with by the recursive detection idiom in place.
415 *
416 * Implementation NOTE:
417 * YES the _doSubChannels variable is NOT read anywhere. BUT, this is NOT an excuse
418 * to go steamrolling the logic into a single-line expression as from experience,
419 * those are notoriously difficult to read + debug when extending later on. The code
420 * below is purposefully laid out so that each case noted above corresponds clearly to
421 * one case below.
422 */
423#define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check) \
424 { \
425 const eAnimFilter_Flags _filter = filter_mode; \
426 short _doSubChannels = 0; \
427 if (!(filter_mode & ANIMFILTER_LIST_VISIBLE) || (expanded_check)) { \
428 _doSubChannels = 1; \
429 } \
430 else if (!(filter_mode & ANIMFILTER_LIST_CHANNELS)) { \
431 _doSubChannels = 2; \
432 } \
433 else { \
434 filter_mode |= ANIMFILTER_TMP_PEEK; \
435 } \
436\
437 { \
438 (void)_doSubChannels; \
439 }
440/* ... standard sub-channel filtering can go on here now ... */
441#define END_ANIMFILTER_SUBCHANNELS \
442 filter_mode = _filter; \
443 } \
444 (void)0
445
446/* ............................... */
447
448/* Test whether AnimData has a usable Action. */
449#define ANIMDATA_HAS_ACTION_LEGACY(id) \
450 ((id)->adt && (id)->adt->action && (id)->adt->action->wrap().is_action_legacy())
451
452#define ANIMDATA_HAS_ACTION_LAYERED(id) \
453 ((id)->adt && (id)->adt->action && (id)->adt->action->wrap().is_action_layered())
454
455/* quick macro to test if AnimData is usable for drivers */
456#define ANIMDATA_HAS_DRIVERS(id) ((id)->adt && (id)->adt->drivers.first)
457
458/* quick macro to test if AnimData is usable for NLA */
459#define ANIMDATA_HAS_NLA(id) ((id)->adt && (id)->adt->nla_tracks.first)
460
498#define ANIMDATA_FILTER_CASES( \
499 id, adtOk, nlaOk, driversOk, nlaKeysOk, legacyActionOk, layeredActionOk) \
500 { \
501 if ((id)->adt) { \
502 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || \
503 !((id)->adt->flag & ADT_CURVES_NOT_VISIBLE)) { \
504 if (filter_mode & ANIMFILTER_ANIMDATA) { \
505 adtOk \
506 } \
507 else if (ac->ads->filterflag & ADS_FILTER_ONLYNLA) { \
508 if (ANIMDATA_HAS_NLA(id)) { \
509 nlaOk \
510 } \
511 else if (!(ac->ads->filterflag & ADS_FILTER_NLA_NOACT) || \
512 ANIMDATA_HAS_ACTION_LAYERED(id)) \
513 { \
514 nlaOk \
515 } \
516 } \
517 else if (ac->ads->filterflag & ADS_FILTER_ONLYDRIVERS) { \
518 if (ANIMDATA_HAS_DRIVERS(id)) { \
519 driversOk \
520 } \
521 } \
522 else { \
523 if (ANIMDATA_HAS_NLA(id)) { \
524 nlaKeysOk \
525 } \
526 if (ANIMDATA_HAS_ACTION_LAYERED(id)) { \
527 layeredActionOk \
528 } \
529 else if (ANIMDATA_HAS_ACTION_LEGACY(id)) { \
530 legacyActionOk \
531 } \
532 } \
533 } \
534 } \
535 } \
536 (void)0
537
538/* ............................... */
539
546#define ANIMCHANNEL_NEW_CHANNEL_FULL( \
547 bmain, channel_data, channel_type, owner_id, fcurve_owner_id, ale_statement) \
548 if (filter_mode & ANIMFILTER_TMP_PEEK) { \
549 return 1; \
550 } \
551 { \
552 bAnimListElem *ale = make_new_animlistelem( \
553 bmain, channel_data, channel_type, (ID *)owner_id, fcurve_owner_id); \
554 if (ale) { \
555 BLI_addtail(anim_data, ale); \
556 items++; \
557 ale_statement \
558 } \
559 } \
560 (void)0
561
562#define ANIMCHANNEL_NEW_CHANNEL(bmain, channel_data, channel_type, owner_id, fcurve_owner_id) \
563 ANIMCHANNEL_NEW_CHANNEL_FULL(bmain, channel_data, channel_type, owner_id, fcurve_owner_id, {})
564
565/* ............................... */
566
567/* quick macro to test if an anim-channel representing an AnimData block is suitably active */
568#define ANIMCHANNEL_ACTIVEOK(ale) \
569 (!(filter_mode & ANIMFILTER_ACTIVE) || !(ale->adt) || (ale->adt->flag & ADT_UI_ACTIVE))
570
571/* Quick macro to test if an anim-channel (F-Curve, Group, etc.)
572 * is selected in an acceptable way. */
573#define ANIMCHANNEL_SELOK(test_func) \
574 (!(filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) || \
575 ((filter_mode & ANIMFILTER_SEL) && test_func) || \
576 ((filter_mode & ANIMFILTER_UNSEL) && test_func == 0))
577
587#define ANIMCHANNEL_SELEDITOK(test_func) \
588 (!(filter_mode & ANIMFILTER_SELEDIT) || !(filter_mode & ANIMFILTER_FOREDIT) || (test_func))
589
590/* ----------- 'Private' Stuff --------------- */
591
597{
598 ale.adt = adt;
599
600 if (!adt || !adt->action) {
601 ale.key_data = nullptr;
602 ale.datatype = ALE_NONE;
603 return;
604 }
605
606 blender::animrig::Action &action = adt->action->wrap();
607 ale.key_data = &action;
609}
610
611/* this function allocates memory for a new bAnimListElem struct for the
612 * provided animation channel-data.
613 */
615 Main *bmain, void *data, const eAnim_ChannelType datatype, ID *owner_id, ID *fcurve_owner_id)
616{
617 /* Only allocate memory if there is data to convert. */
618 if (!data) {
619 return nullptr;
620 }
621
622 /* Allocate and set generic data. */
623 bAnimListElem *ale = MEM_callocN<bAnimListElem>("bAnimListElem");
624
625 ale->data = data;
626 ale->type = datatype;
627
628 ale->bmain = bmain;
629 ale->id = owner_id;
630 ale->adt = BKE_animdata_from_id(owner_id);
631 ale->fcurve_owner_id = fcurve_owner_id;
632
633 /* do specifics */
634 switch (datatype) {
635 case ANIMTYPE_SUMMARY: {
636 /* Nothing to include for now... this is just a dummy wrapper around
637 * all the other channels in the DopeSheet, and gets included at the start of the list. */
638 ale->key_data = nullptr;
639 ale->datatype = ALE_ALL;
640 break;
641 }
642 case ANIMTYPE_SCENE: {
643 Scene *sce = static_cast<Scene *>(data);
644
645 ale->flag = sce->flag;
646
647 ale->key_data = sce;
648 ale->datatype = ALE_SCE;
649
650 ale->adt = BKE_animdata_from_id(static_cast<ID *>(data));
651 break;
652 }
653 case ANIMTYPE_OBJECT: {
654 Base *base = static_cast<Base *>(data);
655 Object *ob = base->object;
656
657 ale->flag = ob->flag;
658
659 ale->key_data = ob;
660 ale->datatype = ALE_OB;
661
662 ale->adt = BKE_animdata_from_id(&ob->id);
663 break;
664 }
666 bAction *action = static_cast<bAction *>(data);
667
668 ale->flag = action->flag;
669
670 ale->key_data = action;
672 break;
673 }
675 animrig::Slot *slot = static_cast<animrig::Slot *>(data);
676 ale->flag = slot->slot_flags;
677
678 BLI_assert_msg(GS(fcurve_owner_id->name) == ID_AC, "fcurve_owner_id should be an Action");
679 /* ale->data = the slot itself, key_data = the Action. */
680 ale->key_data = fcurve_owner_id;
682 break;
683 }
684 case ANIMTYPE_FILLACTD: {
685 bAction *act = static_cast<bAction *>(data);
686
687 ale->flag = act->flag;
688
689 ale->key_data = act;
690 ale->datatype = ALE_ACT;
691 break;
692 }
694 AnimData *adt = static_cast<AnimData *>(data);
695
696 ale->flag = adt->flag;
697
698 /* XXX drivers don't show summary for now. */
699 ale->key_data = nullptr;
700 ale->datatype = ALE_NONE;
701 break;
702 }
703 case ANIMTYPE_DSMAT: {
704 Material *ma = static_cast<Material *>(data);
705 ale->flag = FILTER_MAT_OBJD(ma);
706 key_data_from_adt(*ale, ma->adt);
707 break;
708 }
709 case ANIMTYPE_DSLAM: {
710 Light *la = static_cast<Light *>(data);
711 ale->flag = FILTER_LAM_OBJD(la);
712 key_data_from_adt(*ale, la->adt);
713 break;
714 }
715 case ANIMTYPE_DSCAM: {
716 Camera *ca = static_cast<Camera *>(data);
717 ale->flag = FILTER_CAM_OBJD(ca);
718 key_data_from_adt(*ale, ca->adt);
719 break;
720 }
722 CacheFile *cache_file = static_cast<CacheFile *>(data);
723 ale->flag = FILTER_CACHEFILE_OBJD(cache_file);
724 key_data_from_adt(*ale, cache_file->adt);
725 break;
726 }
727 case ANIMTYPE_DSCUR: {
728 Curve *cu = static_cast<Curve *>(data);
729 ale->flag = FILTER_CUR_OBJD(cu);
730 key_data_from_adt(*ale, cu->adt);
731 break;
732 }
733 case ANIMTYPE_DSARM: {
734 bArmature *arm = static_cast<bArmature *>(data);
735 ale->flag = FILTER_ARM_OBJD(arm);
736 key_data_from_adt(*ale, arm->adt);
737 break;
738 }
739 case ANIMTYPE_DSMESH: {
740 Mesh *mesh = static_cast<Mesh *>(data);
741 ale->flag = FILTER_MESH_OBJD(mesh);
742 key_data_from_adt(*ale, mesh->adt);
743 break;
744 }
745 case ANIMTYPE_DSLAT: {
746 Lattice *lt = static_cast<Lattice *>(data);
747 ale->flag = FILTER_LATTICE_OBJD(lt);
748 key_data_from_adt(*ale, lt->adt);
749 break;
750 }
751 case ANIMTYPE_DSSPK: {
752 Speaker *spk = static_cast<Speaker *>(data);
753 ale->flag = FILTER_SPK_OBJD(spk);
754 key_data_from_adt(*ale, spk->adt);
755 break;
756 }
757 case ANIMTYPE_DSHAIR: {
758 Curves *curves = static_cast<Curves *>(data);
759 ale->flag = FILTER_CURVES_OBJD(curves);
760 key_data_from_adt(*ale, curves->adt);
761 break;
762 }
764 PointCloud *pointcloud = static_cast<PointCloud *>(data);
765 ale->flag = FILTER_POINTS_OBJD(pointcloud);
766 key_data_from_adt(*ale, pointcloud->adt);
767 break;
768 }
769 case ANIMTYPE_DSVOLUME: {
770 Volume *volume = static_cast<Volume *>(data);
771 ale->flag = FILTER_VOLUME_OBJD(volume);
772 key_data_from_adt(*ale, volume->adt);
773 break;
774 }
776 LightProbe *probe = static_cast<LightProbe *>(data);
777 ale->flag = FILTER_LIGHTPROBE_OBJD(probe);
778 key_data_from_adt(*ale, probe->adt);
779 break;
780 }
781 case ANIMTYPE_DSSKEY: {
782 Key *key = static_cast<Key *>(data);
783 ale->flag = FILTER_SKE_OBJD(key);
784 key_data_from_adt(*ale, key->adt);
785 break;
786 }
787 case ANIMTYPE_DSWOR: {
788 World *wo = static_cast<World *>(data);
789 ale->flag = FILTER_WOR_SCED(wo);
790 key_data_from_adt(*ale, wo->adt);
791 break;
792 }
793 case ANIMTYPE_DSNTREE: {
794 bNodeTree *ntree = static_cast<bNodeTree *>(data);
795 ale->flag = FILTER_NTREE_DATA(ntree);
796 key_data_from_adt(*ale, ntree->adt);
797 break;
798 }
800 FreestyleLineStyle *linestyle = static_cast<FreestyleLineStyle *>(data);
801 ale->flag = FILTER_LS_SCED(linestyle);
802 key_data_from_adt(*ale, linestyle->adt);
803 break;
804 }
805 case ANIMTYPE_DSPART: {
806 ParticleSettings *part = static_cast<ParticleSettings *>(ale->data);
807 ale->flag = FILTER_PART_OBJD(part);
808 key_data_from_adt(*ale, part->adt);
809 break;
810 }
811 case ANIMTYPE_DSTEX: {
812 Tex *tex = static_cast<Tex *>(data);
813 ale->flag = FILTER_TEX_DATA(tex);
814 key_data_from_adt(*ale, tex->adt);
815 break;
816 }
817 case ANIMTYPE_DSGPENCIL: {
818 bGPdata *gpd = static_cast<bGPdata *>(data);
819 /* NOTE: we just reuse the same expand filter for this case */
820 ale->flag = EXPANDED_GPD(gpd);
821
822 /* XXX: currently, this is only used for access to its animation data */
823 key_data_from_adt(*ale, gpd->adt);
824 break;
825 }
826 case ANIMTYPE_DSMCLIP: {
827 MovieClip *clip = static_cast<MovieClip *>(data);
828 ale->flag = EXPANDED_MCLIP(clip);
829 key_data_from_adt(*ale, clip->adt);
830 break;
831 }
833 AnimData *adt = static_cast<AnimData *>(data);
834
835 ale->flag = adt->flag;
836
837 ale->key_data = nullptr;
838 ale->datatype = ALE_NONE;
839 break;
840 }
841 case ANIMTYPE_GROUP: {
842 BLI_assert_msg(GS(fcurve_owner_id->name) == ID_AC, "fcurve_owner_id should be an Action");
843
844 bActionGroup *agrp = static_cast<bActionGroup *>(data);
845
846 ale->flag = agrp->flag;
847
848 ale->key_data = nullptr;
849 ale->datatype = ALE_GROUP;
850 break;
851 }
852 case ANIMTYPE_FCURVE:
853 case ANIMTYPE_NLACURVE: /* practically the same as ANIMTYPE_FCURVE.
854 * Differences are applied post-creation */
855 {
856 FCurve *fcu = static_cast<FCurve *>(data);
857
858 ale->flag = fcu->flag;
859
860 ale->key_data = fcu;
861 ale->datatype = ALE_FCURVE;
862 break;
863 }
864 case ANIMTYPE_SHAPEKEY: {
865 KeyBlock *kb = static_cast<KeyBlock *>(data);
866 Key *key = reinterpret_cast<Key *>(ale->id);
867
868 ale->flag = kb->flag;
869
870 /* whether we have keyframes depends on whether there is a Key block to find it from */
871 if (key) {
872 /* index of shapekey is defined by place in key's list */
873 ale->index = BLI_findindex(&key->block, kb);
874
875 /* the corresponding keyframes are from the animdata */
876 if (ale->adt && ale->adt->action) {
877 /* Try to find the F-Curve which corresponds to this exactly. */
878 if (std::optional<std::string> rna_path = BKE_keyblock_curval_rnapath_get(key, kb)) {
880 {*rna_path, 0});
881 }
882 }
883 ale->datatype = (ale->key_data) ? ALE_FCURVE : ALE_NONE;
884 }
885 break;
886 }
887 case ANIMTYPE_GPLAYER: {
888 bGPDlayer *gpl = static_cast<bGPDlayer *>(data);
889
890 ale->flag = gpl->flag;
891
892 ale->key_data = nullptr;
893 ale->datatype = ALE_GPFRAME;
894 break;
895 }
897 GreasePencilLayer *layer = static_cast<GreasePencilLayer *>(data);
898
899 ale->flag = layer->base.flag;
900
901 ale->key_data = nullptr;
903 break;
904 }
906 GreasePencilLayerTreeGroup *layer_group = static_cast<GreasePencilLayerTreeGroup *>(data);
907
908 ale->flag = layer_group->base.flag;
909
910 ale->key_data = nullptr;
912 break;
913 }
915 GreasePencil *grease_pencil = static_cast<GreasePencil *>(data);
916
917 ale->flag = grease_pencil->flag;
918
919 ale->key_data = nullptr;
921 break;
922 }
923 case ANIMTYPE_MASKLAYER: {
924 MaskLayer *masklay = static_cast<MaskLayer *>(data);
925
926 ale->flag = masklay->flag;
927
928 ale->key_data = nullptr;
929 ale->datatype = ALE_MASKLAY;
930 break;
931 }
932 case ANIMTYPE_NLATRACK: {
933 NlaTrack *nlt = static_cast<NlaTrack *>(data);
934
935 ale->flag = nlt->flag;
936
937 ale->key_data = &nlt->strips;
938 ale->datatype = ALE_NLASTRIP;
939 break;
940 }
941 case ANIMTYPE_NLAACTION: {
942 /* nothing to include for now... nothing editable from NLA-perspective here */
943 ale->key_data = nullptr;
944 ale->datatype = ALE_NONE;
945 break;
946 }
947
948 case ANIMTYPE_NONE:
951 case ANIMTYPE_DSMBALL:
953 case ANIMTYPE_PALETTE:
955 break;
956 }
957
958 return ale;
959}
960
961/* ----------------------------------------- */
962
963/* 'Only Selected' selected data and/or 'Include Hidden' filtering
964 * NOTE: when this function returns true, the F-Curve is to be skipped
965 */
967 FCurve *fcu,
968 ID *owner_id,
969 const eAnimFilter_Flags filter_mode)
970{
971 if (fcu->grp != nullptr && fcu->grp->flag & ADT_CURVES_ALWAYS_VISIBLE) {
972 return false;
973 }
974 /* hidden items should be skipped if we only care about visible data,
975 * but we aren't interested in hidden stuff */
976 const bool skip_hidden = (filter_mode & ANIMFILTER_DATA_VISIBLE) &&
978
979 if (GS(owner_id->name) == ID_OB) {
980 Object *ob = reinterpret_cast<Object *>(owner_id);
981 bPoseChannel *pchan = nullptr;
982 char bone_name[sizeof(pchan->name)];
983
984 /* Only consider if F-Curve involves `pose.bones`. */
985 if (fcu->rna_path &&
986 BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name)))
987 {
988 /* Get bone-name, and check if this bone is selected. */
989 pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
990
991 /* check whether to continue or skip */
992 if (pchan && pchan->bone) {
993 /* If only visible channels,
994 * skip if bone not visible unless user wants channels from hidden data too. */
995 if (skip_hidden) {
996 bArmature *arm = static_cast<bArmature *>(ob->data);
997
998 /* Skipping - is currently hidden. */
1000 return true;
1001 }
1002 }
1003
1004 /* can only add this F-Curve if it is selected */
1005 if (ac->ads->filterflag & ADS_FILTER_ONLYSEL) {
1006 if ((pchan->bone->flag & BONE_SELECTED) == 0) {
1007 return true;
1008 }
1009 }
1010 }
1011 }
1012 }
1013 else if (GS(owner_id->name) == ID_SCE) {
1014 Scene *scene = reinterpret_cast<Scene *>(owner_id);
1015 Strip *strip = nullptr;
1016 char strip_name[sizeof(strip->name)];
1017
1018 /* Only consider if F-Curve involves `sequence_editor.strips`. */
1019 if (fcu->rna_path &&
1020 BLI_str_quoted_substr(fcu->rna_path, "strips_all[", strip_name, sizeof(strip_name)))
1021 {
1022 /* Get strip name, and check if this strip is selected. */
1024 if (ed) {
1025 strip = blender::seq::get_strip_by_name(ed->seqbasep, strip_name, false);
1026 }
1027
1028 /* Can only add this F-Curve if it is selected. */
1029 if (ac->ads->filterflag & ADS_FILTER_ONLYSEL) {
1030
1031 /* NOTE(@ideasman42): The `strip == nullptr` check doesn't look right
1032 * (compared to other checks in this function which skip data that can't be found).
1033 *
1034 * This is done since the search for sequence strips doesn't use a global lookup:
1035 * - Nested meta-strips are excluded.
1036 * - When inside a meta-strip - strips outside the meta-strip excluded.
1037 *
1038 * Instead, only the strips directly visible to the user are considered for selection.
1039 * The nullptr check here means everything else is considered unselected and is not shown.
1040 *
1041 * There is a subtle difference between nodes, pose-bones ... etc
1042 * since data-paths that point to missing strips are not shown.
1043 * If this is an important difference, the nullptr case could perform a global lookup,
1044 * only returning `true` if the sequence strip exists elsewhere
1045 * (ignoring its selection state). */
1046 if (strip == nullptr) {
1047 return true;
1048 }
1049
1050 if ((strip->flag & SELECT) == 0) {
1051 return true;
1052 }
1053 }
1054 }
1055 }
1056 else if (GS(owner_id->name) == ID_NT) {
1057 bNodeTree *ntree = reinterpret_cast<bNodeTree *>(owner_id);
1058 bNode *node = nullptr;
1059 char node_name[sizeof(node->name)];
1060
1061 /* Check for selected nodes. */
1062 if (fcu->rna_path &&
1063 BLI_str_quoted_substr(fcu->rna_path, "nodes[", node_name, sizeof(node_name)))
1064 {
1065 /* Get strip name, and check if this strip is selected. */
1066 node = bke::node_find_node_by_name(*ntree, node_name);
1067
1068 /* Can only add this F-Curve if it is selected. */
1069 if (node) {
1070 if (ac->ads->filterflag & ADS_FILTER_ONLYSEL) {
1071 if ((node->flag & NODE_SELECT) == 0) {
1072 return true;
1073 }
1074 }
1075 }
1076 }
1077 }
1078
1079 return false;
1080}
1081
1082/* Helper for name-based filtering - Perform "partial/fuzzy matches" (as in 80a7efd) */
1083static bool name_matches_dopesheet_filter(const bDopeSheet *ads, const char *name)
1084{
1085 if (ads->flag & ADS_FLAG_FUZZY_NAMES) {
1086 /* full fuzzy, multi-word, case insensitive matches */
1087 const size_t str_len = strlen(ads->searchstr);
1088 const int words_max = BLI_string_max_possible_word_count(str_len);
1089
1090 int(*words)[2] = static_cast<int(*)[2]>(BLI_array_alloca(words, words_max));
1091 const int words_len = BLI_string_find_split_words(
1092 ads->searchstr, str_len, ' ', words, words_max);
1093 bool found = false;
1094
1095 /* match name against all search words */
1096 for (int index = 0; index < words_len; index++) {
1097 if (BLI_strncasestr(name, ads->searchstr + words[index][0], words[index][1])) {
1098 found = true;
1099 break;
1100 }
1101 }
1102
1103 /* if we have a match somewhere, this returns true */
1104 return ((ads->flag & ADS_FLAG_INVERT_FILTER) == 0) ? found : !found;
1105 }
1106 /* fallback/default - just case insensitive, but starts from start of word */
1107 bool found = BLI_strcasestr(name, ads->searchstr) != nullptr;
1108 return ((ads->flag & ADS_FLAG_INVERT_FILTER) == 0) ? found : !found;
1109}
1110
1111/* (Display-)Name-based F-Curve filtering
1112 * NOTE: when this function returns true, the F-Curve is to be skipped
1113 */
1115 bAnimContext *ac, FCurve *fcu, eAnim_ChannelType channel_type, void *owner, ID *owner_id)
1116{
1117 bAnimListElem ale_dummy = {nullptr};
1118 const bAnimChannelType *acf;
1119
1120 /* create a dummy wrapper for the F-Curve, so we can get typeinfo for it */
1121 ale_dummy.type = channel_type;
1122 ale_dummy.owner = owner;
1123 ale_dummy.id = owner_id;
1124 ale_dummy.data = fcu;
1125
1126 /* get type info for channel */
1127 acf = ANIM_channel_get_typeinfo(&ale_dummy);
1128 if (acf && acf->name) {
1129 char name[256]; /* hopefully this will be enough! */
1130
1131 /* get name */
1132 acf->name(&ale_dummy, name);
1133
1134 /* check for partial match with the match string, assuming case insensitive filtering
1135 * if match, this channel shouldn't be ignored!
1136 */
1137 return !name_matches_dopesheet_filter(ac->ads, name);
1138 }
1139
1140 /* just let this go... */
1141 return true;
1142}
1143
1145{
1147 if (!acf) {
1149 /* Do not filter out stuff unless we know it can be filtered out. */
1150 return true;
1151 }
1152
1153 char name[ANIM_CHAN_NAME_SIZE];
1154 acf->name(&ale, name);
1155 return name_matches_dopesheet_filter(&ads, name);
1156}
1157
1163static bool fcurve_has_errors(bAnimContext *ac, const FCurve *fcu)
1164{
1165 /* F-Curve disabled (path evaluation error). */
1166 if (fcu->flag & FCURVE_DISABLED) {
1167 return true;
1168 }
1169
1170 /* driver? */
1171 if (fcu->driver) {
1172 const ChannelDriver *driver = fcu->driver;
1173
1174 /* error flag on driver usually means that there is an error
1175 * BUT this may not hold with PyDrivers as this flag gets cleared
1176 * if no critical errors prevent the driver from working...
1177 */
1178 if (driver->flag & DRIVER_FLAG_INVALID) {
1179 return true;
1180 }
1181
1182 /* check variables for other things that need linting... */
1183 /* TODO: maybe it would be more efficient just to have a quick flag for this? */
1184 LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) {
1186 if (dtar->flag & DTAR_FLAG_INVALID) {
1187 return true;
1188 }
1189
1190 if ((dtar->flag & DTAR_FLAG_FALLBACK_USED) &&
1192 {
1193 return true;
1194 }
1195 }
1197 }
1198 }
1199
1200 /* no errors found */
1201 return false;
1202}
1203
1204/* find the next F-Curve that is usable for inclusion */
1206 FCurve *first,
1207 eAnim_ChannelType channel_type,
1208 const eAnimFilter_Flags filter_mode,
1209 void *owner,
1210 ID *owner_id)
1211{
1212 bActionGroup *grp = (channel_type == ANIMTYPE_FCURVE) ? static_cast<bActionGroup *>(owner) :
1213 nullptr;
1214 FCurve *fcu = nullptr;
1215
1216 /* Loop over F-Curves - assume that the caller of this has already checked
1217 * that these should be included.
1218 * NOTE: we need to check if the F-Curves belong to the same group,
1219 * as this gets called for groups too...
1220 */
1221 for (fcu = first; ((fcu) && (fcu->grp == grp)); fcu = fcu->next) {
1222 /* special exception for Pose-Channel/Sequence-Strip/Node Based F-Curves:
1223 * - The 'Only Selected' and 'Include Hidden' data filters should be applied to sub-ID data
1224 * which can be independently selected/hidden, such as Pose-Channels, Sequence Strips,
1225 * and Nodes. Since these checks were traditionally done as first check for objects,
1226 * we do the same here.
1227 * - We currently use an 'approximate' method for getting these F-Curves that doesn't require
1228 * carefully checking the entire path.
1229 * - This will also affect things like Drivers, and also works for Bone Constraints.
1230 */
1231 if (ac->ads && owner_id) {
1232 if ((filter_mode & ANIMFILTER_TMP_IGNORE_ONLYSEL) == 0) {
1233 if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) ||
1235 {
1236 if (skip_fcurve_selected_data(ac, fcu, owner_id, filter_mode)) {
1237 continue;
1238 }
1239 }
1240 }
1241 }
1242
1243 /* only include if visible (Graph Editor check, not channels check) */
1244 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || (fcu->flag & FCURVE_VISIBLE)) {
1245 /* only work with this channel and its subchannels if it is editable */
1246 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_FCU(fcu)) {
1247 /* Only include this curve if selected in a way consistent
1248 * with the filtering requirements. */
1250 /* only include if this curve is active */
1251 if (!(filter_mode & ANIMFILTER_ACTIVE) || (fcu->flag & FCURVE_ACTIVE)) {
1252 /* name based filtering... */
1253 if (((ac->ads) && (ac->ads->searchstr[0] != '\0')) && (owner_id)) {
1254 if (skip_fcurve_with_name(ac, fcu, channel_type, owner, owner_id)) {
1255 continue;
1256 }
1257 }
1258
1259 /* error-based filtering... */
1260 if ((ac->ads) && (ac->ads->filterflag & ADS_FILTER_ONLY_ERRORS)) {
1261 /* skip if no errors... */
1262 if (!fcurve_has_errors(ac, fcu)) {
1263 continue;
1264 }
1265 }
1266
1267 /* this F-Curve can be used, so return it */
1268 return fcu;
1269 }
1270 }
1271 }
1272 }
1273 }
1274
1275 /* no (more) F-Curves from the list are suitable... */
1276 return nullptr;
1277}
1278
1280 ListBase *anim_data,
1281 FCurve *first,
1282 eAnim_ChannelType fcurve_type,
1283 const eAnimFilter_Flags filter_mode,
1284 void *owner,
1285 ID *owner_id,
1286 ID *fcurve_owner_id)
1287{
1288 FCurve *fcu;
1289 size_t items = 0;
1290
1291 /* Loop over every F-Curve able to be included.
1292 *
1293 * This for-loop works like this:
1294 * 1) The starting F-Curve is assigned to the fcu pointer
1295 * so that we have a starting point to search from.
1296 * 2) The first valid F-Curve to start from (which may include the one given as 'first')
1297 * in the remaining list of F-Curves is found, and verified to be non-null.
1298 * 3) The F-Curve referenced by fcu pointer is added to the list
1299 * 4) The fcu pointer is set to the F-Curve after the one we just added,
1300 * so that we can keep going through the rest of the F-Curve list without an eternal loop.
1301 * Back to step 2 :)
1302 */
1303 for (fcu = first;
1304 (fcu = animfilter_fcurve_next(ac, fcu, fcurve_type, filter_mode, owner, owner_id));
1305 fcu = fcu->next)
1306 {
1307 if (UNLIKELY(fcurve_type == ANIMTYPE_NLACURVE)) {
1308 /* NLA Control Curve - Basically the same as normal F-Curves,
1309 * except we need to set some stuff differently */
1310 ANIMCHANNEL_NEW_CHANNEL_FULL(ac->bmain, fcu, ANIMTYPE_NLACURVE, owner_id, fcurve_owner_id, {
1311 ale->owner = owner; /* strip */
1312 /* Since #130440 landed, this should now in theory be something like
1313 * `ale->adt = BKE_animdata_from_id(owner_id)`, rather than a nullptr.
1314 * However, at the moment the nullptr doesn't hurt, and it helps us
1315 * catch bugs like #147803 via the assert in `fcurve_to_keylist()`. If
1316 * the nullptr does start to hurt at some point, please change it! */
1317 ale->adt = nullptr;
1318 });
1319 }
1320 else {
1321 /* Normal FCurve */
1322 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, fcu, ANIMTYPE_FCURVE, owner_id, fcurve_owner_id);
1323 }
1324 }
1325
1326 /* return the number of items added to the list */
1327 return items;
1328}
1329
1330static inline bool fcurve_span_selection_matters(const eAnimFilter_Flags filter_mode)
1331{
1332 /* This means that ANIMFILTER_SELEDIT only works if ANIMFILTER_FOREDIT is also set. Given the
1333 * description on ANIMFILTER_SELEDIT this seems reasonable. */
1334 if ((filter_mode & ANIMFILTER_FOREDIT) && (filter_mode & ANIMFILTER_SELEDIT)) {
1335 return true;
1336 }
1337 return filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL);
1338}
1339
1340static inline bool fcurve_span_must_be_selected(const eAnimFilter_Flags filter_mode)
1341{
1342 if ((filter_mode & ANIMFILTER_FOREDIT) && (filter_mode & ANIMFILTER_SELEDIT)) {
1343 return true;
1344 }
1345 return filter_mode & ANIMFILTER_SEL;
1346}
1347
1364 ListBase * /*bAnimListElem*/ anim_data,
1365 Span<FCurve *> fcurves,
1366 const animrig::slot_handle_t slot_handle,
1367 const eAnimFilter_Flags filter_mode,
1368 ID *animated_id,
1369 ID *fcurve_owner_id)
1370{
1371 size_t num_items = 0;
1372 BLI_assert(animated_id);
1373
1374 const bool active_matters = filter_mode & ANIMFILTER_ACTIVE;
1375 const bool selection_matters = fcurve_span_selection_matters(filter_mode);
1376 const bool must_be_selected = fcurve_span_must_be_selected(filter_mode);
1377 const bool visibility_matters = filter_mode & ANIMFILTER_CURVE_VISIBLE;
1378 const bool editability_matters = filter_mode & ANIMFILTER_FOREDIT;
1379 const bool show_only_errors = ac->ads && (ac->ads->filterflag & ADS_FILTER_ONLY_ERRORS);
1380 const bool filter_by_name = ac->ads && (ac->ads->searchstr[0] != '\0');
1381
1382 for (FCurve *fcu : fcurves) {
1383 /* make_new_animlistelem will return nullptr when fcu == nullptr, and that's
1384 * going to cause problems. */
1385 BLI_assert(fcu);
1386
1387 if (editability_matters && (fcu->flag & FCURVE_PROTECTED)) {
1388 continue;
1389 }
1390
1391 if (selection_matters && bool(fcu->flag & FCURVE_SELECTED) != must_be_selected) {
1392 continue;
1393 }
1394 if (active_matters && !(fcu->flag & FCURVE_ACTIVE)) {
1395 continue;
1396 }
1397 if (visibility_matters && !(fcu->flag & FCURVE_VISIBLE)) {
1398 continue;
1399 }
1400 if (show_only_errors && !fcurve_has_errors(ac, fcu)) {
1401 continue;
1402 }
1403 if (skip_fcurve_selected_data(ac, fcu, animated_id, filter_mode)) {
1404 continue;
1405 }
1406
1408 ac->bmain, fcu, ANIMTYPE_FCURVE, animated_id, fcurve_owner_id);
1409
1410 /* Filtering by name needs a way to look up the name, which is easiest if
1411 * there is already an #bAnimListElem. */
1412 if (filter_by_name && !ale_name_matches_dopesheet_filter(*ac->ads, *ale)) {
1413 MEM_freeN(ale);
1414 continue;
1415 }
1416
1417 if (filter_mode & ANIMFILTER_TMP_PEEK) {
1418 /* Found an animation channel, which is good enough for the 'TMP_PEEK' mode. */
1419 MEM_freeN(ale);
1420 return 1;
1421 }
1422
1423 /* bAnimListElem::slot_handle is exposed as int32_t and not as slot_handle_t, so better
1424 * ensure that these are still equivalent.
1425 * TODO: move to another part of the code. */
1426 static_assert(
1427 std::is_same_v<decltype(ActionSlot::handle), decltype(bAnimListElem::slot_handle)>);
1428
1429 /* Note that this might not be the same as ale->adt->slot_handle. The reason this F-Curve is
1430 * shown could be because it's in the Action editor, showing ale->adt->action with _all_
1431 * slots, and this F-Curve could be from a different slot than what's used by the owner
1432 * of `ale->adt`. */
1433 ale->slot_handle = slot_handle;
1434
1435 BLI_addtail(anim_data, ale);
1436 num_items++;
1437 }
1438
1439 return num_items;
1440}
1441
1451 ListBase *anim_data,
1452 bAction *act,
1453 animrig::slot_handle_t slot_handle,
1454 bActionGroup *agrp,
1455 eAnimFilter_Flags filter_mode,
1456 ID *owner_id)
1457{
1458 BLI_assert(act != nullptr);
1459 BLI_assert(agrp != nullptr);
1460
1461 ListBase tmp_data = {nullptr, nullptr};
1462 size_t tmp_items = 0;
1463 size_t items = 0;
1464
1465 animrig::Action &action = act->wrap();
1466
1467 /* if we care about the selection status of the channels,
1468 * but the group isn't expanded (1)...
1469 * (1) this only matters if we actually care about the hierarchy though.
1470 * - Hierarchy matters: this hack should be applied
1471 * - Hierarchy ignored: cases like #21276 won't work properly, unless we skip this hack
1472 */
1473 if (
1474 /* Care about hierarchy but group isn't expanded. */
1475 ((filter_mode & ANIMFILTER_LIST_VISIBLE) && EXPANDED_AGRP(ac, agrp) == 0) &&
1476 /* Care about selection status. */
1477 (filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)))
1478 {
1479 /* If the group itself isn't selected appropriately,
1480 * we shouldn't consider its children either. */
1481 if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp)) == 0) {
1482 return 0;
1483 }
1484
1485 /* if we're still here,
1486 * then the selection status of the curves within this group should not matter,
1487 * since this creates too much overhead for animators (i.e. making a slow workflow).
1488 *
1489 * Tools affected by this at time of coding (2010 Feb 09):
1490 * - Inserting keyframes on selected channels only.
1491 * - Pasting keyframes.
1492 * - Creating ghost curves in Graph Editor.
1493 */
1495 }
1496
1497 /* add grouped F-Curves */
1499 /* special filter so that we can get just the F-Curves within the active group */
1500 if (!(filter_mode & ANIMFILTER_ACTGROUPED) || (agrp->flag & AGRP_ACTIVE)) {
1501 /* for the Graph Editor, curves may be set to not be visible in the view to lessen
1502 * clutter, but to do this, we need to check that the group doesn't have its
1503 * not-visible flag set preventing all its sub-curves to be shown
1504 */
1505 if (!(filter_mode & ANIMFILTER_CURVE_VISIBLE) || !(agrp->flag & AGRP_NOTVISIBLE)) {
1506 /* group must be editable for its children to be editable (if we care about this) */
1507 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_AGRP(agrp)) {
1508 /* Filter the fcurves in this group, adding them to the temporary
1509 * filter list. */
1510 if (action.is_action_legacy()) {
1511 /* get first F-Curve which can be used here */
1512 FCurve *first_fcu = animfilter_fcurve_next(ac,
1513 static_cast<FCurve *>(agrp->channels.first),
1515 filter_mode,
1516 agrp,
1517 owner_id);
1518
1519 /* filter list, starting from this F-Curve */
1520 tmp_items += animfilter_fcurves(
1521 ac, &tmp_data, first_fcu, ANIMTYPE_FCURVE, filter_mode, agrp, owner_id, &act->id);
1522 }
1523 else {
1524 BLI_assert(agrp->channelbag != nullptr);
1525 Span<FCurve *> fcurves = agrp->wrap().fcurves();
1526 tmp_items += animfilter_fcurves_span(
1527 ac, &tmp_data, fcurves, slot_handle, filter_mode, owner_id, &act->id);
1528 }
1529 }
1530 }
1531 }
1532 }
1534
1535 /* did we find anything? */
1536 if (tmp_items) {
1537 /* add this group as a channel first */
1538 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1539 /* filter selection of channel specially here again,
1540 * since may be open and not subject to previous test */
1541 if (ANIMCHANNEL_SELOK(SEL_AGRP(agrp))) {
1542 if (action.is_action_legacy()) {
1543 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, agrp, ANIMTYPE_GROUP, owner_id, &act->id);
1544 }
1545 else {
1546 ANIMCHANNEL_NEW_CHANNEL_FULL(ac->bmain, agrp, ANIMTYPE_GROUP, owner_id, &act->id, {
1547 ale->slot_handle = slot_handle;
1548 });
1549 }
1550 }
1551 }
1552
1553 /* now add the list of collected channels */
1554 BLI_movelisttolist(anim_data, &tmp_data);
1556 items += tmp_items;
1557 }
1558
1559 /* return the number of items added to the list */
1560 return items;
1561}
1562
1564 ListBase * /* bAnimListElem */ anim_data,
1565 animrig::Action &action,
1566 animrig::Slot &slot,
1567 const eAnimFilter_Flags filter_mode,
1568 ID *animated_id)
1569{
1570 BLI_assert(ac);
1571
1572 /* In some cases (see `ob_to_keylist()` and friends) fake bDopeSheet and fake bAnimContext are
1573 * created. These are mostly null-initialized, and so do not have a bmain. This means that
1574 * lookup of the animated ID is not possible, which can result in failure to look up the proper
1575 * F-Curve display name. For the `..._to_keylist` functions that doesn't matter, as those are
1576 * only interested in the key data anyway. So rather than trying to get a reliable `bmain`
1577 * through the maze, this code just treats it as optional (even though ideally it should always
1578 * be known). */
1579 ID *slot_user_id = nullptr;
1580 if (ac->bmain) {
1581 slot_user_id = animrig::action_slot_get_id_best_guess(*ac->bmain, slot, animated_id);
1582 }
1583 if (!slot_user_id) {
1584 BLI_assert(animated_id);
1585 /* At the time of writing this (PR #134922), downstream code (see e.g.
1586 * `animfilter_fcurves_span()`) assumes this is non-null, so we need to set
1587 * it to *something*. If it's not an actual user of the slot then channels
1588 * might not resolve to an actual property and thus be displayed oddly in
1589 * the channel list, but that's not technically a problem, it's just a
1590 * little strange for the end user. */
1591 slot_user_id = animated_id;
1592 }
1593
1594 /* Don't include anything from this animation if it is linked in from another
1595 * file, and we're getting stuff for editing... */
1596 if ((filter_mode & ANIMFILTER_FOREDIT) &&
1597 (ID_IS_LINKED(&action) || ID_IS_OVERRIDE_LIBRARY(&action)))
1598 {
1599 return 0;
1600 }
1601
1602 const bool selection_matters = filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL);
1603 const bool must_be_selected = filter_mode & ANIMFILTER_SEL;
1604 const bool selection_ok_for_slot = !selection_matters || slot.is_selected() == must_be_selected;
1605
1606 int items = 0;
1607
1608 /* Add a list element for the Slot itself, but only if in Action mode. The Dopesheet mode
1609 * shouldn't display Slots, as F-Curves are always shown in the context of the animated ID
1610 * anyway. */
1611 const bool is_action_mode = (ac->spacetype == SPACE_ACTION &&
1613 const bool show_active_group_only = filter_mode & ANIMFILTER_ACTGROUPED;
1614 const bool include_summary_channels = (filter_mode & ANIMFILTER_LIST_CHANNELS);
1615 const bool show_slot_channel = (is_action_mode && selection_ok_for_slot &&
1616 include_summary_channels);
1617 if (show_slot_channel) {
1618 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, &slot, ANIMTYPE_ACTION_SLOT, slot_user_id, &action.id);
1619 items++;
1620 }
1621
1622 /* If the 'list visible' flag is used, the expansion state of the Slot
1623 * matters. Otherwise the sub-channels can always be listed. */
1624 const bool visible_only = (filter_mode & ANIMFILTER_LIST_VISIBLE);
1625 const bool expansion_is_ok = !visible_only || !show_slot_channel || slot.is_expanded();
1626
1628 if (channelbag == nullptr) {
1629 return items;
1630 }
1631
1632 if (!expansion_is_ok) {
1633 return items;
1634 }
1635
1636 /* Add channel groups and their member channels. */
1637 for (bActionGroup *group : channelbag->channel_groups()) {
1638 items += animfilter_act_group(
1639 ac, anim_data, &action, slot.handle, group, filter_mode, slot_user_id);
1640 }
1641
1642 /* Add ungrouped channels. */
1643 if (!show_active_group_only) {
1644 int first_ungrouped_fcurve_index = 0;
1645 if (!channelbag->channel_groups().is_empty()) {
1646 const bActionGroup *last_group = channelbag->channel_groups().last();
1647 first_ungrouped_fcurve_index = last_group->fcurve_range_start +
1648 last_group->fcurve_range_length;
1649 }
1650
1651 Span<FCurve *> fcurves = channelbag->fcurves().drop_front(first_ungrouped_fcurve_index);
1652 items += animfilter_fcurves_span(
1653 ac, anim_data, fcurves, slot.handle, filter_mode, slot_user_id, &action.id);
1654 }
1655
1656 return items;
1657}
1658
1660 ListBase *anim_data,
1661 animrig::Action &action,
1662 const eAnimFilter_Flags filter_mode,
1663 ID *owner_id)
1664{
1665 /* Don't include anything from this animation if it is linked in from another
1666 * file, and we're getting stuff for editing... */
1667 if ((filter_mode & ANIMFILTER_FOREDIT) &&
1668 (ID_IS_LINKED(&action) || ID_IS_OVERRIDE_LIBRARY(&action)))
1669 {
1670 return 0;
1671 }
1672
1673 int num_items = 0;
1674 for (animrig::Slot *slot : action.slots()) {
1675 BLI_assert(slot);
1676
1677 num_items += ANIM_animfilter_action_slot(ac, anim_data, action, *slot, filter_mode, owner_id);
1678 }
1679
1680 return num_items;
1681}
1682
1684 ListBase *anim_data,
1685 animrig::Action &action,
1686 const animrig::slot_handle_t slot_handle,
1687 const eAnimFilter_Flags filter_mode,
1688 ID *owner_id)
1689{
1690 FCurve *lastchan = nullptr;
1691 size_t items = 0;
1692
1693 if (action.is_empty()) {
1694 return 0;
1695 }
1696
1697 /* don't include anything from this action if it is linked in from another file,
1698 * and we're getting stuff for editing...
1699 */
1700 if ((filter_mode & ANIMFILTER_FOREDIT) &&
1701 (!ID_IS_EDITABLE(&action) || ID_IS_OVERRIDE_LIBRARY(&action)))
1702 {
1703 return 0;
1704 }
1705
1706 if (action.is_action_legacy()) {
1707 LISTBASE_FOREACH (bActionGroup *, agrp, &action.groups) {
1708 /* Store reference to last channel of group. */
1709 if (agrp->channels.last) {
1710 lastchan = static_cast<FCurve *>(agrp->channels.last);
1711 }
1712
1713 items += animfilter_act_group(
1714 ac, anim_data, &action, animrig::Slot::unassigned, agrp, filter_mode, owner_id);
1715 }
1716
1717 /* Un-grouped F-Curves (only if we're not only considering those channels in
1718 * the active group) */
1719 if (!(filter_mode & ANIMFILTER_ACTGROUPED)) {
1720 FCurve *firstfcu = (lastchan) ? (lastchan->next) :
1721 static_cast<FCurve *>(action.curves.first);
1722 items += animfilter_fcurves(
1723 ac, anim_data, firstfcu, ANIMTYPE_FCURVE, filter_mode, nullptr, owner_id, &action.id);
1724 }
1725
1726 return items;
1727 }
1728
1729 /* For now we don't show layers anywhere, just the contained F-Curves. */
1730
1731 /* Only show all Slots in Action editor mode. Otherwise the F-Curves ought to be displayed
1732 * underneath their animated ID anyway. */
1733 const bool is_action_mode = (ac->spacetype == SPACE_ACTION &&
1735 const bool show_active_only = (ac->ads->filterflag & ADS_FILTER_ONLY_SLOTS_OF_ACTIVE);
1736 if (is_action_mode && !show_active_only) {
1737 return animfilter_action_slots(ac, anim_data, action, filter_mode, owner_id);
1738 }
1739
1740 animrig::Slot *slot = action.slot_for_handle(slot_handle);
1741 if (!slot) {
1742 /* Can happen when an Action is assigned, but not a Slot. */
1743 return 0;
1744 }
1745 return ANIM_animfilter_action_slot(ac, anim_data, action, *slot, filter_mode, owner_id);
1746}
1747
1748/* Include NLA-Data for NLA-Editor:
1749 * - When ANIMFILTER_LIST_CHANNELS is used, that means we should be filtering the list for display
1750 * Although the evaluation order is from the first track to the last and then apply the
1751 * Action on top, we present this in the UI as the Active Action followed by the last track
1752 * to the first so that we get the evaluation order presented as per a stack.
1753 * - For normal filtering (i.e. for editing),
1754 * we only need the NLA-tracks but they can be in 'normal' evaluation order, i.e. first to last.
1755 * Otherwise, some tools may get screwed up.
1756 */
1758 ListBase *anim_data,
1759 AnimData *adt,
1760 const eAnimFilter_Flags filter_mode,
1761 ID *owner_id)
1762{
1763 NlaTrack *nlt;
1764 NlaTrack *first = nullptr, *next = nullptr;
1765 size_t items = 0;
1766
1767 /* if showing channels, include active action */
1768 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1769 /* if NLA action-line filtering is off, don't show unless there are keyframes,
1770 * in order to keep things more compact for doing transforms
1771 */
1772 if (!(ac->ads->filterflag & ADS_FILTER_NLA_NOACT) || (adt->action)) {
1773 /* there isn't really anything editable here, so skip if need editable */
1774 if ((filter_mode & ANIMFILTER_FOREDIT) == 0) {
1775 /* Just add the action track now (this MUST appear for drawing):
1776 * - As AnimData may not have an action,
1777 * we pass a dummy pointer just to get the list elem created,
1778 * then overwrite this with the real value - REVIEW THIS.
1779 */
1781 ac->bmain, (void *)(&adt->action), ANIMTYPE_NLAACTION, owner_id, nullptr, {
1782 ale->data = adt->action ? adt->action : nullptr;
1783 });
1784 }
1785 }
1786
1787 /* first track to include will be the last one if we're filtering by channels */
1788 first = static_cast<NlaTrack *>(adt->nla_tracks.last);
1789 }
1790 else {
1791 /* first track to include will the first one (as per normal) */
1792 first = static_cast<NlaTrack *>(adt->nla_tracks.first);
1793 }
1794
1795 /* loop over NLA Tracks -
1796 * assume that the caller of this has already checked that these should be included */
1797 for (nlt = first; nlt; nlt = next) {
1798 /* 'next' NLA-Track to use depends on whether we're filtering for drawing or not */
1799 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1800 next = nlt->prev;
1801 }
1802 else {
1803 next = nlt->next;
1804 }
1805
1806 /* only work with this channel and its subchannels if it is editable */
1807 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_NLT(nlt)) {
1808 /* only include this track if selected in a way consistent with the filtering requirements */
1809 if (ANIMCHANNEL_SELOK(SEL_NLT(nlt))) {
1810 /* only include if this track is active */
1811 if (!(filter_mode & ANIMFILTER_ACTIVE) || (nlt->flag & NLATRACK_ACTIVE)) {
1812 /* name based filtering... */
1813 if (((ac->ads) && (ac->ads->searchstr[0] != '\0')) && (owner_id)) {
1814 bool track_ok = false, strip_ok = false;
1815
1816 /* check if the name of the track, or the strips it has are ok... */
1817 track_ok = name_matches_dopesheet_filter(ac->ads, nlt->name);
1818
1819 if (track_ok == false) {
1820 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
1821 if (name_matches_dopesheet_filter(ac->ads, strip->name)) {
1822 strip_ok = true;
1823 break;
1824 }
1825 }
1826 }
1827
1828 /* skip if both fail this test... */
1829 if (!track_ok && !strip_ok) {
1830 continue;
1831 }
1832 }
1833
1834 /* add the track now that it has passed all our tests */
1835 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, nlt, ANIMTYPE_NLATRACK, owner_id, nullptr);
1836 }
1837 }
1838 }
1839 }
1840
1841 /* return the number of items added to the list */
1842 return items;
1843}
1844
1845/* Include the control FCurves per NLA Strip in the channel list
1846 * NOTE: This is includes the expander too...
1847 */
1849 ListBase *anim_data,
1850 AnimData *adt,
1851 eAnimFilter_Flags filter_mode,
1852 ID *owner_id)
1853{
1854 ListBase tmp_data = {nullptr, nullptr};
1855 size_t tmp_items = 0;
1856 size_t items = 0;
1857
1858 /* add control curves from each NLA strip... */
1859 /* NOTE: ANIMTYPE_FCURVES are created here, to avoid duplicating the code needed */
1861 /* for now, we only go one level deep - so controls on grouped FCurves are not handled */
1863 LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
1864 /* pass strip as the "owner",
1865 * so that the name lookups (used while filtering) will resolve */
1866 /* NLA tracks are coming from AnimData, so owner of f-curves
1867 * is the same as owner of animation data. */
1868 tmp_items += animfilter_fcurves(ac,
1869 &tmp_data,
1870 static_cast<FCurve *>(strip->fcurves.first),
1872 filter_mode,
1873 strip,
1874 owner_id,
1875 owner_id);
1876 }
1877 }
1878 }
1880
1881 /* did we find anything? */
1882 if (tmp_items) {
1883 /* add the expander as a channel first */
1884 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1885 /* currently these channels cannot be selected, so they should be skipped */
1886 if ((filter_mode & (ANIMFILTER_SEL | ANIMFILTER_UNSEL)) == 0) {
1887 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, adt, ANIMTYPE_NLACONTROLS, owner_id, nullptr);
1888 }
1889 }
1890
1891 /* now add the list of collected channels */
1892 BLI_movelisttolist(anim_data, &tmp_data);
1894 items += tmp_items;
1895 }
1896
1897 /* return the number of items added to the list */
1898 return items;
1899}
1900
1901/* determine what animation data from AnimData block should get displayed */
1903 ListBase *anim_data,
1904 ID *id,
1905 const eAnimFilter_Flags filter_mode)
1906{
1908 size_t items = 0;
1909
1910 /* image object data-blocks have no anim-data so check for nullptr */
1911 if (adt) {
1912 IdAdtTemplate *iat = reinterpret_cast<IdAdtTemplate *>(id);
1913
1914 /* NOTE: this macro is used instead of inlining the logic here,
1915 * since this sort of filtering is still needed in a few places in the rest of the code still -
1916 * notably for the few cases where special mode-based
1917 * different types of data expanders are required.
1918 */
1920 iat,
1921 { /* AnimData */
1922 /* specifically filter animdata block */
1925 }
1926 },
1927 { /* NLA */
1928 items += animfilter_nla(ac, anim_data, adt, filter_mode, id);
1929 },
1930 { /* Drivers */
1931 items += animfilter_fcurves(ac,
1932 anim_data,
1933 static_cast<FCurve *>(adt->drivers.first),
1935 filter_mode,
1936 nullptr,
1937 id,
1938 id);
1939 },
1940 { /* NLA Control Keyframes */
1941 items += animfilter_nla_controls(ac, anim_data, adt, filter_mode, id);
1942 },
1943 { /* Keyframes from legacy Action. */
1944 items += animfilter_action(ac,
1945 anim_data,
1946 adt->action->wrap(),
1948 eAnimFilter_Flags(filter_mode),
1949 id);
1950 },
1951 { /* Keyframes from layered Action. */
1952 items += animfilter_action(ac,
1953 anim_data,
1954 adt->action->wrap(),
1956 eAnimFilter_Flags(filter_mode),
1957 id);
1958 });
1959 }
1960
1961 return items;
1962}
1963
1964/* Include ShapeKey Data for ShapeKey Editor */
1966 ListBase *anim_data,
1967 Key *key,
1968 const eAnimFilter_Flags filter_mode)
1969{
1970 using namespace blender::animrig;
1971
1972 size_t items = 0;
1973
1974 /* check if channels or only F-Curves */
1975 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
1976 bDopeSheet *ads = ac->ads;
1977
1978 if (key->type == KEY_RELATIVE) {
1979 /* TODO: This currently doesn't take into account the animatable "Range Min/Max" keys on the
1980 * key-blocks. */
1981
1982 /* loop through the channels adding ShapeKeys as appropriate */
1983 LISTBASE_FOREACH (KeyBlock *, kb, &key->block) {
1984 /* skip the first one, since that's the non-animatable basis */
1985 if (kb == key->block.first) {
1986 continue;
1987 }
1988
1989 /* Skip shapekey if the name doesn't match the filter string. */
1990 if (ads != nullptr && ads->searchstr[0] != '\0' &&
1991 name_matches_dopesheet_filter(ads, kb->name) == false)
1992 {
1993 continue;
1994 }
1995
1996 /* only work with this channel and its subchannels if it is editable */
1997 if (!(filter_mode & ANIMFILTER_FOREDIT) || EDITABLE_SHAPEKEY(kb)) {
1998 /* Only include this track if selected in a way consistent
1999 * with the filtering requirements. */
2001 /* TODO: consider 'active' too? */
2002
2003 /* owner-id here must be key so that the F-Curve can be resolved... */
2004 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, kb, ANIMTYPE_SHAPEKEY, key, nullptr);
2005 }
2006 }
2007 }
2008 }
2009 else {
2010 /* key->type == KEY_NORMAL */
2011 if (!key->adt || !key->adt->action) {
2012 return 0;
2013 }
2014 Action &action = key->adt->action->wrap();
2015
2016 Vector<FCurve *> key_fcurves;
2017 for (FCurve *fcurve : fcurves_for_action_slot(action, key->adt->slot_handle)) {
2018 if (STREQ(fcurve->rna_path, "eval_time") ||
2019 BLI_str_endswith(fcurve->rna_path, ".interpolation"))
2020 {
2021 key_fcurves.append(fcurve);
2022 }
2023 }
2024
2025 items += animfilter_fcurves_span(
2026 ac, anim_data, key_fcurves, key->adt->slot_handle, filter_mode, &key->id, &action.id);
2027 }
2028 }
2029 else {
2030 /* just use the action associated with the shapekey */
2031 /* TODO: somehow manage to pass dopesheet info down here too? */
2032 if (key->adt) {
2033 if (filter_mode & ANIMFILTER_ANIMDATA) {
2034 if (ANIMCHANNEL_SELOK(SEL_ANIMDATA(key->adt))) {
2035 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, key->adt, ANIMTYPE_ANIMDATA, key, nullptr);
2036 }
2037 }
2038 else if (key->adt->action) {
2039 items = animfilter_action(ac,
2040 anim_data,
2041 key->adt->action->wrap(),
2042 key->adt->slot_handle,
2043 eAnimFilter_Flags(filter_mode),
2044 reinterpret_cast<ID *>(key));
2045 }
2046 }
2047 }
2048
2049 /* return the number of items added to the list */
2050 return items;
2051}
2052
2053/* Helper for Grease Pencil - layers within a data-block. */
2054
2056 ListBase *anim_data,
2057 GreasePencil *grease_pencil,
2059 const eAnimFilter_Flags filter_mode)
2060{
2061
2062 size_t items = 0;
2063
2064 /* Only if the layer is selected. */
2065 if (!ANIMCHANNEL_SELOK(layer.is_selected())) {
2066 return items;
2067 }
2068
2069 /* Only if the layer is editable. */
2070 if ((filter_mode & ANIMFILTER_FOREDIT) && layer.is_locked()) {
2071 return items;
2072 }
2073
2074 /* Only if the layer is active. */
2075 if ((filter_mode & ANIMFILTER_ACTIVE) && grease_pencil->is_layer_active(&layer)) {
2076 return items;
2077 }
2078
2079 /* Skip empty layers. */
2080 if (layer.is_empty()) {
2081 return items;
2082 }
2083
2084 /* Add layer channel. */
2086 static_cast<void *>(&layer),
2088 grease_pencil,
2089 nullptr);
2090
2091 return items;
2092}
2093
2095 bAnimContext *ac,
2096 ListBase *anim_data,
2097 GreasePencil *grease_pencil,
2099 eAnimFilter_Flags filter_mode)
2100{
2101 using namespace blender::bke::greasepencil;
2102 size_t items = 0;
2103
2104 /* Skip node if the name doesn't match the filter string. */
2105 const bool name_search = (ac->ads->searchstr[0] != '\0');
2106 const bool skip_node = name_search &&
2107 !name_matches_dopesheet_filter(ac->ads, node.name().c_str());
2108
2109 if (node.is_layer() && !skip_node) {
2111 ac, anim_data, grease_pencil, node.as_layer(), filter_mode);
2112 }
2113 else if (node.is_group()) {
2114 const LayerGroup &layer_group = node.as_group();
2115
2116 ListBase tmp_data = {nullptr, nullptr};
2117 size_t tmp_items = 0;
2118
2119 /* Add grease pencil layer channels. */
2123 ac, &tmp_data, grease_pencil, node_->wrap(), filter_mode);
2124 }
2125 }
2127
2128 if ((tmp_items == 0) && !name_search) {
2129 /* If no sub-channels, return early.
2130 * Except if the search by name is on, because we might want to display the layer group alone
2131 * in that case. */
2132 return items;
2133 }
2134
2135 if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !skip_node) {
2136 /* Add data block container (if for drawing, and it contains sub-channels). */
2138 static_cast<void *>(&node),
2140 grease_pencil,
2141 nullptr);
2142 }
2143
2144 /* Add the list of collected channels. */
2145 BLI_movelisttolist(anim_data, &tmp_data);
2147 items += tmp_items;
2148 }
2149 return items;
2150}
2151
2153 ListBase *anim_data,
2154 GreasePencil *grease_pencil,
2155 const eAnimFilter_Flags filter_mode)
2156{
2157 size_t items = 0;
2158
2160 GreasePencilLayerTreeNode *, node, &grease_pencil->root_group_ptr->children)
2161 {
2163 ac, anim_data, grease_pencil, node->wrap(), filter_mode);
2164 }
2165
2166 return items;
2167}
2168
2169/* Helper for Grease Pencil - layers within a data-block. */
2171 ListBase *anim_data,
2172 bGPdata *gpd,
2173 const eAnimFilter_Flags filter_mode)
2174{
2175 size_t items = 0;
2176
2177 /* loop over layers as the conditions are acceptable (top-Down order) */
2179 /* only if selected */
2180 if (!ANIMCHANNEL_SELOK(SEL_GPL(gpl))) {
2181 continue;
2182 }
2183
2184 /* only if editable */
2185 if ((filter_mode & ANIMFILTER_FOREDIT) && !EDITABLE_GPL(gpl)) {
2186 continue;
2187 }
2188
2189 /* active... */
2190 if ((filter_mode & ANIMFILTER_ACTIVE) && (gpl->flag & GP_LAYER_ACTIVE) == 0) {
2191 continue;
2192 }
2193
2194 /* skip layer if the name doesn't match the filter string */
2195 if (ac->ads != nullptr && ac->ads->searchstr[0] != '\0' &&
2196 name_matches_dopesheet_filter(ac->ads, gpl->info) == false)
2197 {
2198 continue;
2199 }
2200
2201 /* Skip empty layers. */
2202 if (BLI_listbase_is_empty(&gpl->frames)) {
2203 continue;
2204 }
2205
2206 /* add to list */
2207 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, gpl, ANIMTYPE_GPLAYER, gpd, nullptr);
2208 }
2209
2210 return items;
2211}
2212
2214 ListBase *anim_data,
2215 GreasePencil *grease_pencil,
2216 eAnimFilter_Flags filter_mode)
2217{
2218 using namespace blender;
2219
2220 size_t items = 0;
2221
2222 /* The Grease Pencil mode is not supposed to show channels for regular F-Curves from regular
2223 * Actions. At some point this might be desirable, but it would also require changing the
2224 * filtering flags for pretty much all operators running there. */
2225 const bool show_animdata = grease_pencil->adt && (ac->datatype != ANIMCONT_GPENCIL);
2226
2227 /* When asked from "AnimData" blocks (i.e. the top-level containers for normal animation),
2228 * for convenience, this will return grease pencil data-blocks instead.
2229 * This may cause issues down the track, but for now, this will do.
2230 */
2231 if (filter_mode & ANIMFILTER_ANIMDATA) {
2232 if (show_animdata) {
2233 items += animfilter_block_data(
2234 ac, anim_data, reinterpret_cast<ID *>(grease_pencil), filter_mode);
2235 }
2236 }
2237 else {
2238 ListBase tmp_data = {nullptr, nullptr};
2239 size_t tmp_items = 0;
2240
2241 /* Add grease pencil layer channels. */
2243 if (show_animdata) {
2244 tmp_items += animfilter_block_data(
2245 ac, &tmp_data, reinterpret_cast<ID *>(grease_pencil), filter_mode);
2246 }
2247
2248 if (!(filter_mode & ANIMFILTER_FCURVESONLY)) {
2250 ac, &tmp_data, grease_pencil, filter_mode);
2251 }
2252 }
2254
2255 if (tmp_items == 0) {
2256 /* If no sub-channels, return early. */
2257 return items;
2258 }
2259
2260 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2261 /* Add data block container (if for drawing, and it contains sub-channels). */
2263 ac->bmain, grease_pencil, ANIMTYPE_GREASE_PENCIL_DATABLOCK, grease_pencil, nullptr);
2264 }
2265
2266 /* Add the list of collected channels. */
2267 BLI_movelisttolist(anim_data, &tmp_data);
2269 items += tmp_items;
2270 }
2271
2272 return items;
2273}
2274
2276 ListBase *anim_data,
2277 const eAnimFilter_Flags filter_mode)
2278{
2279 size_t items = 0;
2280 Scene *scene = ac->scene;
2281 ViewLayer *view_layer = ac->view_layer;
2282 bDopeSheet *ads = ac->ads;
2283
2284 BKE_view_layer_synced_ensure(scene, view_layer);
2286 if (!base->object || (base->object->type != OB_GREASE_PENCIL)) {
2287 continue;
2288 }
2289 Object *ob = base->object;
2290
2291 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ac->ads->filterflag & ADS_FILTER_INCL_HIDDEN))
2292 {
2293 /* Layer visibility - we check both object and base,
2294 * since these may not be in sync yet. */
2295 if ((base->flag & BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT) == 0 ||
2297 {
2298 continue;
2299 }
2300
2301 /* Outliner restrict-flag */
2303 continue;
2304 }
2305 }
2306
2307 /* Check selection and object type filters */
2308 if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) && !(base->flag & BASE_SELECTED)) {
2309 /* Only selected should be shown */
2310 continue;
2311 }
2312
2313 if (ads->filter_grp != nullptr) {
2315 continue;
2316 }
2317 }
2318
2320 ac, anim_data, static_cast<GreasePencil *>(ob->data), filter_mode);
2321 }
2322
2323 /* Return the number of items added to the list */
2324 return items;
2325}
2326
2327/* Helper for Grease Pencil data integrated with main DopeSheet */
2329 ListBase *anim_data,
2330 bGPdata *gpd,
2331 eAnimFilter_Flags filter_mode)
2332{
2333 ListBase tmp_data = {nullptr, nullptr};
2334 size_t tmp_items = 0;
2335 size_t items = 0;
2336
2337 /* add relevant animation channels for Grease Pencil */
2339 /* add animation channels */
2340 tmp_items += animfilter_block_data(ac, &tmp_data, &gpd->id, filter_mode);
2341
2342 /* add Grease Pencil layers */
2343 if (!(filter_mode & ANIMFILTER_FCURVESONLY)) {
2344 tmp_items += animdata_filter_gpencil_layers_data_legacy(ac, &tmp_data, gpd, filter_mode);
2345 }
2346
2347 /* TODO: do these need a separate expander?
2348 * XXX: what order should these go in? */
2349 }
2351
2352 /* did we find anything? */
2353 if (tmp_items) {
2354 /* include data-expand widget first */
2355 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2356 /* check if filtering by active status */
2357 /* XXX: active check here needs checking */
2358 if (ANIMCHANNEL_ACTIVEOK(gpd)) {
2359 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, gpd, ANIMTYPE_DSGPENCIL, gpd, nullptr);
2360 }
2361 }
2362
2363 /* now add the list of collected channels */
2364 BLI_movelisttolist(anim_data, &tmp_data);
2366 items += tmp_items;
2367 }
2368
2369 /* return the number of items added to the list */
2370 return items;
2371}
2372
2373/* Helper for Cache File data integrated with main DopeSheet */
2375 ListBase *anim_data,
2376 CacheFile *cache_file,
2377 eAnimFilter_Flags filter_mode)
2378{
2379 ListBase tmp_data = {nullptr, nullptr};
2380 size_t tmp_items = 0;
2381 size_t items = 0;
2382
2383 /* add relevant animation channels for Cache File */
2385 /* add animation channels */
2386 tmp_items += animfilter_block_data(ac, &tmp_data, &cache_file->id, filter_mode);
2387 }
2389
2390 /* did we find anything? */
2391 if (tmp_items) {
2392 /* include data-expand widget first */
2393 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2394 /* check if filtering by active status */
2395 /* XXX: active check here needs checking */
2396 if (ANIMCHANNEL_ACTIVEOK(cache_file)) {
2397 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, cache_file, ANIMTYPE_DSCACHEFILE, cache_file, nullptr);
2398 }
2399 }
2400
2401 /* now add the list of collected channels */
2402 BLI_movelisttolist(anim_data, &tmp_data);
2404 items += tmp_items;
2405 }
2406
2407 /* return the number of items added to the list */
2408 return items;
2409}
2410
2411/* Helper for Mask Editing - mask layers */
2413 ListBase *anim_data,
2414 Mask *mask,
2415 const eAnimFilter_Flags filter_mode)
2416{
2418 size_t items = 0;
2419
2420 LISTBASE_FOREACH (MaskLayer *, masklay, &mask->masklayers) {
2421 if (!ANIMCHANNEL_SELOK(SEL_MASKLAY(masklay))) {
2422 continue;
2423 }
2424
2425 if ((filter_mode & ANIMFILTER_FOREDIT) && !EDITABLE_MASK(masklay)) {
2426 continue;
2427 }
2428
2429 if ((filter_mode & ANIMFILTER_ACTIVE) & (masklay_act != masklay)) {
2430 continue;
2431 }
2432
2433 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, masklay, ANIMTYPE_MASKLAYER, mask, nullptr);
2434 }
2435
2436 return items;
2437}
2438
2439/* Grab all mask data */
2441 ListBase *anim_data,
2442 void * /*data*/,
2443 eAnimFilter_Flags filter_mode)
2444{
2445 size_t items = 0;
2446
2447 /* For now, grab mask data-blocks directly from main. */
2448 /* XXX: this is not good... */
2449 LISTBASE_FOREACH (Mask *, mask, &ac->bmain->masks) {
2450 ListBase tmp_data = {nullptr, nullptr};
2451 size_t tmp_items = 0;
2452
2453 /* only show if mask is used by something... */
2454 if (ID_REAL_USERS(mask) < 1) {
2455 continue;
2456 }
2457
2458 /* add mask animation channels */
2459 if (!(filter_mode & ANIMFILTER_FCURVESONLY)) {
2461 tmp_items += animdata_filter_mask_data(ac, &tmp_data, mask, filter_mode);
2462 }
2464 }
2465
2466 /* did we find anything? */
2467 if (!tmp_items) {
2468 continue;
2469 }
2470
2471 /* include data-expand widget first */
2472 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2473 /* add mask data-block as channel too (if for drawing, and it has layers) */
2475 }
2476
2477 /* now add the list of collected channels */
2478 BLI_movelisttolist(anim_data, &tmp_data);
2480 items += tmp_items;
2481 }
2482
2483 /* return the number of items added to the list */
2484 return items;
2485}
2486
2487/* NOTE: owner_id is scene, material, or texture block,
2488 * which is the direct owner of the node tree in question. */
2490 ListBase *anim_data,
2491 ID *owner_id,
2492 bNodeTree *ntree,
2493 eAnimFilter_Flags filter_mode)
2494{
2495 ListBase tmp_data = {nullptr, nullptr};
2496 size_t tmp_items = 0;
2497 size_t items = 0;
2498
2499 /* add nodetree animation channels */
2501 /* animation data filtering */
2502 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(ntree), filter_mode);
2503 }
2505
2506 /* did we find anything? */
2507 if (tmp_items) {
2508 /* include data-expand widget first */
2509 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2510 /* check if filtering by active status */
2511 if (ANIMCHANNEL_ACTIVEOK(ntree)) {
2512 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, ntree, ANIMTYPE_DSNTREE, owner_id, nullptr);
2513 }
2514 }
2515
2516 /* now add the list of collected channels */
2517 BLI_movelisttolist(anim_data, &tmp_data);
2519 items += tmp_items;
2520 }
2521
2522 /* return the number of items added to the list */
2523 return items;
2524}
2525
2527 ListBase *anim_data,
2528 ID *owner_id,
2529 bNodeTree *ntree,
2530 const eAnimFilter_Flags filter_mode)
2531{
2532 size_t items = 0;
2533
2534 items += animdata_filter_ds_nodetree_group(ac, anim_data, owner_id, ntree, filter_mode);
2535
2536 for (bNode *node : ntree->all_nodes()) {
2537 if (node->is_group()) {
2538 if (node->id) {
2539 if ((ac->ads->filterflag & ADS_FILTER_ONLYSEL) && (node->flag & NODE_SELECT) == 0) {
2540 continue;
2541 }
2542 /* Recurse into the node group */
2543 items += animdata_filter_ds_nodetree(ac,
2544 anim_data,
2545 owner_id,
2546 reinterpret_cast<bNodeTree *>(node->id),
2547 filter_mode | ANIMFILTER_TMP_IGNORE_ONLYSEL);
2548 }
2549 }
2550 }
2551
2552 return items;
2553}
2554
2556 ListBase *anim_data,
2557 Scene *sce,
2558 eAnimFilter_Flags filter_mode)
2559{
2560 size_t items = 0;
2561
2562 LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) {
2563 LISTBASE_FOREACH (FreestyleLineSet *, lineset, &view_layer->freestyle_config.linesets) {
2564 if (lineset->linestyle) {
2565 lineset->linestyle->id.tag |= ID_TAG_DOIT;
2566 }
2567 }
2568 }
2569
2570 LISTBASE_FOREACH (ViewLayer *, view_layer, &sce->view_layers) {
2571 /* skip render layers without Freestyle enabled */
2572 if ((view_layer->flag & VIEW_LAYER_FREESTYLE) == 0) {
2573 continue;
2574 }
2575
2576 /* loop over linesets defined in the render layer */
2577 LISTBASE_FOREACH (FreestyleLineSet *, lineset, &view_layer->freestyle_config.linesets) {
2578 FreestyleLineStyle *linestyle = lineset->linestyle;
2579 ListBase tmp_data = {nullptr, nullptr};
2580 size_t tmp_items = 0;
2581
2582 if ((linestyle == nullptr) || !(linestyle->id.tag & ID_TAG_DOIT)) {
2583 continue;
2584 }
2585 linestyle->id.tag &= ~ID_TAG_DOIT;
2586
2587 /* add scene-level animation channels */
2589 /* animation data filtering */
2590 tmp_items += animfilter_block_data(
2591 ac, &tmp_data, reinterpret_cast<ID *>(linestyle), filter_mode);
2592 }
2594
2595 /* did we find anything? */
2596 if (tmp_items) {
2597 /* include anim-expand widget first */
2598 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2599 /* check if filtering by active status */
2600 if (ANIMCHANNEL_ACTIVEOK(linestyle)) {
2601 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, linestyle, ANIMTYPE_DSLINESTYLE, sce, nullptr);
2602 }
2603 }
2604
2605 /* now add the list of collected channels */
2606 BLI_movelisttolist(anim_data, &tmp_data);
2608 items += tmp_items;
2609 }
2610 }
2611 }
2612
2613 /* return the number of items added to the list */
2614 return items;
2615}
2616
2618 bAnimContext *ac, ListBase *anim_data, Tex *tex, ID *owner_id, eAnimFilter_Flags filter_mode)
2619{
2620 ListBase tmp_data = {nullptr, nullptr};
2621 size_t tmp_items = 0;
2622 size_t items = 0;
2623
2624 /* add texture's animation data to temp collection */
2626 /* texture animdata */
2627 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(tex), filter_mode);
2628
2629 /* nodes */
2630 if ((tex->nodetree) && !(ac->ads->filterflag & ADS_FILTER_NONTREE)) {
2631 /* owner_id as id instead of texture,
2632 * since it'll otherwise be impossible to track the depth. */
2633
2634 /* FIXME: perhaps as a result, textures should NOT be included under materials,
2635 * but under their own section instead so that free-floating textures can also be animated.
2636 */
2637 tmp_items += animdata_filter_ds_nodetree(
2638 ac, &tmp_data, reinterpret_cast<ID *>(tex), tex->nodetree, filter_mode);
2639 }
2640 }
2642
2643 /* did we find anything? */
2644 if (tmp_items) {
2645 /* include texture-expand widget? */
2646 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2647 /* check if filtering by active status */
2648 if (ANIMCHANNEL_ACTIVEOK(tex)) {
2649 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, tex, ANIMTYPE_DSTEX, owner_id, nullptr);
2650 }
2651 }
2652
2653 /* now add the list of collected channels */
2654 BLI_movelisttolist(anim_data, &tmp_data);
2656 items += tmp_items;
2657 }
2658
2659 /* return the number of items added to the list */
2660 return items;
2661}
2662
2663/* NOTE: owner_id is the direct owner of the texture stack in question
2664 * It used to be Material/Light/World before the Blender Internal removal for 2.8
2665 */
2667 ListBase *anim_data,
2668 ID *owner_id,
2669 const eAnimFilter_Flags filter_mode)
2670{
2671 MTex **mtex = nullptr;
2672 size_t items = 0;
2673 int a = 0;
2674
2675 /* get datatype specific data first */
2676 if (owner_id == nullptr) {
2677 return 0;
2678 }
2679
2680 switch (GS(owner_id->name)) {
2681 case ID_PA: {
2682 ParticleSettings *part = reinterpret_cast<ParticleSettings *>(owner_id);
2683 mtex = reinterpret_cast<MTex **>(&part->mtex);
2684 break;
2685 }
2686 default: {
2687 /* invalid/unsupported option */
2688 if (G.debug & G_DEBUG) {
2689 printf("ERROR: Unsupported owner_id (i.e. texture stack) for filter textures - %s\n",
2690 owner_id->name);
2691 }
2692 return 0;
2693 }
2694 }
2695
2696 /* Firstly check that we actually have some textures,
2697 * by gathering all textures in a temp list. */
2698 for (a = 0; a < MAX_MTEX; a++) {
2699 Tex *tex = (mtex[a]) ? mtex[a]->tex : nullptr;
2700
2701 /* for now, if no texture returned, skip (this shouldn't confuse the user I hope) */
2702 if (tex == nullptr) {
2703 continue;
2704 }
2705
2706 /* add texture's anim channels */
2707 items += animdata_filter_ds_texture(ac, anim_data, tex, owner_id, filter_mode);
2708 }
2709
2710 /* return the number of items added to the list */
2711 return items;
2712}
2713
2715 ListBase *anim_data,
2716 Material *ma,
2717 eAnimFilter_Flags filter_mode)
2718{
2719 ListBase tmp_data = {nullptr, nullptr};
2720 size_t tmp_items = 0;
2721 size_t items = 0;
2722
2723 /* add material's animation data to temp collection */
2725 /* material's animation data */
2726 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(ma), filter_mode);
2727
2728 /* nodes */
2729 if ((ma->nodetree) && !(ac->ads->filterflag & ADS_FILTER_NONTREE)) {
2730 tmp_items += animdata_filter_ds_nodetree(
2731 ac, &tmp_data, reinterpret_cast<ID *>(ma), ma->nodetree, filter_mode);
2732 }
2733 }
2735
2736 /* did we find anything? */
2737 if (tmp_items) {
2738 /* include material-expand widget first */
2739 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2740 /* check if filtering by active status */
2741 if (ANIMCHANNEL_ACTIVEOK(ma)) {
2742 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, ma, ANIMTYPE_DSMAT, ma, nullptr);
2743 }
2744 }
2745
2746 /* now add the list of collected channels */
2747 BLI_movelisttolist(anim_data, &tmp_data);
2749 items += tmp_items;
2750 }
2751
2752 return items;
2753}
2754
2756 ListBase *anim_data,
2757 Object *ob,
2758 const eAnimFilter_Flags filter_mode)
2759{
2760 size_t items = 0;
2761 int a = 0;
2762
2763 /* First pass: take the materials referenced via the Material slots of the object. */
2764 for (a = 1; a <= ob->totcol; a++) {
2765 Material *ma = BKE_object_material_get(ob, a);
2766
2767 /* if material is valid, try to add relevant contents from here */
2768 if (ma) {
2769 /* add channels */
2770 items += animdata_filter_ds_material(ac, anim_data, ma, filter_mode);
2771 }
2772 }
2773
2774 /* return the number of items added to the list */
2775 return items;
2776}
2777
2778/* ............ */
2779
2780/* Temporary context for modifier linked-data channel extraction */
2782 bAnimContext *ac; /* anim editor context */
2783 bDopeSheet *ads; /* TODO: Remove this pointer from the struct and just use ac->ads. */
2784
2785 ListBase tmp_data; /* list of channels created (but not yet added to the main list) */
2786 size_t items; /* number of channels created */
2787
2788 eAnimFilter_Flags filter_mode; /* flags for stuff we want to filter */
2789};
2790
2791/* dependency walker callback for modifier dependencies */
2792static void animfilter_modifier_idpoin_cb(void *afm_ptr,
2793 Object *ob,
2794 ID **idpoin,
2795 LibraryForeachIDCallbackFlag /*cb_flag*/)
2796{
2797 tAnimFilterModifiersContext *afm = static_cast<tAnimFilterModifiersContext *>(afm_ptr);
2798 ID *owner_id = &ob->id;
2799 ID *id = *idpoin;
2800
2801 /* NOTE: the walker only guarantees to give us all the ID-ptr *slots*,
2802 * not just the ones which are actually used, so be careful!
2803 */
2804 if (id == nullptr) {
2805 return;
2806 }
2807
2808 /* check if this is something we're interested in... */
2809 switch (GS(id->name)) {
2810 case ID_TE: /* Textures */
2811 {
2812 Tex *tex = reinterpret_cast<Tex *>(id);
2813 if (!(afm->ac->ads->filterflag & ADS_FILTER_NOTEX)) {
2814 BLI_assert(afm->ac->ads == afm->ads);
2816 afm->ac, &afm->tmp_data, tex, owner_id, afm->filter_mode);
2817 }
2818 break;
2819 }
2820 case ID_NT: {
2821 bNodeTree *node_tree = reinterpret_cast<bNodeTree *>(id);
2822 if (!(afm->ac->ads->filterflag & ADS_FILTER_NONTREE)) {
2823 BLI_assert(afm->ac->ads == afm->ads);
2825 afm->ac, &afm->tmp_data, owner_id, node_tree, afm->filter_mode);
2826 }
2827 }
2828
2829 /* TODO: images? */
2830 default:
2831 break;
2832 }
2833}
2834
2835/* animation linked to data used by modifiers
2836 * NOTE: strictly speaking, modifier animation is already included under Object level
2837 * but for some modifiers (e.g. Displace), there can be linked data that has settings
2838 * which would be nice to animate (i.e. texture parameters) but which are not actually
2839 * attached to any other objects/materials/etc. in the scene
2840 */
2841/* TODO: do we want an expander for this? */
2843 ListBase *anim_data,
2844 Object *ob,
2845 const eAnimFilter_Flags filter_mode)
2846{
2847 tAnimFilterModifiersContext afm = {nullptr};
2848 size_t items = 0;
2849
2850 /* 1) create a temporary "context" containing all the info we have here to pass to the callback
2851 * use to walk through the dependencies of the modifiers
2852 *
2853 * Assumes that all other unspecified values (i.e. accumulation buffers)
2854 * are zeroed out properly!
2855 */
2856 afm.ac = ac;
2857 afm.ads = ac->ads; /* TODO: Remove this pointer from the struct and just use afm.ac->ads. */
2858 afm.filter_mode = filter_mode;
2859
2860 /* 2) walk over dependencies */
2862
2863 /* 3) extract data from the context, merging it back into the standard list */
2864 if (afm.items) {
2865 /* now add the list of collected channels */
2866 BLI_movelisttolist(anim_data, &afm.tmp_data);
2868 items += afm.items;
2869 }
2870
2871 return items;
2872}
2873
2874/* ............ */
2875
2877 ListBase *anim_data,
2878 Object *ob,
2879 eAnimFilter_Flags filter_mode)
2880{
2881 size_t items = 0;
2882
2884 ListBase tmp_data = {nullptr, nullptr};
2885 size_t tmp_items = 0;
2886
2887 /* Note that when psys->part->adt is nullptr the textures can still be
2888 * animated. */
2889 if (psys->part == nullptr) {
2890 continue;
2891 }
2892
2893 /* add particle-system's animation data to temp collection */
2895 /* particle system's animation data */
2896 tmp_items += animfilter_block_data(
2897 ac, &tmp_data, reinterpret_cast<ID *>(psys->part), filter_mode);
2898
2899 /* textures */
2900 if (!(ac->ads->filterflag & ADS_FILTER_NOTEX)) {
2901 tmp_items += animdata_filter_ds_textures(
2902 ac, &tmp_data, reinterpret_cast<ID *>(psys->part), filter_mode);
2903 }
2904 }
2906
2907 /* did we find anything? */
2908 if (tmp_items) {
2909 /* include particle-expand widget first */
2910 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
2911 /* check if filtering by active status */
2912 if (ANIMCHANNEL_ACTIVEOK(psys->part)) {
2913 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, psys->part, ANIMTYPE_DSPART, psys->part, nullptr);
2914 }
2915 }
2916
2917 /* now add the list of collected channels */
2918 BLI_movelisttolist(anim_data, &tmp_data);
2920 items += tmp_items;
2921 }
2922 }
2923
2924 /* return the number of items added to the list */
2925 return items;
2926}
2927
2929 ListBase *anim_data,
2930 Object *ob,
2931 eAnimFilter_Flags filter_mode)
2932{
2933 ListBase tmp_data = {nullptr, nullptr};
2934 size_t tmp_items = 0;
2935 size_t items = 0;
2936
2937 IdAdtTemplate *iat = static_cast<IdAdtTemplate *>(ob->data);
2939 short expanded = 0;
2940 const eAnimFilter_Flags ads_filterflag = eAnimFilter_Flags(ac->ads->filterflag);
2941 const eDopeSheet_FilterFlag2 ads_filterflag2 = eDopeSheet_FilterFlag2(ac->ads->filterflag2);
2942
2943 /* get settings based on data type */
2944 switch (ob->type) {
2945 case OB_CAMERA: /* ------- Camera ------------ */
2946 {
2947 Camera *ca = static_cast<Camera *>(ob->data);
2948
2949 if (ads_filterflag & ADS_FILTER_NOCAM) {
2950 return 0;
2951 }
2952
2953 type = ANIMTYPE_DSCAM;
2954 expanded = FILTER_CAM_OBJD(ca);
2955 break;
2956 }
2957 case OB_LAMP: /* ---------- Light ----------- */
2958 {
2959 Light *la = static_cast<Light *>(ob->data);
2960
2961 if (ads_filterflag & ADS_FILTER_NOLAM) {
2962 return 0;
2963 }
2964
2965 type = ANIMTYPE_DSLAM;
2966 expanded = FILTER_LAM_OBJD(la);
2967 break;
2968 }
2969 case OB_CURVES_LEGACY: /* ------- Curve ---------- */
2970 case OB_SURF: /* ------- Nurbs Surface ---------- */
2971 case OB_FONT: /* ------- Text Curve ---------- */
2972 {
2973 Curve *cu = static_cast<Curve *>(ob->data);
2974
2975 if (ads_filterflag & ADS_FILTER_NOCUR) {
2976 return 0;
2977 }
2978
2979 type = ANIMTYPE_DSCUR;
2980 expanded = FILTER_CUR_OBJD(cu);
2981 break;
2982 }
2983 case OB_MBALL: /* ------- MetaBall ---------- */
2984 {
2985 MetaBall *mb = static_cast<MetaBall *>(ob->data);
2986
2987 if (ads_filterflag & ADS_FILTER_NOMBA) {
2988 return 0;
2989 }
2990
2991 type = ANIMTYPE_DSMBALL;
2992 expanded = FILTER_MBALL_OBJD(mb);
2993 break;
2994 }
2995 case OB_ARMATURE: /* ------- Armature ---------- */
2996 {
2997 bArmature *arm = static_cast<bArmature *>(ob->data);
2998
2999 if (ads_filterflag & ADS_FILTER_NOARM) {
3000 return 0;
3001 }
3002
3003 type = ANIMTYPE_DSARM;
3004 expanded = FILTER_ARM_OBJD(arm);
3005 break;
3006 }
3007 case OB_MESH: /* ------- Mesh ---------- */
3008 {
3009 Mesh *mesh = static_cast<Mesh *>(ob->data);
3010
3011 if (ads_filterflag & ADS_FILTER_NOMESH) {
3012 return 0;
3013 }
3014
3015 type = ANIMTYPE_DSMESH;
3016 expanded = FILTER_MESH_OBJD(mesh);
3017 break;
3018 }
3019 case OB_LATTICE: /* ---- Lattice ---- */
3020 {
3021 Lattice *lt = static_cast<Lattice *>(ob->data);
3022
3023 if (ads_filterflag & ADS_FILTER_NOLAT) {
3024 return 0;
3025 }
3026
3027 type = ANIMTYPE_DSLAT;
3028 expanded = FILTER_LATTICE_OBJD(lt);
3029 break;
3030 }
3031 case OB_SPEAKER: /* ---------- Speaker ----------- */
3032 {
3033 Speaker *spk = static_cast<Speaker *>(ob->data);
3034
3035 type = ANIMTYPE_DSSPK;
3036 expanded = FILTER_SPK_OBJD(spk);
3037 break;
3038 }
3039 case OB_CURVES: /* ---------- Curves ----------- */
3040 {
3041 Curves *curves = static_cast<Curves *>(ob->data);
3042
3043 if (ads_filterflag2 & ADS_FILTER_NOHAIR) {
3044 return 0;
3045 }
3046
3047 type = ANIMTYPE_DSHAIR;
3048 expanded = FILTER_CURVES_OBJD(curves);
3049 break;
3050 }
3051 case OB_POINTCLOUD: /* ---------- PointCloud ----------- */
3052 {
3053 PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
3054
3055 if (ads_filterflag2 & ADS_FILTER_NOPOINTCLOUD) {
3056 return 0;
3057 }
3058
3059 type = ANIMTYPE_DSPOINTCLOUD;
3060 expanded = FILTER_POINTS_OBJD(pointcloud);
3061 break;
3062 }
3063 case OB_VOLUME: /* ---------- Volume ----------- */
3064 {
3065 Volume *volume = static_cast<Volume *>(ob->data);
3066
3067 if (ads_filterflag2 & ADS_FILTER_NOVOLUME) {
3068 return 0;
3069 }
3070
3071 type = ANIMTYPE_DSVOLUME;
3072 expanded = FILTER_VOLUME_OBJD(volume);
3073 break;
3074 }
3075 case OB_LIGHTPROBE: /* ---------- LightProbe ----------- */
3076 {
3077 LightProbe *probe = static_cast<LightProbe *>(ob->data);
3078
3079 if (ads_filterflag2 & ADS_FILTER_NOLIGHTPROBE) {
3080 return 0;
3081 }
3082
3083 type = ANIMTYPE_DSLIGHTPROBE;
3084 expanded = FILTER_LIGHTPROBE_OBJD(probe);
3085 break;
3086 }
3087 }
3088
3089 /* add object data animation channels */
3090 BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
3091 /* animation data filtering */
3092 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(iat), filter_mode);
3093
3094 /* sub-data filtering... */
3095 switch (ob->type) {
3096 case OB_LAMP: /* light - textures + nodetree */
3097 {
3098 Light *la = static_cast<Light *>(ob->data);
3099 bNodeTree *ntree = la->nodetree;
3100
3101 /* nodetree */
3102 if ((ntree) && !(ads_filterflag & ADS_FILTER_NONTREE)) {
3103 tmp_items += animdata_filter_ds_nodetree(ac, &tmp_data, &la->id, ntree, filter_mode);
3104 }
3105 break;
3106 }
3107 }
3108 }
3110
3111 /* did we find anything? */
3112 if (tmp_items) {
3113 /* include data-expand widget first */
3114 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3115 /* check if filtering by active status */
3116 if (ANIMCHANNEL_ACTIVEOK(iat)) {
3117 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, iat, type, iat, nullptr);
3118 }
3119 }
3120
3121 /* now add the list of collected channels */
3122 BLI_movelisttolist(anim_data, &tmp_data);
3124 items += tmp_items;
3125 }
3126
3127 /* return the number of items added to the list */
3128 return items;
3129}
3130
3131/* shapekey-level animation */
3133 bAnimContext *ac, ListBase *anim_data, Object *ob, Key *key, eAnimFilter_Flags filter_mode)
3134{
3135 ListBase tmp_data = {nullptr, nullptr};
3136 size_t tmp_items = 0;
3137 size_t items = 0;
3138
3139 /* add shapekey-level animation channels */
3141 /* animation data filtering */
3142 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(key), filter_mode);
3143 }
3145
3146 /* did we find anything? */
3147 if (tmp_items) {
3148 /* include key-expand widget first */
3149 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3150 if (ANIMCHANNEL_ACTIVEOK(key)) {
3151 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, key, ANIMTYPE_DSSKEY, ob, nullptr);
3152 }
3153 }
3154
3155 /* now add the list of collected channels */
3156 BLI_movelisttolist(anim_data, &tmp_data);
3158 items += tmp_items;
3159 }
3160
3161 /* return the number of items added to the list */
3162 return items;
3163}
3164
3165/* object-level animation */
3167 ListBase *anim_data,
3168 Object *ob,
3169 eAnimFilter_Flags filter_mode)
3170{
3171 ListBase tmp_data = {nullptr, nullptr};
3172 size_t tmp_items = 0;
3173 size_t items = 0;
3174
3175 AnimData *adt = ob->adt;
3177 short expanded = 1;
3178 void *cdata = nullptr;
3179
3180 /* determine the type of expander channels to use */
3181 /* this is the best way to do this for now... */
3183 ob, /* Some useless long comment to prevent wrapping by old clang-format versions... */
3184 {/* AnimData - no channel, but consider data */},
3185 {/* NLA - no channel, but consider data */},
3186 { /* Drivers */
3187 type = ANIMTYPE_FILLDRIVERS;
3188 cdata = adt;
3189 expanded = EXPANDED_DRVD(adt);
3190 },
3191 {/* NLA Strip Controls - no dedicated channel for now (XXX) */},
3192 { /* Keyframes from legacy Action. */
3193 type = ANIMTYPE_FILLACTD;
3194 cdata = adt->action;
3195 expanded = EXPANDED_ACTC(adt->action);
3196 },
3197 { /* Keyframes from layered action. */
3199 cdata = adt->action;
3200 expanded = EXPANDED_ADT(adt);
3201 });
3202
3203 /* add object-level animation channels */
3204 BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
3205 /* animation data filtering */
3206 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(ob), filter_mode);
3207 }
3209
3210 /* did we find anything? */
3211 if (tmp_items) {
3212 /* include anim-expand widget first */
3213 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3214 if (type != ANIMTYPE_NONE) {
3215 /* NOTE: active-status (and the associated checks) don't apply here... */
3216 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, cdata, type, ob, nullptr);
3217 }
3218 }
3219
3220 /* now add the list of collected channels */
3221 BLI_movelisttolist(anim_data, &tmp_data);
3223 items += tmp_items;
3224 }
3225
3226 /* return the number of items added to the list */
3227 return items;
3228}
3229
3230/* get animation channels from object2 */
3232 ListBase *anim_data,
3233 Base *base,
3234 eAnimFilter_Flags filter_mode)
3235{
3236 ListBase tmp_data = {nullptr, nullptr};
3237 Object *ob = base->object;
3238 size_t tmp_items = 0;
3239 size_t items = 0;
3240 const eAnimFilter_Flags ads_filterflag = eAnimFilter_Flags(ac->ads->filterflag);
3241
3242 /* filter data contained under object first */
3244 Key *key = BKE_key_from_object(ob);
3245
3246 /* object-level animation */
3247 if ((ob->adt) && !(ads_filterflag & ADS_FILTER_NOOBJ)) {
3248 tmp_items += animdata_filter_ds_obanim(ac, &tmp_data, ob, filter_mode);
3249 }
3250
3251 /* particle deflector textures */
3252 if (ob->pd != nullptr && ob->pd->tex != nullptr && !(ads_filterflag & ADS_FILTER_NOTEX)) {
3253 tmp_items += animdata_filter_ds_texture(ac, &tmp_data, ob->pd->tex, &ob->id, filter_mode);
3254 }
3255
3256 /* shape-key */
3257 if ((key && key->adt) && !(ads_filterflag & ADS_FILTER_NOSHAPEKEYS)) {
3258 tmp_items += animdata_filter_ds_keyanim(ac, &tmp_data, ob, key, filter_mode);
3259 }
3260
3261 /* modifiers */
3262 if ((ob->modifiers.first) && !(ads_filterflag & ADS_FILTER_NOMODIFIERS)) {
3263 tmp_items += animdata_filter_ds_modifiers(ac, &tmp_data, ob, filter_mode);
3264 }
3265
3266 /* materials */
3267 if ((ob->totcol) && !(ads_filterflag & ADS_FILTER_NOMAT)) {
3268 tmp_items += animdata_filter_ds_materials(ac, &tmp_data, ob, filter_mode);
3269 }
3270
3271 /* object data */
3272 if (ob->data) {
3273 tmp_items += animdata_filter_ds_obdata(ac, &tmp_data, ob, filter_mode);
3274 }
3275
3276 /* particles */
3277 if ((ob->particlesystem.first) && !(ads_filterflag & ADS_FILTER_NOPART)) {
3278 tmp_items += animdata_filter_ds_particles(ac, &tmp_data, ob, filter_mode);
3279 }
3280
3281 /* grease pencil */
3282 if (ob->type == OB_GREASE_PENCIL && (ob->data) && !(ads_filterflag & ADS_FILTER_NOGPENCIL)) {
3284 ac, &tmp_data, static_cast<GreasePencil *>(ob->data), filter_mode);
3285 }
3286 }
3288
3289 /* if we collected some channels, add these to the new list... */
3290 if (tmp_items) {
3291 /* firstly add object expander if required */
3292 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3293 /* check if filtering by selection */
3294 /* XXX: double-check on this -
3295 * most of the time, a lot of tools need to filter out these channels! */
3296 if (ANIMCHANNEL_SELOK((base->flag & BASE_SELECTED))) {
3297 /* check if filtering by active status */
3298 if (ANIMCHANNEL_ACTIVEOK(ob)) {
3299 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, base, ANIMTYPE_OBJECT, ob, nullptr);
3300 }
3301 }
3302 }
3303
3304 /* now add the list of collected channels */
3305 BLI_movelisttolist(anim_data, &tmp_data);
3307 items += tmp_items;
3308 }
3309
3310 /* return the number of items added */
3311 return items;
3312}
3313
3315 bAnimContext *ac, ListBase *anim_data, Scene *sce, World *wo, eAnimFilter_Flags filter_mode)
3316{
3317 ListBase tmp_data = {nullptr, nullptr};
3318 size_t tmp_items = 0;
3319 size_t items = 0;
3320
3321 /* add world animation channels */
3323 /* animation data filtering */
3324 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(wo), filter_mode);
3325
3326 /* nodes */
3327 if ((wo->nodetree) && !(ac->ads->filterflag & ADS_FILTER_NONTREE)) {
3328 tmp_items += animdata_filter_ds_nodetree(
3329 ac, &tmp_data, reinterpret_cast<ID *>(wo), wo->nodetree, filter_mode);
3330 }
3331 }
3333
3334 /* did we find anything? */
3335 if (tmp_items) {
3336 /* include data-expand widget first */
3337 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3338 /* check if filtering by active status */
3339 if (ANIMCHANNEL_ACTIVEOK(wo)) {
3340 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, wo, ANIMTYPE_DSWOR, sce, nullptr);
3341 }
3342 }
3343
3344 /* now add the list of collected channels */
3345 BLI_movelisttolist(anim_data, &tmp_data);
3347 items += tmp_items;
3348 }
3349
3350 /* return the number of items added to the list */
3351 return items;
3352}
3353
3355 ListBase *anim_data,
3356 Scene *sce,
3357 eAnimFilter_Flags filter_mode)
3358{
3359 ListBase tmp_data = {nullptr, nullptr};
3360 size_t tmp_items = 0;
3361 size_t items = 0;
3362
3363 AnimData *adt = sce->adt;
3365 short expanded = 1;
3366 void *cdata = nullptr;
3367
3368 /* determine the type of expander channels to use */
3369 /* this is the best way to do this for now... */
3371 sce, /* Some useless long comment to prevent wrapping by old clang-format versions... */
3372 {/* AnimData - no channel, but consider data */},
3373 {/* NLA - no channel, but consider data */},
3374 { /* Drivers */
3375 type = ANIMTYPE_FILLDRIVERS;
3376 cdata = adt;
3377 expanded = EXPANDED_DRVD(adt);
3378 },
3379 {/* NLA Strip Controls - no dedicated channel for now (XXX) */},
3380 { /* Keyframes from legacy Action. */
3381 type = ANIMTYPE_FILLACTD;
3382 cdata = adt->action;
3383 expanded = EXPANDED_ACTC(adt->action);
3384 },
3385 { /* Keyframes from layered Action. */
3387 cdata = adt->action;
3388 expanded = EXPANDED_ADT(adt);
3389 });
3390
3391 /* add scene-level animation channels */
3392 BEGIN_ANIMFILTER_SUBCHANNELS (expanded) {
3393 /* animation data filtering */
3394 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(sce), filter_mode);
3395 }
3397
3398 /* did we find anything? */
3399 if (tmp_items) {
3400 /* include anim-expand widget first */
3401 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3402 if (type != ANIMTYPE_NONE) {
3403 /* NOTE: active-status (and the associated checks) don't apply here... */
3404 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, cdata, type, sce, nullptr);
3405 }
3406 }
3407
3408 /* now add the list of collected channels */
3409 BLI_movelisttolist(anim_data, &tmp_data);
3411 items += tmp_items;
3412 }
3413
3414 /* return the number of items added to the list */
3415 return items;
3416}
3417
3419 ListBase *anim_data,
3420 Scene *sce,
3421 eAnimFilter_Flags filter_mode)
3422{
3423 ListBase tmp_data = {nullptr, nullptr};
3424 size_t tmp_items = 0;
3425 size_t items = 0;
3426
3427 /* filter data contained under object first */
3429 bNodeTree *ntree = sce->nodetree;
3430 World *wo = sce->world;
3431
3432 /* Action, Drivers, or NLA for Scene */
3433 if ((ac->ads->filterflag & ADS_FILTER_NOSCE) == 0) {
3434 tmp_items += animdata_filter_ds_scene(ac, &tmp_data, sce, filter_mode);
3435 }
3436
3437 /* world */
3438 if ((wo) && !(ac->ads->filterflag & ADS_FILTER_NOWOR)) {
3439 tmp_items += animdata_filter_ds_world(ac, &tmp_data, sce, wo, filter_mode);
3440 }
3441
3442 /* nodetree */
3443 if ((ntree) && !(ac->ads->filterflag & ADS_FILTER_NONTREE)) {
3444 tmp_items += animdata_filter_ds_nodetree(
3445 ac, &tmp_data, reinterpret_cast<ID *>(sce), ntree, filter_mode);
3446 }
3447
3448 /* line styles */
3449 if ((ac->ads->filterflag & ADS_FILTER_NOLINESTYLE) == 0) {
3450 tmp_items += animdata_filter_ds_linestyle(ac, &tmp_data, sce, filter_mode);
3451 }
3452
3453 /* TODO: one day, when sequencer becomes its own datatype,
3454 * perhaps it should be included here. */
3455 }
3457
3458 /* if we collected some channels, add these to the new list... */
3459 if (tmp_items) {
3460 /* firstly add object expander if required */
3461 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3462 /* check if filtering by selection */
3463 if (ANIMCHANNEL_SELOK((sce->flag & SCE_DS_SELECTED))) {
3464 /* NOTE: active-status doesn't matter for this! */
3465 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, sce, ANIMTYPE_SCENE, sce, nullptr);
3466 }
3467 }
3468
3469 /* now add the list of collected channels */
3470 BLI_movelisttolist(anim_data, &tmp_data);
3472 items += tmp_items;
3473 }
3474
3475 /* return the number of items added */
3476 return items;
3477}
3478
3480 ListBase *anim_data,
3481 MovieClip *clip,
3482 eAnimFilter_Flags filter_mode)
3483{
3484 ListBase tmp_data = {nullptr, nullptr};
3485 size_t tmp_items = 0;
3486 size_t items = 0;
3487 /* add world animation channels */
3489 /* animation data filtering */
3490 tmp_items += animfilter_block_data(ac, &tmp_data, reinterpret_cast<ID *>(clip), filter_mode);
3491 }
3493 /* did we find anything? */
3494 if (tmp_items) {
3495 /* include data-expand widget first */
3496 if (filter_mode & ANIMFILTER_LIST_CHANNELS) {
3497 /* check if filtering by active status */
3498 if (ANIMCHANNEL_ACTIVEOK(clip)) {
3499 ANIMCHANNEL_NEW_CHANNEL(ac->bmain, clip, ANIMTYPE_DSMCLIP, clip, nullptr);
3500 }
3501 }
3502 /* now add the list of collected channels */
3503 BLI_movelisttolist(anim_data, &tmp_data);
3505 items += tmp_items;
3506 }
3507 /* return the number of items added to the list */
3508 return items;
3509}
3510
3512 ListBase *anim_data,
3513 const eAnimFilter_Flags filter_mode)
3514{
3515 size_t items = 0;
3516 LISTBASE_FOREACH (MovieClip *, clip, &ac->bmain->movieclips) {
3517 /* only show if gpd is used by something... */
3518 if (ID_REAL_USERS(clip) < 1) {
3519 continue;
3520 }
3521 items += animdata_filter_ds_movieclip(ac, anim_data, clip, filter_mode);
3522 }
3523 /* return the number of items added to the list */
3524 return items;
3525}
3526
3527/* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */
3529 Base *base,
3530 const eObjectMode object_mode,
3531 const eAnimFilter_Flags filter_mode)
3532{
3533 Object *ob = base->object;
3534
3535 if (base->object == nullptr) {
3536 return false;
3537 }
3538
3539 /* firstly, check if object can be included, by the following factors:
3540 * - if only visible, must check for layer and also viewport visibility
3541 * --> while tools may demand only visible, user setting takes priority
3542 * as user option controls whether sets of channels get included while
3543 * tool-flag takes into account collapsed/open channels too
3544 * - if only selected, must check if object is selected
3545 * - there must be animation data to edit (this is done recursively as we
3546 * try to add the channels)
3547 */
3548 if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ac->ads->filterflag & ADS_FILTER_INCL_HIDDEN)) {
3549 /* layer visibility - we check both object and base, since these may not be in sync yet */
3552 {
3553 return false;
3554 }
3555
3556 /* outliner restrict-flag */
3558 return false;
3559 }
3560 }
3561
3562 /* if only F-Curves with visible flags set can be shown, check that
3563 * data-block hasn't been set to invisible.
3564 */
3565 if (filter_mode & ANIMFILTER_CURVE_VISIBLE) {
3566 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) {
3567 return false;
3568 }
3569 }
3570
3571 /* Pinned curves are visible regardless of selection flags. */
3572 if ((ob->adt) && (ob->adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
3573 return true;
3574 }
3575
3576 /* Special case.
3577 * We don't do recursive checks for pin, but we need to deal with tricky
3578 * setup like animated camera lens without (pinned) animated camera location.
3579 * Without such special handle here we wouldn't be able to pin such
3580 * camera data animation to the editor.
3581 */
3582 if (ob->data != nullptr) {
3583 AnimData *data_adt = BKE_animdata_from_id(static_cast<ID *>(ob->data));
3584 if (data_adt != nullptr && (data_adt->flag & ADT_CURVES_ALWAYS_VISIBLE)) {
3585 return true;
3586 }
3587 }
3588
3589 /* check selection and object type filters */
3590 if (ac->ads->filterflag & ADS_FILTER_ONLYSEL) {
3591 if (object_mode & OB_MODE_POSE) {
3592 /* When in pose-mode handle all pose-mode objects.
3593 * This avoids problems with pose-mode where objects may be unselected,
3594 * where a selected bone of an unselected object would be hidden. see: #81922. */
3595 if (!(base->object->mode & object_mode)) {
3596 return false;
3597 }
3598 }
3599 else {
3600 /* only selected should be shown (ignore active) */
3601 if (!(base->flag & BASE_SELECTED)) {
3602 return false;
3603 }
3604 }
3605 }
3606
3607 /* check if object belongs to the filtering group if option to filter
3608 * objects by the grouped status is on
3609 * - used to ease the process of doing multiple-character choreographies
3610 */
3611 if (ac->ads->filter_grp != nullptr) {
3613 return false;
3614 }
3615 }
3616
3617 /* no reason to exclude this object... */
3618 return true;
3619}
3620
3621/* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */
3622static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr)
3623{
3624 const Base *b1 = *((const Base **)base1_ptr);
3625 const Base *b2 = *((const Base **)base2_ptr);
3626
3627 return BLI_strcasecmp_natural(b1->object->id.name + 2, b2->object->id.name + 2);
3628}
3629
3630/* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */
3632 const Scene *scene,
3633 ViewLayer *view_layer,
3634 const eAnimFilter_Flags filter_mode,
3635 size_t *r_usable_bases)
3636{
3637 /* Create an array with space for all the bases, but only containing the usable ones */
3638 BKE_view_layer_synced_ensure(scene, view_layer);
3639 ListBase *object_bases = BKE_view_layer_object_bases_get(view_layer);
3640 size_t tot_bases = BLI_listbase_count(object_bases);
3641 size_t num_bases = 0;
3642
3643 Base **sorted_bases = MEM_calloc_arrayN<Base *>(tot_bases, "Dopesheet Usable Sorted Bases");
3644 LISTBASE_FOREACH (Base *, base, object_bases) {
3645 const eObjectMode object_mode = eObjectMode(base->object->mode);
3646 if (animdata_filter_base_is_ok(ac, base, object_mode, filter_mode)) {
3647 sorted_bases[num_bases++] = base;
3648 }
3649 }
3650
3651 /* Sort this list of pointers (based on the names) */
3652 qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp);
3653
3654 /* Return list of sorted bases */
3655 *r_usable_bases = num_bases;
3656 return sorted_bases;
3657}
3658
3659/* TODO: implement pinning...
3660 * (if and when pinning is done, what we need to do is to provide freeing mechanisms -
3661 * to protect against data that was deleted). */
3663 ListBase *anim_data,
3664 eAnimFilter_Flags filter_mode)
3665{
3666 bDopeSheet *ads = ac->ads;
3667 Scene *scene = reinterpret_cast<Scene *>(ads->source);
3668 ViewLayer *view_layer = ac->view_layer;
3669 size_t items = 0;
3670
3671 /* check that we do indeed have a scene */
3672 if ((ads->source == nullptr) || (GS(ads->source->name) != ID_SCE)) {
3673 printf("Dope Sheet Error: No scene!\n");
3674 if (G.debug & G_DEBUG) {
3675 printf("\tPointer = %p, Name = '%s'\n",
3676 (void *)ads->source,
3677 (ads->source) ? ads->source->name : nullptr);
3678 }
3679 return 0;
3680 }
3681
3682 /* augment the filter-flags with settings based on the dopesheet filterflags
3683 * so that some temp settings can get added automagically...
3684 */
3685 if (ac->ads->filterflag & ADS_FILTER_SELEDIT) {
3686 /* only selected F-Curves should get their keyframes considered for editability */
3687 filter_mode |= ANIMFILTER_SELEDIT;
3688 }
3689
3690 /* Cache files level animations (frame duration and such). */
3691 if (!(ac->ads->filterflag2 & ADS_FILTER_NOCACHEFILES) &&
3693 {
3694 LISTBASE_FOREACH (CacheFile *, cache_file, &ac->bmain->cachefiles) {
3695 items += animdata_filter_ds_cachefile(ac, anim_data, cache_file, filter_mode);
3696 }
3697 }
3698
3699 /* Annotations are always shown if "Only Show Selected" is disabled. This works in the Timeline
3700 * as well as in the Dope Sheet.*/
3702 {
3703 LISTBASE_FOREACH (bGPdata *, gp_data, &ac->bmain->gpencils) {
3704 items += animdata_filter_ds_gpencil(ac, anim_data, gp_data, filter_mode);
3705 }
3706 }
3707
3708 /* movie clip's animation */
3709 if (!(ac->ads->filterflag2 & ADS_FILTER_NOMOVIECLIPS) &&
3711 {
3712 items += animdata_filter_dopesheet_movieclips(ac, anim_data, filter_mode);
3713 }
3714
3715 /* Scene-linked animation - e.g. world, compositing nodes, scene anim
3716 * (including sequencer currently). */
3717 items += animdata_filter_dopesheet_scene(ac, anim_data, scene, filter_mode);
3718
3719 /* If filtering for channel drawing, we want the objects in alphabetical order,
3720 * to make it easier to predict where items are in the hierarchy
3721 * - This order only really matters
3722 * if we need to show all channels in the list (e.g. for drawing).
3723 * (XXX: What about lingering "active" flags? The order may now become unpredictable)
3724 * - Don't do this if this behavior has been turned off (i.e. due to it being too slow)
3725 * - Don't do this if there's just a single object
3726 */
3727 BKE_view_layer_synced_ensure(scene, view_layer);
3728 ListBase *object_bases = BKE_view_layer_object_bases_get(view_layer);
3729 if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) &&
3730 (object_bases->first != object_bases->last))
3731 {
3732 /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */
3733 /* TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort... */
3734 Base **sorted_bases;
3735 size_t num_bases;
3736
3737 sorted_bases = animdata_filter_ds_sorted_bases(ac, scene, view_layer, filter_mode, &num_bases);
3738 if (sorted_bases) {
3739 /* Add the necessary channels for these bases... */
3740 for (size_t i = 0; i < num_bases; i++) {
3741 items += animdata_filter_dopesheet_ob(ac, anim_data, sorted_bases[i], filter_mode);
3742 }
3743
3744 /* TODO: store something to validate whether any changes are needed? */
3745
3746 /* free temporary data */
3747 MEM_freeN(sorted_bases);
3748 }
3749 }
3750 else {
3751 /* Filter and add contents of each base (i.e. object) without them sorting first
3752 * NOTE: This saves performance in cases where order doesn't matter
3753 */
3754 Object *obact = BKE_view_layer_active_object_get(view_layer);
3755 const eObjectMode object_mode = (obact != nullptr) ? eObjectMode(obact->mode) : OB_MODE_OBJECT;
3756 LISTBASE_FOREACH (Base *, base, object_bases) {
3757 if (animdata_filter_base_is_ok(ac, base, object_mode, filter_mode)) {
3758 /* since we're still here, this object should be usable */
3759 items += animdata_filter_dopesheet_ob(ac, anim_data, base, filter_mode);
3760 }
3761 }
3762 }
3763
3764 /* return the number of items in the list */
3765 return items;
3766}
3767
3768/* Summary track for DopeSheet/Action Editor
3769 * - return code is whether the summary lets the other channels get drawn
3770 */
3772 ListBase *anim_data,
3773 const eAnimFilter_Flags filter_mode,
3774 size_t *items)
3775{
3776 bDopeSheet *ads = nullptr;
3777
3778 /* get the DopeSheet information to use
3779 * - we should only need to deal with the DopeSheet/Action Editor,
3780 * since all the other Animation Editors won't have this concept
3781 * being applicable.
3782 */
3783 if ((ac && ac->sl) && (ac->spacetype == SPACE_ACTION)) {
3784 SpaceAction *saction = reinterpret_cast<SpaceAction *>(ac->sl);
3785 ads = &saction->ads;
3786 }
3787 else {
3788 /* invalid space type - skip this summary channels */
3789 return 1;
3790 }
3791
3792 /* dopesheet summary
3793 * - only for drawing and/or selecting keyframes in channels, but not for real editing
3794 * - only useful for DopeSheet/Action/etc. editors where it is actually useful
3795 */
3796 if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && (ac->ads->filterflag & ADS_FILTER_SUMMARY)) {
3797 bAnimListElem *ale = make_new_animlistelem(ac->bmain, ac, ANIMTYPE_SUMMARY, nullptr, nullptr);
3798 if (ale) {
3799 BLI_addtail(anim_data, ale);
3800 (*items)++;
3801 }
3802
3803 /* If summary is collapsed, don't show other channels beneath this - this check is put inside
3804 * the summary check so that it doesn't interfere with normal operation.
3805 */
3806 if (ads->flag & ADS_FLAG_SUMMARY_COLLAPSED) {
3807 return 0;
3808 }
3809 }
3810
3811 /* the other channels beneath this can be shown */
3812 return 1;
3813}
3814
3815/* ......................... */
3816
3817/* filter data associated with a channel - usually for handling summary-channels in DopeSheet */
3819 ListBase *anim_data,
3820 bAnimListElem *channel,
3821 const eAnimFilter_Flags filter_mode)
3822{
3823 size_t items = 0;
3824
3825 /* data to filter depends on channel type */
3826 /* NOTE: only common channel-types have been handled for now. More can be added as necessary */
3827 switch (channel->type) {
3828 case ANIMTYPE_SUMMARY:
3829 items += animdata_filter_dopesheet(ac, anim_data, filter_mode);
3830 break;
3831
3832 case ANIMTYPE_SCENE:
3834 ac, anim_data, static_cast<Scene *>(channel->data), filter_mode);
3835 break;
3836
3837 case ANIMTYPE_OBJECT:
3839 ac, anim_data, static_cast<Base *>(channel->data), filter_mode);
3840 break;
3841
3844 ac, anim_data, static_cast<CacheFile *>(channel->data), filter_mode);
3845 break;
3846
3847 case ANIMTYPE_ANIMDATA:
3848 items += animfilter_block_data(ac, anim_data, channel->id, filter_mode);
3849 break;
3850
3851 default:
3852 printf("ERROR: Unsupported channel type (%d) in animdata_filter_animchan()\n",
3853 channel->type);
3854 break;
3855 }
3856
3857 return items;
3858}
3859
3860/* ----------- Cleanup API --------------- */
3861
3862/* Remove entries with invalid types in animation channel list */
3864{
3865 size_t items = 0;
3866
3867 /* only keep entries with valid types */
3868 LISTBASE_FOREACH_MUTABLE (bAnimListElem *, ale, anim_data) {
3869 if (ale->type == ANIMTYPE_NONE) {
3870 BLI_freelinkN(anim_data, ale);
3871 }
3872 else {
3873 items++;
3874 }
3875 }
3876
3877 return items;
3878}
3879
3880/* Remove duplicate entries in animation channel list */
3882{
3883 GSet *gs;
3884 size_t items = 0;
3885
3886 /* Build new hash-table to efficiently store and retrieve which entries have been
3887 * encountered already while searching. */
3888 gs = BLI_gset_ptr_new(__func__);
3889
3890 /* loop through items, removing them from the list if a similar item occurs already */
3891 LISTBASE_FOREACH_MUTABLE (bAnimListElem *, ale, anim_data) {
3892 /* check if hash has any record of an entry like this
3893 * - just use ale->data for now, though it would be nicer to involve
3894 * ale->type in combination too to capture corner cases
3895 * (where same data performs differently)
3896 */
3897 if (BLI_gset_add(gs, ale->data)) {
3898 /* this entry is 'unique' and can be kept */
3899 items++;
3900 }
3901 else {
3902 /* this entry isn't needed anymore */
3903 BLI_freelinkN(anim_data, ale);
3904 }
3905 }
3906
3907 /* free the hash... */
3908 BLI_gset_free(gs, nullptr);
3909
3910 /* return the number of items still in the list */
3911 return items;
3912}
3913
3914/* ----------- Public API --------------- */
3915
3917 ListBase *anim_data,
3918 const eAnimFilter_Flags filter_mode,
3919 void *data,
3920 const eAnimCont_Types datatype)
3921{
3922 if (!data || !anim_data) {
3923 return 0;
3924 }
3925
3926 size_t items = 0;
3927 switch (datatype) {
3928 /* Action-Editing Modes */
3929 case ANIMCONT_ACTION: /* 'Action Editor' */
3930 {
3931 Object *obact = ac->obact;
3932 SpaceAction *saction = reinterpret_cast<SpaceAction *>(ac->sl);
3933 bDopeSheet *ads = (saction) ? &saction->ads : nullptr;
3934 BLI_assert(ads == ac->ads);
3935 UNUSED_VARS_NDEBUG(ads);
3936
3937 /* specially check for AnimData filter, see #36687. */
3938 /* TODO: see how this interacts with the new layered Actions. */
3939 if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) {
3940 /* all channels here are within the same AnimData block, hence this special case */
3941 if (LIKELY(obact->adt)) {
3943 ac->bmain, obact->adt, ANIMTYPE_ANIMDATA, reinterpret_cast<ID *>(obact), nullptr);
3944 }
3945 }
3946 else {
3947 /* The check for the DopeSheet summary is included here
3948 * since the summary works here too. */
3949 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3951 obact->adt && data == obact->adt->action,
3952 "This code assumes the Action editor shows the Action of the active object");
3953
3954 animrig::Action &action = static_cast<bAction *>(data)->wrap();
3955 const animrig::slot_handle_t slot_handle = obact->adt->slot_handle;
3956 items += animfilter_action(
3957 ac, anim_data, action, slot_handle, filter_mode, reinterpret_cast<ID *>(obact));
3958 }
3959 }
3960
3961 break;
3962 }
3963 case ANIMCONT_SHAPEKEY: /* 'ShapeKey Editor' */
3964 {
3965 Key *key = static_cast<Key *>(data);
3966
3967 /* specially check for AnimData filter, see #36687. */
3968 if (UNLIKELY(filter_mode & ANIMFILTER_ANIMDATA)) {
3969 /* all channels here are within the same AnimData block, hence this special case */
3970 if (LIKELY(key->adt)) {
3972 ac->bmain, key->adt, ANIMTYPE_ANIMDATA, reinterpret_cast<ID *>(key), nullptr);
3973 }
3974 }
3975 else {
3976 /* The check for the DopeSheet summary is included here
3977 * since the summary works here too. */
3978 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3979 items = animdata_filter_shapekey(ac, anim_data, key, filter_mode);
3980 }
3981 }
3982
3983 break;
3984 }
3985
3986 /* Modes for Specialty Data Types (i.e. not keyframes) */
3987 case ANIMCONT_GPENCIL: {
3988 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3989 items = animdata_filter_grease_pencil(ac, anim_data, filter_mode);
3990 }
3991 break;
3992 }
3993 case ANIMCONT_MASK: {
3994 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
3995 items = animdata_filter_mask(ac, anim_data, data, filter_mode);
3996 }
3997 break;
3998 }
3999
4000 /* DopeSheet Based Modes */
4001 case ANIMCONT_DOPESHEET: /* 'DopeSheet Editor' */
4002 {
4003 /* Due to code in `actedit_get_context()`, the equation below holds. The `data` pointer is no
4004 * longer used here, in favor of always passing `ac` down the call chain. The called code
4005 * can access it via `ac->ads`. Because the anim filtering code is quite complex, I (Sybren)
4006 * want to keep this assertion in place. */
4007 BLI_assert_msg(ac->ads == data, "ANIMCONT_DOPESHEET");
4008
4009 /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
4010 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
4011 items += animdata_filter_dopesheet(ac, anim_data, filter_mode);
4012 }
4013 break;
4014 }
4015 case ANIMCONT_FCURVES: /* Graph Editor -> F-Curves/Animation Editing */
4016 case ANIMCONT_DRIVERS: /* Graph Editor -> Drivers Editing */
4017 case ANIMCONT_NLA: /* NLA Editor */
4018 {
4019 /* Due to code in `actedit_get_context()`, the equation below holds. The `data` pointer is no
4020 * longer used here, in favor of always passing `ac` down the call chain. The called code
4021 * can access it via `ac->ads`. Because the anim filtering code is quite complex, I (Sybren)
4022 * want to keep this assertion in place. */
4023 BLI_assert_msg(ac->ads == data, "ANIMCONT_FCURVES/DRIVERS/NLA");
4024
4025 /* all of these editors use the basic DopeSheet data for filtering options,
4026 * but don't have all the same features */
4027 items = animdata_filter_dopesheet(ac, anim_data, filter_mode);
4028 break;
4029 }
4030
4031 /* Timeline Mode - Basically the same as dopesheet,
4032 * except we only have the summary for now */
4033 case ANIMCONT_TIMELINE: {
4034 /* Due to code in `actedit_get_context()`, the equation below holds. The `data` pointer is no
4035 * longer used here, in favor of always passing `ac` down the call chain. The called code
4036 * can access it via `ac->ads`. Because the anim filtering code is quite complex, I (Sybren)
4037 * want to keep this assertion in place. */
4038 BLI_assert_msg(ac->ads == data, "ANIMCONT_TIMELINE");
4039
4040 /* the DopeSheet editor is the primary place where the DopeSheet summaries are useful */
4041 if (animdata_filter_dopesheet_summary(ac, anim_data, filter_mode, &items)) {
4042 items += animdata_filter_dopesheet(ac, anim_data, filter_mode);
4043 }
4044 break;
4045 }
4046
4047 /* Special/Internal Use */
4048 case ANIMCONT_CHANNEL: /* animation channel */
4049 {
4050 /* based on the channel type, filter relevant data for this */
4052 ac, anim_data, static_cast<bAnimListElem *>(data), filter_mode);
4053 break;
4054 }
4055
4056 case ANIMCONT_NONE:
4057 printf("ANIM_animdata_filter() - Invalid datatype argument ANIMCONT_NONE\n");
4058 break;
4059 }
4060
4061 /* remove any 'weedy' entries */
4062 items = animdata_filter_remove_invalid(anim_data);
4063
4064 /* remove duplicates (if required) */
4065 if (filter_mode & ANIMFILTER_NODUPLIS) {
4066 items = animdata_filter_remove_duplis(anim_data);
4067 }
4068
4069 return items;
4070}
4071
4072/* ************************************************************ */
Functions and classes to work with Actions.
Functions to deal with Armatures.
C++ functions to deal with Armature collections (i.e. the successor of bone layers).
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:82
bool BKE_collection_has_object_recursive(Collection *collection, Object *ob)
ScrArea * CTX_wm_area(const bContext *C)
Depsgraph * CTX_data_depsgraph_pointer(const bContext *C)
SpaceLink * CTX_wm_space_data(const bContext *C)
Scene * CTX_data_scene(const bContext *C)
Main * CTX_data_main(const bContext *C)
ARegion * CTX_wm_region(const bContext *C)
ViewLayer * CTX_data_view_layer(const bContext *C)
#define DRIVER_TARGETS_USED_LOOPER_BEGIN(dvar)
#define DRIVER_TARGETS_LOOPER_END
@ G_DEBUG
Low-level operations for grease pencil.
std::optional< std::string > BKE_keyblock_curval_rnapath_get(const Key *key, const KeyBlock *kb)
Definition key.cc:1975
Key * BKE_key_from_object(Object *ob)
Definition key.cc:1824
void BKE_view_layer_synced_ensure(const Scene *scene, ViewLayer *view_layer)
Object * BKE_view_layer_active_object_get(const ViewLayer *view_layer)
ListBase * BKE_view_layer_object_bases_get(ViewLayer *view_layer)
LibraryForeachIDCallbackFlag
struct MaskLayer * BKE_mask_layer_active(struct Mask *mask)
General operations, lookup, etc. for materials.
Material * BKE_object_material_get(Object *ob, short act)
void void void BKE_modifiers_foreach_ID_link(Object *ob, IDWalkFunc walk, void *user_data)
#define BLI_array_alloca(arr, realsize)
Definition BLI_alloca.h:18
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
struct GSet GSet
Definition BLI_ghash.h:337
GSet * BLI_gset_ptr_new(const char *info)
void BLI_gset_free(GSet *gs, GSetKeyFreeFP keyfreefp)
bool BLI_gset_add(GSet *gs, void *key)
Definition BLI_ghash.cc:966
int BLI_findindex(const ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:586
void void void BLI_movelisttolist(ListBase *dst, ListBase *src) ATTR_NONNULL(1
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
#define LISTBASE_FOREACH_BACKWARD(type, var, list)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition listbase.cc:524
int bool bool bool size_t size_t size_t int BLI_string_max_possible_word_count(int str_len) ATTR_WARN_UNUSED_RESULT
Definition string.cc:583
int char char * BLI_strncasestr(const char *s, const char *find, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
int char char int int int BLI_strcasecmp_natural(const char *s1, const char *s2) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
int bool bool BLI_str_endswith(const char *__restrict str, const char *__restrict end) ATTR_NONNULL(1
bool bool int BLI_string_find_split_words(const char *str, size_t str_maxlen, char delim, int r_words[][2], int words_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
int char * BLI_strcasestr(const char *s, const char *find) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
Definition string.cc:531
#define UNUSED_VARS_NDEBUG(...)
#define UNLIKELY(x)
#define ELEM(...)
#define STREQ(a, b)
#define LIKELY(x)
@ ID_TAG_DOIT
Definition DNA_ID.h:944
@ ID_TE
@ ID_NT
@ ID_SCE
@ ID_AC
@ ID_OB
@ ID_PA
eDopeSheet_FilterFlag2
@ ADS_FILTER_NOLIGHTPROBE
@ ADS_FILTER_DRIVER_FALLBACK_AS_ERROR
@ ADS_FILTER_NOMOVIECLIPS
@ ADS_FILTER_NOVOLUME
@ ADS_FILTER_NOHAIR
@ ADS_FILTER_NOCACHEFILES
@ ADS_FILTER_NOPOINTCLOUD
@ ADS_FILTER_ONLYSEL
@ ADS_FILTER_NOARM
@ ADS_FILTER_NLA_NOACT
@ ADS_FILTER_NOMAT
@ ADS_FILTER_NONTREE
@ ADS_FILTER_NOCAM
@ ADS_FILTER_NOSHAPEKEYS
@ ADS_FILTER_NOTEX
@ ADS_FILTER_ONLYNLA
@ ADS_FILTER_ONLY_ERRORS
@ ADS_FILTER_ONLYDRIVERS
@ ADS_FILTER_SELEDIT
@ ADS_FILTER_NOSCE
@ ADS_FILTER_NOLAM
@ ADS_FILTER_ONLY_SLOTS_OF_ACTIVE
@ ADS_FILTER_NOMODIFIERS
@ ADS_FILTER_NOLINESTYLE
@ ADS_FILTER_SUMMARY
@ ADS_FILTER_NOGPENCIL
@ ADS_FILTER_NOOBJ
@ ADS_FILTER_NOCUR
@ ADS_FILTER_NOPART
@ ADS_FILTER_NOMESH
@ ADS_FILTER_NOWOR
@ ADS_FILTER_INCL_HIDDEN
@ ADS_FILTER_NOMBA
@ ADS_FILTER_NOLAT
@ AGRP_ACTIVE
@ AGRP_NOTVISIBLE
@ ADS_FLAG_SUMMARY_COLLAPSED
@ ADS_FLAG_INVERT_FILTER
@ ADS_FLAG_NO_DB_SORT
@ ADS_FLAG_FUZZY_NAMES
eAnimEdit_Context
@ SACTCONT_GPENCIL
@ SACTCONT_ACTION
@ SACTCONT_TIMELINE
@ SACTCONT_DOPESHEET
@ SACTCONT_SHAPEKEY
@ SACTCONT_MASK
@ SACTCONT_CACHEFILE
@ ADT_CURVES_ALWAYS_VISIBLE
@ ADT_CURVES_NOT_VISIBLE
@ ADT_NLA_SKEYS_COLLAPSED
@ DTAR_FLAG_FALLBACK_USED
@ DTAR_FLAG_INVALID
@ DRIVER_FLAG_INVALID
@ FCURVE_DISABLED
@ FCURVE_ACTIVE
@ FCURVE_SELECTED
@ FCURVE_PROTECTED
@ FCURVE_VISIBLE
@ NLATRACK_ACTIVE
@ BONE_SELECTED
@ GREASE_PENCIL_ANIM_CHANNEL_EXPANDED
@ KEY_RELATIVE
@ BASE_ENABLED_AND_VISIBLE_IN_DEFAULT_VIEWPORT
@ BASE_ENABLED_AND_MAYBE_VISIBLE_IN_VIEWPORT
@ VIEW_LAYER_FREESTYLE
@ NODE_SELECT
eObjectMode
@ OB_MODE_POSE
@ OB_MODE_OBJECT
Object is a sort of wrapper for general info.
@ OB_HIDE_VIEWPORT
@ OB_SPEAKER
@ OB_LATTICE
@ OB_MBALL
@ OB_SURF
@ OB_CAMERA
@ OB_FONT
@ OB_GREASE_PENCIL
@ OB_ARMATURE
@ OB_LAMP
@ OB_MESH
@ OB_POINTCLOUD
@ OB_VOLUME
@ OB_CURVES_LEGACY
@ OB_CURVES
@ OB_LIGHTPROBE
#define BASE_SELECTED(v3d, base)
@ SCE_KEYS_NO_SELONLY
@ SCE_DS_SELECTED
eRegion_Type
eSpace_Type
@ SPACE_TEXT
@ SPACE_CLIP
@ SPACE_ACTION
@ SPACE_CONSOLE
@ SPACE_OUTLINER
@ SPACE_STATUSBAR
@ SPACE_TOPBAR
@ SPACE_NODE
@ SPACE_SPREADSHEET
@ SPACE_USERPREF
@ SPACE_FILE
@ SPACE_PROPERTIES
@ SPACE_NLA
@ SPACE_SEQ
@ SPACE_EMPTY
@ SPACE_SCRIPT
@ SPACE_IMAGE
@ SPACE_GRAPH
@ SPACE_VIEW3D
@ SPACE_INFO
eGraphEdit_Mode
@ SIPO_MODE_DRIVERS
@ SIPO_MODE_ANIMATION
@ USER_ANIM_ONLY_SHOW_SELECTED_CURVE_KEYS
#define EXPANDED_ADT(adt)
#define FILTER_SPK_OBJD(spk)
#define FILTER_CACHEFILE_OBJD(cf)
#define SEL_SHAPEKEY(kb)
#define FILTER_LIGHTPROBE_OBJD(probe)
eAnim_ChannelType
@ ANIMTYPE_DSSPK
@ ANIMTYPE_DSTEX
@ ANIMTYPE_SUMMARY
@ ANIMTYPE_DSNTREE
@ ANIMTYPE_NLACURVE
@ ANIMTYPE_SHAPEKEY
@ ANIMTYPE_DSMBALL
@ ANIMTYPE_DSCAM
@ ANIMTYPE_DSLIGHTPROBE
@ ANIMTYPE_DSPOINTCLOUD
@ ANIMTYPE_FILLDRIVERS
@ ANIMTYPE_NONE
@ ANIMTYPE_DSPART
@ ANIMTYPE_DSLINESTYLE
@ ANIMTYPE_GROUP
@ ANIMTYPE_ACTION_SLOT
@ ANIMTYPE_SPECIALDATA__UNUSED
@ ANIMTYPE_GREASE_PENCIL_DATABLOCK
@ ANIMTYPE_DSCUR
@ ANIMTYPE_SCENE
@ ANIMTYPE_DSARM
@ ANIMTYPE_NLACONTROLS
@ ANIMTYPE_GPLAYER
@ ANIMTYPE_MASKDATABLOCK
@ ANIMTYPE_ANIMDATA
@ ANIMTYPE_MASKLAYER
@ ANIMTYPE_DSGPENCIL
@ ANIMTYPE_DSLAT
@ ANIMTYPE_NLAACTION
@ ANIMTYPE_DSMCLIP
@ ANIMTYPE_DSMAT
@ ANIMTYPE_NUM_TYPES
@ ANIMTYPE_DSCACHEFILE
@ ANIMTYPE_DSVOLUME
@ ANIMTYPE_FCURVE
@ ANIMTYPE_DSLAM
@ ANIMTYPE_PALETTE
@ ANIMTYPE_GREASE_PENCIL_LAYER
@ ANIMTYPE_FILLACT_LAYERED
@ ANIMTYPE_FILLACTD
@ ANIMTYPE_OBJECT
@ ANIMTYPE_DSMESH
@ ANIMTYPE_GREASE_PENCIL_LAYER_GROUP
@ ANIMTYPE_NLATRACK
@ ANIMTYPE_DSWOR
@ ANIMTYPE_DSSKEY
@ ANIMTYPE_DSHAIR
#define EXPANDED_MCLIP(clip)
#define FILTER_NTREE_DATA(ntree)
#define FILTER_SKE_OBJD(key)
#define FILTER_MESH_OBJD(me)
#define EDITABLE_GPL(gpl)
#define SEL_AGRP(agrp)
#define EXPANDED_SCEC(sce)
#define SEL_MASKLAY(masklay)
#define SEL_GPL(gpl)
#define FILTER_ARM_OBJD(arm)
#define EDITABLE_AGRP(agrp)
#define EXPANDED_AGRP(ac, agrp)
#define FILTER_CAM_OBJD(ca)
@ ALE_GREASE_PENCIL_GROUP
@ ALE_SCE
@ ALE_GREASE_PENCIL_CEL
@ ALE_GREASE_PENCIL_DATA
@ ALE_NONE
@ ALE_GPFRAME
@ ALE_FCURVE
@ ALE_NLASTRIP
@ ALE_ALL
@ ALE_ACT
@ ALE_ACTION_LAYERED
@ ALE_OB
@ ALE_GROUP
@ ALE_ACTION_SLOT
@ ALE_MASKLAY
#define FILTER_LATTICE_OBJD(lt)
#define FILTER_CURVES_OBJD(ha)
#define EXPANDED_ACTC(actc)
#define FILTER_LAM_OBJD(la)
eAnimCont_Types
@ ANIMCONT_DRIVERS
@ ANIMCONT_FCURVES
@ ANIMCONT_NLA
@ ANIMCONT_MASK
@ ANIMCONT_SHAPEKEY
@ ANIMCONT_TIMELINE
@ ANIMCONT_DOPESHEET
@ ANIMCONT_ACTION
@ ANIMCONT_NONE
@ ANIMCONT_GPENCIL
@ ANIMCONT_CHANNEL
#define EXPANDED_OBJC(ob)
#define SEL_FCU(fcu)
#define EDITABLE_SHAPEKEY(kb)
#define EDITABLE_FCU(fcu)
#define EDITABLE_MASK(masklay)
#define FILTER_CUR_OBJD(cu)
#define FILTER_MAT_OBJD(ma)
#define EDITABLE_NLT(nlt)
#define FILTER_WOR_SCED(wo)
#define FILTER_MBALL_OBJD(mb)
#define FILTER_LS_SCED(linestyle)
#define EXPANDED_DRVD(adt)
#define EXPANDED_MASK(mask)
#define SEL_ANIMDATA(adt)
#define FILTER_POINTS_OBJD(pt)
#define EXPANDED_GPD(gpd)
#define FILTER_TEX_DATA(tex)
#define FILTER_VOLUME_OBJD(vo)
#define SEL_NLT(nlt)
eAnimFilter_Flags
@ ANIMFILTER_TMP_PEEK
@ ANIMFILTER_ACTIVE
@ ANIMFILTER_UNSEL
@ ANIMFILTER_FOREDIT
@ ANIMFILTER_ANIMDATA
@ ANIMFILTER_DATA_VISIBLE
@ ANIMFILTER_CURVE_VISIBLE
@ ANIMFILTER_SELEDIT
@ ANIMFILTER_LIST_VISIBLE
@ ANIMFILTER_LIST_CHANNELS
@ ANIMFILTER_NODUPLIS
@ ANIMFILTER_TMP_IGNORE_ONLYSEL
@ ANIMFILTER_FCURVESONLY
@ ANIMFILTER_SEL
@ ANIMFILTER_ACTGROUPED
#define FILTER_PART_OBJD(part)
Read Guarded memory(de)allocation.
#define C
Definition RandGen.cpp:29
#define MAX_MTEX
Definition Stroke.h:31
const bAnimChannelType * ANIM_channel_get_typeinfo(const bAnimListElem *ale)
static size_t animdata_filter_ds_scene(bAnimContext *ac, ListBase *anim_data, Scene *sce, eAnimFilter_Flags filter_mode)
#define ANIMCHANNEL_NEW_CHANNEL(bmain, channel_data, channel_type, owner_id, fcurve_owner_id)
static size_t animdata_filter_dopesheet_ob(bAnimContext *ac, ListBase *anim_data, Base *base, eAnimFilter_Flags filter_mode)
static Key * actedit_get_shapekeys(bAnimContext *ac)
static size_t animfilter_block_data(bAnimContext *ac, ListBase *anim_data, ID *id, const eAnimFilter_Flags filter_mode)
bool ANIM_animdata_can_have_greasepencil(const eAnimCont_Types type)
static bool nlaedit_get_context(bAnimContext *ac, SpaceNla *snla)
static size_t animdata_filter_dopesheet_movieclips(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_grease_pencil_layers_data(bAnimContext *ac, ListBase *anim_data, GreasePencil *grease_pencil, const eAnimFilter_Flags filter_mode)
static bool animdata_filter_base_is_ok(bAnimContext *ac, Base *base, const eObjectMode object_mode, const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_obanim(bAnimContext *ac, ListBase *anim_data, Object *ob, eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_movieclip(bAnimContext *ac, ListBase *anim_data, MovieClip *clip, eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_nodetree_group(bAnimContext *ac, ListBase *anim_data, ID *owner_id, bNodeTree *ntree, eAnimFilter_Flags filter_mode)
static bool name_matches_dopesheet_filter(const bDopeSheet *ads, const char *name)
static size_t animdata_filter_ds_particles(bAnimContext *ac, ListBase *anim_data, Object *ob, eAnimFilter_Flags filter_mode)
static size_t animfilter_fcurves_span(bAnimContext *ac, ListBase *anim_data, Span< FCurve * > fcurves, const animrig::slot_handle_t slot_handle, const eAnimFilter_Flags filter_mode, ID *animated_id, ID *fcurve_owner_id)
#define ANIMCHANNEL_SELOK(test_func)
static size_t animdata_filter_mask(bAnimContext *ac, ListBase *anim_data, void *, eAnimFilter_Flags filter_mode)
static bool fcurve_span_selection_matters(const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_gpencil(bAnimContext *ac, ListBase *anim_data, bGPdata *gpd, eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_materials(bAnimContext *ac, ListBase *anim_data, Object *ob, const eAnimFilter_Flags filter_mode)
static size_t animfilter_nla_controls(bAnimContext *ac, ListBase *anim_data, AnimData *adt, eAnimFilter_Flags filter_mode, ID *owner_id)
static size_t animdata_filter_grease_pencil(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_grease_pencil_layer(bAnimContext *ac, ListBase *anim_data, GreasePencil *grease_pencil, blender::bke::greasepencil::Layer &layer, const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_gpencil_layers_data_legacy(bAnimContext *ac, ListBase *anim_data, bGPdata *gpd, const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_textures(bAnimContext *ac, ListBase *anim_data, ID *owner_id, const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_modifiers(bAnimContext *ac, ListBase *anim_data, Object *ob, const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_grease_pencil_layer_node_recursive(bAnimContext *ac, ListBase *anim_data, GreasePencil *grease_pencil, blender::bke::greasepencil::TreeNode &node, eAnimFilter_Flags filter_mode)
bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac)
static void key_data_from_adt(bAnimListElem &ale, AnimData *adt)
#define ANIMCHANNEL_ACTIVEOK(ale)
static size_t animdata_filter_ds_material(bAnimContext *ac, ListBase *anim_data, Material *ma, eAnimFilter_Flags filter_mode)
static size_t animdata_filter_remove_invalid(ListBase *anim_data)
static size_t animdata_filter_ds_texture(bAnimContext *ac, ListBase *anim_data, Tex *tex, ID *owner_id, eAnimFilter_Flags filter_mode)
static short animdata_filter_dopesheet_summary(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, size_t *items)
bool ANIM_animdata_context_getdata(bAnimContext *ac)
static void animfilter_modifier_idpoin_cb(void *afm_ptr, Object *ob, ID **idpoin, LibraryForeachIDCallbackFlag)
static size_t animdata_filter_grease_pencil_data(bAnimContext *ac, ListBase *anim_data, GreasePencil *grease_pencil, eAnimFilter_Flags filter_mode)
static size_t animdata_filter_shapekey(bAnimContext *ac, ListBase *anim_data, Key *key, const eAnimFilter_Flags filter_mode)
static size_t animfilter_fcurves(bAnimContext *ac, ListBase *anim_data, FCurve *first, eAnim_ChannelType fcurve_type, const eAnimFilter_Flags filter_mode, void *owner, ID *owner_id, ID *fcurve_owner_id)
static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr)
static bool skip_fcurve_with_name(bAnimContext *ac, FCurve *fcu, eAnim_ChannelType channel_type, void *owner, ID *owner_id)
static size_t animdata_filter_ds_obdata(bAnimContext *ac, ListBase *anim_data, Object *ob, eAnimFilter_Flags filter_mode)
static bool fcurve_has_errors(bAnimContext *ac, const FCurve *fcu)
static size_t animdata_filter_ds_nodetree(bAnimContext *ac, ListBase *anim_data, ID *owner_id, bNodeTree *ntree, const eAnimFilter_Flags filter_mode)
#define END_ANIMFILTER_SUBCHANNELS
static bAnimListElem * make_new_animlistelem(Main *bmain, void *data, const eAnim_ChannelType datatype, ID *owner_id, ID *fcurve_owner_id)
static size_t animfilter_act_group(bAnimContext *ac, ListBase *anim_data, bAction *act, animrig::slot_handle_t slot_handle, bActionGroup *agrp, eAnimFilter_Flags filter_mode, ID *owner_id)
static bool fcurve_span_must_be_selected(const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_world(bAnimContext *ac, ListBase *anim_data, Scene *sce, World *wo, eAnimFilter_Flags filter_mode)
static bool skip_fcurve_selected_data(bAnimContext *ac, FCurve *fcu, ID *owner_id, const eAnimFilter_Flags filter_mode)
static size_t animdata_filter_remove_duplis(ListBase *anim_data)
static size_t animfilter_action_slots(bAnimContext *ac, ListBase *anim_data, animrig::Action &action, const eAnimFilter_Flags filter_mode, ID *owner_id)
static size_t animdata_filter_animchan(bAnimContext *ac, ListBase *anim_data, bAnimListElem *channel, const eAnimFilter_Flags filter_mode)
size_t ANIM_animfilter_action_slot(bAnimContext *ac, ListBase *anim_data, animrig::Action &action, animrig::Slot &slot, const eAnimFilter_Flags filter_mode, ID *animated_id)
static FCurve * animfilter_fcurve_next(bAnimContext *ac, FCurve *first, eAnim_ChannelType channel_type, const eAnimFilter_Flags filter_mode, void *owner, ID *owner_id)
static size_t animdata_filter_ds_cachefile(bAnimContext *ac, ListBase *anim_data, CacheFile *cache_file, eAnimFilter_Flags filter_mode)
static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, eAnimFilter_Flags filter_mode)
static size_t animdata_filter_ds_keyanim(bAnimContext *ac, ListBase *anim_data, Object *ob, Key *key, eAnimFilter_Flags filter_mode)
#define BEGIN_ANIMFILTER_SUBCHANNELS(expanded_check)
static size_t animfilter_nla(bAnimContext *ac, ListBase *anim_data, AnimData *adt, const eAnimFilter_Flags filter_mode, ID *owner_id)
static size_t animdata_filter_ds_linestyle(bAnimContext *ac, ListBase *anim_data, Scene *sce, eAnimFilter_Flags filter_mode)
static bool graphedit_get_context(bAnimContext *ac, SpaceGraph *sipo)
size_t ANIM_animdata_filter(bAnimContext *ac, ListBase *anim_data, const eAnimFilter_Flags filter_mode, void *data, const eAnimCont_Types datatype)
#define ANIMDATA_FILTER_CASES(id, adtOk, nlaOk, driversOk, nlaKeysOk, legacyActionOk, layeredActionOk)
#define ANIMCHANNEL_NEW_CHANNEL_FULL(bmain, channel_data, channel_type, owner_id, fcurve_owner_id, ale_statement)
static bool actedit_get_context(bAnimContext *ac, SpaceAction *saction)
static bool ale_name_matches_dopesheet_filter(const bDopeSheet &ads, bAnimListElem &ale)
static Base ** animdata_filter_ds_sorted_bases(bAnimContext *ac, const Scene *scene, ViewLayer *view_layer, const eAnimFilter_Flags filter_mode, size_t *r_usable_bases)
static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, animrig::Action &action, const animrig::slot_handle_t slot_handle, const eAnimFilter_Flags filter_mode, ID *owner_id)
static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_data, Scene *sce, eAnimFilter_Flags filter_mode)
static size_t animdata_filter_mask_data(bAnimContext *ac, ListBase *anim_data, Mask *mask, const eAnimFilter_Flags filter_mode)
#define ANIMCHANNEL_SELEDITOK(test_func)
#define ANIM_CHAN_NAME_SIZE
ListBase * ED_context_get_markers(const bContext *C)
#define U
BMesh const char void * data
void append(const T &value)
blender::Span< const Slot * > slots() const
Slot * slot_for_handle(slot_handle_t handle)
blender::Span< const FCurve * > fcurves() const
blender::Span< const bActionGroup * > channel_groups() const
static constexpr slot_handle_t unassigned
const LayerGroup & as_group() const
#define SELECT
#define printf(...)
#define ID_IS_LINKED(_id)
#define ID_IS_EDITABLE(_id)
#define ID_REAL_USERS(id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
#define GS(a)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
ccl_device_inline float2 mask(const MaskType mask, const float2 a)
static ulong * next
#define G(x, y, z)
const animrig::Channelbag * channelbag_for_action_slot(const Action &action, slot_handle_t slot_handle)
ID * action_slot_get_id_best_guess(Main &bmain, Slot &slot, ID *primary_id)
decltype(::ActionSlot::handle) slot_handle_t
Span< FCurve * > fcurves_for_action_slot(Action &action, slot_handle_t slot_handle)
bool bone_is_visible_pchan(const bArmature *armature, const bPoseChannel *pchan)
FCurve * fcurve_find_in_assigned_slot(AnimData &adt, const FCurveDescriptor &fcurve_descriptor)
bNode * node_find_node_by_name(bNodeTree &ntree, StringRefNull name)
Definition node.cc:3607
Editing * editing_get(const Scene *scene)
Definition sequencer.cc:272
Strip * get_strip_by_name(ListBase *seqbase, const char *name, bool recursive)
float wrap(float value, float max, float min)
Definition node_math.h:71
bAction * action
int32_t slot_handle
ListBase drivers
ListBase nla_tracks
short flag
struct Object * object
struct AnimData * adt
struct AnimData * adt
struct AnimData * adt
struct AnimData * adt
struct FCurve * next
bActionGroup * grp
char * rna_path
ChannelDriver * driver
struct AnimData * adt
GreasePencilLayerTreeNode base
GreasePencilLayerTreeNode base
GreasePencilLayerTreeGroup * root_group_ptr
struct AnimData * adt
Definition DNA_ID.h:404
int tag
Definition DNA_ID.h:424
char name[66]
Definition DNA_ID.h:415
struct AnimData * adt
char type
ListBase block
struct AnimData * adt
struct AnimData * adt
struct AnimData * adt
struct bNodeTree * nodetree
void * last
void * first
ListBase masks
Definition BKE_main.hh:281
ListBase movieclips
Definition BKE_main.hh:280
ListBase gpencils
Definition BKE_main.hh:278
ListBase cachefiles
Definition BKE_main.hh:283
struct AnimData * adt
int masklay_act
struct bNodeTree * nodetree
struct AnimData * adt
struct AnimData * adt
struct AnimData * adt
ListBase strips
ListBase strips
struct NlaTrack * next
char name[64]
struct NlaTrack * prev
ListBase particlesystem
struct bPose * pose
ListBase modifiers
struct PartDeflect * pd
short visibility_flag
struct AnimData * adt
struct AnimData * adt
struct MTex * mtex[18]
struct AnimData * adt
struct bNodeTree * nodetree
struct MovieClip * clip
ListBase view_layers
struct AnimData * adt
struct World * world
struct bDopeSheet * ads
struct bDopeSheet * ads
struct AnimData * adt
struct Mask * mask
char name[64]
struct AnimData * adt
struct bNodeTree * nodetree
struct AnimData * adt
struct bNodeTree * nodetree
struct AnimData * adt
struct ActionChannelbag * channelbag
ListBase curves
ListBase groups
void(* name)(bAnimListElem *ale, char *name)
eAnimEdit_Context dopesheet_mode
eGraphEdit_Mode grapheditor_mode
SpaceLink * sl
ListBase * markers
eAnimCont_Types datatype
bDopeSheet * ads
eSpace_Type spacetype
ViewLayer * view_layer
ARegion * region
Depsgraph * depsgraph
Object * obact
eRegion_Type regiontype
ScrArea * area
int32_t slot_handle
AnimData * adt
eAnim_ChannelType type
eAnim_KeyType datatype
struct AnimData * adt
char searchstr[64]
struct Collection * filter_grp
struct AnimData * adt
struct AnimData * adt
char name[64]
struct Bone * bone
eAnimFilter_Flags filter_mode
i
Definition text_draw.cc:230