Blender V4.5
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
8
9#include "ANIM_action.hh"
11
12#include "BLI_assert.h"
13#include "BLI_listbase.h"
14
15#include "BKE_anim_data.hh"
16#include "BKE_nla.hh"
17
19
20#include "RNA_access.hh"
21#include "RNA_prototypes.hh"
22
23namespace blender::animrig {
24
25void foreach_fcurve_in_action(Action &action, FunctionRef<void(FCurve &fcurve)> callback)
26{
27 if (action.is_action_legacy()) {
28 LISTBASE_FOREACH (FCurve *, fcurve, &action.curves) {
29 callback(*fcurve);
30 }
31 return;
32 }
33
34 for (Layer *layer : action.layers()) {
35 for (Strip *strip : layer->strips()) {
36 if (strip->type() != Strip::Type::Keyframe) {
37 continue;
38 }
39 for (Channelbag *bag : strip->data<StripKeyframeData>(action).channelbags()) {
40 for (FCurve *fcu : bag->fcurves()) {
41 callback(*fcu);
42 }
43 }
44 }
45 }
46}
47
49 slot_handle_t handle,
50 FunctionRef<void(FCurve &fcurve)> callback)
51{
52 if (action.is_action_legacy()) {
53 LISTBASE_FOREACH (FCurve *, fcurve, &action.curves) {
54 callback(*fcurve);
55 }
56 }
57 else if (action.is_action_layered()) {
58 for (Layer *layer : action.layers()) {
59 for (Strip *strip : layer->strips()) {
60 if (strip->type() != Strip::Type::Keyframe) {
61 continue;
62 }
63 for (Channelbag *bag : strip->data<StripKeyframeData>(action).channelbags()) {
64 if (bag->slot_handle != handle) {
65 continue;
66 }
67 for (FCurve *fcu : bag->fcurves()) {
68 BLI_assert(fcu != nullptr);
69 callback(*fcu);
70 }
71 }
72 }
73 }
74 }
75}
76
78 const ID &animated_id,
79 FunctionRef<bool(const Action &action, slot_handle_t slot_handle)> callback)
80{
81
82 const auto forward_to_callback = [&](ID & /* animated_id */,
83 bAction *&action_ptr_ref,
84 const slot_handle_t &slot_handle_ref,
85 char * /*last_slot_identifier*/) -> bool {
86 if (!action_ptr_ref) {
87 return true;
88 }
89 return callback(const_cast<const Action &>(action_ptr_ref->wrap()), slot_handle_ref);
90 };
91
92 return foreach_action_slot_use_with_references(const_cast<ID &>(animated_id),
93 forward_to_callback);
94}
95
97 ID &animated_id,
98 FunctionRef<bool(ID &animated_id,
99 bAction *&action_ptr_ref,
100 slot_handle_t &slot_handle_ref,
101 char *last_slot_identifier)> callback)
102{
103 AnimData *adt = BKE_animdata_from_id(&animated_id);
104
105 if (adt) {
106 if (adt->action) {
107 /* Direct assignment. */
108 if (!callback(animated_id, adt->action, adt->slot_handle, adt->last_slot_identifier)) {
109 return false;
110 }
111 }
112
113 /* NLA strips. */
114 const bool looped_until_last_strip = bke::nla::foreach_strip_adt(*adt, [&](NlaStrip *strip) {
115 if (strip->act) {
116 if (!callback(
117 animated_id, strip->act, strip->action_slot_handle, strip->last_slot_identifier))
118 {
119 return false;
120 }
121 }
122 return true;
123 });
124 if (!looped_until_last_strip) {
125 return false;
126 }
127 }
128
129 /* The rest of the code deals with constraints, so only relevant when this is an Object. */
130 if (GS(animated_id.name) != ID_OB) {
131 return true;
132 }
133
134 const Object &object = reinterpret_cast<const Object &>(animated_id);
135
142 auto visit_constraint = [&](const bConstraint &constraint) -> bool {
143 if (constraint.type != CONSTRAINT_TYPE_ACTION) {
144 return true;
145 }
146 bActionConstraint *constraint_data = static_cast<bActionConstraint *>(constraint.data);
147 if (!constraint_data->act) {
148 return true;
149 }
150 return callback(animated_id,
151 constraint_data->act,
152 constraint_data->action_slot_handle,
153 constraint_data->last_slot_identifier);
154 };
155
156 /* Visit Object constraints. */
157 LISTBASE_FOREACH (bConstraint *, con, &object.constraints) {
158 if (!visit_constraint(*con)) {
159 return false;
160 }
161 }
162
163 /* Visit Pose Bone constraints. */
164 if (object.type == OB_ARMATURE) {
165 LISTBASE_FOREACH (bPoseChannel *, pchan, &object.pose->chanbase) {
166 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
167 if (!visit_constraint(*con)) {
168 return false;
169 }
170 }
171 }
172 }
173
174 return true;
175}
176
178 FunctionRef<bool(ID &animated_id,
179 bAction *action,
180 PointerRNA &action_slot_ptr,
181 PropertyRNA &action_slot_prop,
182 char *last_slot_identifier)> callback)
183{
184 /* This function has to copy the logic of #foreach_action_slot_use_with_references(),
185 * as it needs to know where exactly those pointers came from. */
186
187 AnimData *adt = BKE_animdata_from_id(&animated_id);
188
189 if (adt) {
190 if (adt->action) {
191 /* Direct assignment. */
192 PointerRNA ptr = RNA_pointer_create_discrete(&animated_id, &RNA_AnimData, adt);
193 PropertyRNA *prop = RNA_struct_find_property(&ptr, "action_slot");
194 if (!callback(animated_id, adt->action, ptr, *prop, adt->last_slot_identifier)) {
195 return false;
196 }
197 }
198
199 /* NLA strips. */
200 const bool looped_until_last_strip = bke::nla::foreach_strip_adt(*adt, [&](NlaStrip *strip) {
201 if (strip->act) {
202 PointerRNA ptr = RNA_pointer_create_discrete(&animated_id, &RNA_NlaStrip, strip);
203 PropertyRNA *prop = RNA_struct_find_property(&ptr, "action_slot");
204
205 if (!callback(animated_id, strip->act, ptr, *prop, strip->last_slot_identifier)) {
206 return false;
207 }
208 }
209 return true;
210 });
211 if (!looped_until_last_strip) {
212 return false;
213 }
214 }
215
216 /* The rest of the code deals with constraints, so only relevant when this is an Object. */
217 if (GS(animated_id.name) != ID_OB) {
218 return true;
219 }
220
221 const Object &object = reinterpret_cast<const Object &>(animated_id);
222
229 auto visit_constraint = [&](bConstraint &constraint) -> bool {
230 if (constraint.type != CONSTRAINT_TYPE_ACTION) {
231 return true;
232 }
233 bActionConstraint *constraint_data = static_cast<bActionConstraint *>(constraint.data);
234 if (!constraint_data->act) {
235 return true;
236 }
237
238 PointerRNA ptr = RNA_pointer_create_discrete(&animated_id, &RNA_ActionConstraint, &constraint);
239 PropertyRNA *prop = RNA_struct_find_property(&ptr, "action_slot");
240
241 return callback(
242 animated_id, constraint_data->act, ptr, *prop, constraint_data->last_slot_identifier);
243 };
244
245 /* Visit Object constraints. */
246 LISTBASE_FOREACH (bConstraint *, con, &object.constraints) {
247 if (!visit_constraint(*con)) {
248 return false;
249 }
250 }
251
252 /* Visit Pose Bone constraints. */
253 if (object.type == OB_ARMATURE) {
254 LISTBASE_FOREACH (bPoseChannel *, pchan, &object.pose->chanbase) {
255 LISTBASE_FOREACH (bConstraint *, con, &pchan->constraints) {
256 if (!visit_constraint(*con)) {
257 return false;
258 }
259 }
260 }
261 }
262
263 return true;
264}
265
266} // 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:82
#define BLI_assert(a)
Definition BLI_assert.h:46
#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
blender::Span< const Channelbag * > channelbags() const
#define GS(a)
void foreach_fcurve_in_action_slot(Action &action, slot_handle_t handle, FunctionRef< void(FCurve &fcurve)> callback)
void foreach_fcurve_in_action(Action &action, FunctionRef< void(FCurve &fcurve)> callback)
decltype(::ActionSlot::handle) slot_handle_t
bool foreach_action_slot_use_with_rna(ID &animated_id, FunctionRef< bool(ID &animated_id, bAction *action, PointerRNA &action_slot_owner_ptr, PropertyRNA &action_slot_prop, char *last_slot_identifier)> callback)
bool foreach_action_slot_use_with_references(ID &animated_id, FunctionRef< bool(ID &animated_id, bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *last_slot_identifier)> callback)
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)
PropertyRNA * RNA_struct_find_property(PointerRNA *ptr, const char *identifier)
PointerRNA RNA_pointer_create_discrete(ID *id, StructRNA *type, void *data)
bAction * action
int32_t slot_handle
char last_slot_identifier[66]
Definition DNA_ID.h:404
char name[66]
Definition DNA_ID.h:415
char last_slot_identifier[66]
int32_t action_slot_handle
bAction * act
ListBase curves
PointerRNA * ptr
Definition wm_files.cc:4226