Blender V4.3
action_iterators.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2024 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
9#include "ANIM_action.hh"
11
12#include "BLI_assert.h"
13
14#include "BKE_anim_data.hh"
15#include "BKE_nla.hh"
16
18
19namespace blender::animrig {
20
22{
23 if (action.is_action_legacy()) {
24 LISTBASE_FOREACH (FCurve *, fcurve, &action.curves) {
25 callback(*fcurve);
26 }
27 return;
28 }
29
30 for (Layer *layer : action.layers()) {
31 for (Strip *strip : layer->strips()) {
32 if (strip->type() != Strip::Type::Keyframe) {
33 continue;
34 }
35 for (ChannelBag *bag : strip->data<StripKeyframeData>(action).channelbags()) {
36 for (FCurve *fcu : bag->fcurves()) {
37 callback(*fcu);
38 }
39 }
40 }
41 }
42}
43
45 slot_handle_t handle,
46 FunctionRef<void(FCurve &fcurve)> callback)
47{
48 if (action.is_action_legacy()) {
49 LISTBASE_FOREACH (FCurve *, fcurve, &action.curves) {
50 callback(*fcurve);
51 }
52 }
53 else if (action.is_action_layered()) {
54 for (Layer *layer : action.layers()) {
55 for (Strip *strip : layer->strips()) {
56 if (strip->type() != Strip::Type::Keyframe) {
57 continue;
58 }
59 for (ChannelBag *bag : strip->data<StripKeyframeData>(action).channelbags()) {
60 if (bag->slot_handle != handle) {
61 continue;
62 }
63 for (FCurve *fcu : bag->fcurves()) {
64 BLI_assert(fcu != nullptr);
65 callback(*fcu);
66 }
67 }
68 }
69 }
70 }
71}
72
74 const ID &animated_id,
75 FunctionRef<bool(const Action &action, slot_handle_t slot_handle)> callback)
76{
77
78 const auto forward_to_callback = [&](bAction *&action_ptr_ref,
79 const slot_handle_t &slot_handle_ref,
80 char * /*slot_name*/) -> bool {
81 if (!action_ptr_ref) {
82 return true;
83 }
84 return callback(const_cast<const Action &>(action_ptr_ref->wrap()), slot_handle_ref);
85 };
86
87 return foreach_action_slot_use_with_references(const_cast<ID &>(animated_id),
88 forward_to_callback);
89}
90
92 ID &animated_id,
93 FunctionRef<bool(bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *slot_name)>
95{
96 AnimData *adt = BKE_animdata_from_id(&animated_id);
97
98 if (adt) {
99 if (adt->action) {
100 /* Direct assignment. */
101 if (!callback(adt->action, adt->slot_handle, adt->slot_name)) {
102 return false;
103 }
104 }
105
106 /* NLA strips. */
107 const bool looped_until_last_strip = bke::nla::foreach_strip_adt(*adt, [&](NlaStrip *strip) {
108 if (strip->act) {
109 if (!callback(strip->act, strip->action_slot_handle, strip->action_slot_name)) {
110 return false;
111 }
112 }
113 return true;
114 });
115 if (!looped_until_last_strip) {
116 return false;
117 }
118 }
119
120 /* The rest of the code deals with constraints, so only relevant when this is an Object. */
121 if (GS(animated_id.name) != ID_OB) {
122 return true;
123 }
124
125 const Object &object = reinterpret_cast<const Object &>(animated_id);
126
133 auto visit_constraint = [&](const bConstraint &constraint) -> bool {
134 if (constraint.type != CONSTRAINT_TYPE_ACTION) {
135 return true;
136 }
137 bActionConstraint *constraint_data = static_cast<bActionConstraint *>(constraint.data);
138 if (!constraint_data->act) {
139 return true;
140 }
141 return callback(constraint_data->act,
142 constraint_data->action_slot_handle,
143 constraint_data->action_slot_name);
144 };
145
146 /* Visit Object constraints. */
147 LISTBASE_FOREACH (bConstraint *, con, &object.constraints) {
148 if (!visit_constraint(*con)) {
149 return false;
150 }
151 }
152
153 /* Visit Pose Bone constraints. */
154 if (object.type == OB_ARMATURE) {
155 LISTBASE_FOREACH (bPoseChannel *, pchan, &object.pose->chanbase) {
156 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
157 if (!visit_constraint(*con)) {
158 return false;
159 }
160 }
161 }
162 }
163
164 return true;
165}
166
167} // namespace blender::animrig
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
AnimData * BKE_animdata_from_id(const ID *id)
Definition anim_data.cc:89
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
@ ID_OB
@ CONSTRAINT_TYPE_ACTION
@ OB_ARMATURE
btSequentialImpulseConstraintSolverMt int btPersistentManifold int btTypedConstraint ** constraints
blender::Span< const Layer * > layers() const
DEGForeachIDComponentCallback callback
#define GS(x)
Definition iris.cc:202
void foreach_fcurve_in_action_slot(Action &action, slot_handle_t handle, FunctionRef< void(FCurve &fcurve)> callback)
bool foreach_action_slot_use_with_references(ID &animated_id, FunctionRef< bool(bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *slot_name)> callback)
void foreach_fcurve_in_action(Action &action, FunctionRef< void(FCurve &fcurve)> callback)
decltype(::ActionSlot::handle) slot_handle_t
bool foreach_action_slot_use(const ID &animated_id, FunctionRef< bool(const Action &action, slot_handle_t slot_handle)> callback)
bool foreach_strip_adt(const AnimData &adt, blender::FunctionRef< bool(NlaStrip *)> callback)
bAction * action
int32_t slot_handle
char slot_name[66]
Definition DNA_ID.h:413
char name[66]
Definition DNA_ID.h:425
bAction * act
ListBase curves