Blender V4.3
action_legacy.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
5#include "ANIM_action.hh"
7
9
10#include "BKE_fcurve.hh"
11
13
15{
16 for (Layer *layer : action.layers()) {
17 for (Strip *strip : layer->strips()) {
18 if (strip->type() == Strip::Type::Keyframe) {
19 return strip;
20 }
21 }
22 }
23
24 return nullptr;
25}
26
28{
29 if (action.slots().is_empty()) {
30 return nullptr;
31 }
32
33 Strip *keystrip = first_keyframe_strip(action);
34 if (!keystrip) {
35 return nullptr;
36 }
37
38 return keystrip->data<StripKeyframeData>(action).channelbag_for_slot(*action.slot(0));
39}
40
42{
44
45 /* Ensure a Slot. */
46 Slot *slot;
47 if (action.slots().is_empty()) {
48 slot = &action.slot_add();
49 }
50 else {
51 slot = action.slot(0);
52 }
53
54 /* Ensure a Layer + keyframe Strip. */
55 action.layer_keystrip_ensure();
56 Strip &keystrip = *action.layer(0)->strip(0);
57
58 /* Ensure a ChannelBag. */
59 return keystrip.data<StripKeyframeData>(action).channelbag_for_slot_ensure(*slot);
60}
61
62/* Lots of template args to support transparent non-const and const versions. */
63template<typename ActionType,
64 typename FCurveType,
65 typename LayerType,
66 typename StripType,
67 typename StripKeyframeDataType,
68 typename ChannelBagType>
70{
71#ifdef WITH_ANIM_BAKLAVA
72 /* Legacy Action. */
73 if (action.is_action_legacy()) {
74#endif /* WITH_ANIM_BAKLAVA */
75 Vector<FCurveType *> legacy_fcurves;
76 LISTBASE_FOREACH (FCurveType *, fcurve, &action.curves) {
77 legacy_fcurves.append(fcurve);
78 }
79 return legacy_fcurves;
80#ifdef WITH_ANIM_BAKLAVA
81 }
82
83 /* Layered Action. */
84 BLI_assert(action.is_action_layered());
85
86 Vector<FCurveType *> all_fcurves;
87 for (LayerType *layer : action.layers()) {
88 for (StripType *strip : layer->strips()) {
89 switch (strip->type()) {
90 case Strip::Type::Keyframe: {
91 StripKeyframeDataType &strip_data = strip->template data<StripKeyframeData>(action);
92 for (ChannelBagType *bag : strip_data.channelbags()) {
93 for (FCurveType *fcurve : bag->fcurves()) {
94 all_fcurves.append(fcurve);
95 }
96 }
97 }
98 }
99 }
100 }
101 return all_fcurves;
102#endif /* WITH_ANIM_BAKLAVA */
103}
104
106{
107 if (!action) {
108 return {};
109 }
111 action->wrap());
112}
113
115{
116 if (!action) {
117 return {};
118 }
119 return fcurves_all_templated<const Action,
120 const FCurve,
121 const Layer,
122 const Strip,
123 const StripKeyframeData,
124 const ChannelBag>(action->wrap());
125}
126
127/* Lots of template args to support transparent non-const and const versions. */
128template<typename ActionType,
129 typename FCurveType,
130 typename LayerType,
131 typename StripType,
132 typename StripKeyframeDataType,
133 typename ChannelBagType>
135 const slot_handle_t slot_handle)
136{
137#ifndef WITH_ANIM_BAKLAVA
138 UNUSED_VARS(slot_handle);
139#endif /* !WITH_ANIM_BAKLAVA */
140
141#ifdef WITH_ANIM_BAKLAVA
142 /* Legacy Action. */
143 if (action.is_action_legacy()) {
144#endif /* WITH_ANIM_BAKLAVA */
145 return listbase_to_vector<FCurveType>(action.curves);
146#ifdef WITH_ANIM_BAKLAVA
147 }
148
149 /* Layered Action. */
150 Vector<FCurveType *> as_vector(animrig::fcurves_for_action_slot(action, slot_handle));
151 return as_vector;
152#endif /* WITH_ANIM_BAKLAVA */
153}
154
156{
157 if (!action) {
158 return {};
159 }
161 FCurve,
162 Layer,
163 Strip,
165 ChannelBag>(action->wrap(), slot_handle);
166}
168 const slot_handle_t slot_handle)
169{
170 if (!action) {
171 return {};
172 }
174 const FCurve,
175 const Layer,
176 const Strip,
177 const StripKeyframeData,
178 const ChannelBag>(action->wrap(), slot_handle);
179}
180
182{
183 if (!adt || !adt->action) {
184 return {};
185 }
187}
189{
190 if (!adt || !adt->action) {
191 return {};
192 }
193 return legacy::fcurves_for_action_slot(const_cast<const bAction *>(adt->action),
194 adt->slot_handle);
195}
196
198{
199 if (adt == nullptr || adt->action == nullptr) {
200 return false;
201 }
202
203 Action &action = adt->action->wrap();
204
205 if (action.is_action_legacy()) {
206 return action.curves.first != nullptr;
207 }
208
209 return action.has_keyframes(adt->slot_handle);
210}
211
213{
214 if (!action) {
215 return {};
216 }
217
218 Action &action_wrap = action->wrap();
219
220#ifdef WITH_ANIM_BAKLAVA
221 /* Legacy Action. */
222 if (action_wrap.is_action_legacy()) {
223#endif /* WITH_ANIM_BAKLAVA */
224 Vector<bActionGroup *> legacy_groups;
225 LISTBASE_FOREACH (bActionGroup *, group, &action_wrap.groups) {
226 legacy_groups.append(group);
227 }
228 return legacy_groups;
229#ifdef WITH_ANIM_BAKLAVA
230 }
231
232 /* Layered Action. */
233 Vector<bActionGroup *> all_groups;
234 for (Layer *layer : action_wrap.layers()) {
235 for (Strip *strip : layer->strips()) {
236 switch (strip->type()) {
237 case Strip::Type::Keyframe: {
238 StripKeyframeData &strip_data = strip->template data<StripKeyframeData>(action_wrap);
239 for (ChannelBag *bag : strip_data.channelbags()) {
240 all_groups.extend(bag->channel_groups());
241 }
242 }
243 }
244 }
245 }
246 return all_groups;
247#endif /* WITH_ANIM_BAKLAVA */
248}
249
251{
252 if (!adt || !adt->action) {
253 return {};
254 }
255
256 Action &action = adt->action->wrap();
257
258 /* Legacy Action. */
259 if (action.is_action_legacy()) {
260 return channel_groups_all(adt->action);
261 }
262
263 /* Layered Action. */
265 if (!bag) {
266 return {};
267 }
268
269 Vector<bActionGroup *> slot_groups(bag->channel_groups());
270 return slot_groups;
271}
272
274{
275 const Action &action_wrap = action.wrap();
276 if (action_wrap.is_empty()) {
277 const bool may_do_layered = USER_EXPERIMENTAL_TEST(&U, use_animation_baklava);
278 return !may_do_layered;
279 }
280 return action_wrap.is_action_legacy();
281}
282
284 const slot_handle_t slot_handle,
285 const StringRefNull rna_path_prefix)
286{
287 BLI_assert(!rna_path_prefix.is_empty());
288 if (rna_path_prefix.is_empty()) {
289 return false;
290 }
291
292 Action &action_wrapped = action.wrap();
293
294 /* Legacy Action. Code is 'borrowed' from fcurves_path_remove_fix() in
295 * blenkernel/intern/anim_data.cc */
296 if (action_wrapped.is_action_legacy()) {
297 bool any_removed = false;
298 LISTBASE_FOREACH_MUTABLE (FCurve *, fcurve, &action.curves) {
299 if (!fcurve->rna_path) {
300 continue;
301 }
302
303 if (STRPREFIX(fcurve->rna_path, rna_path_prefix.c_str())) {
304 BLI_remlink(&action.curves, fcurve);
305 BKE_fcurve_free(fcurve);
306 any_removed = true;
307 }
308 }
309 return any_removed;
310 }
311
312 /* Layered Action. */
313 ChannelBag *bag = channelbag_for_action_slot(action.wrap(), slot_handle);
314 if (!bag) {
315 return false;
316 }
317
318 bool any_removed = false;
319 for (int64_t fcurve_index = 0; fcurve_index < bag->fcurve_array_num; fcurve_index++) {
320 FCurve *fcurve = bag->fcurve(fcurve_index);
321 if (!fcurve->rna_path) {
322 continue;
323 }
324
325 if (STRPREFIX(fcurve->rna_path, rna_path_prefix.c_str())) {
326 bag->fcurve_remove_by_index(fcurve_index);
327 fcurve_index--;
328 any_removed = true;
329 }
330 }
331 return any_removed;
332}
333
334} // namespace blender::animrig::legacy
Functions and classes to work with Actions.
Functions for backward compatibility with the legacy Action API.
void BKE_fcurve_free(FCurve *fcu)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define LISTBASE_FOREACH(type, var, list)
#define LISTBASE_FOREACH_MUTABLE(type, var, list)
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:130
#define STRPREFIX(a, b)
#define UNUSED_VARS(...)
struct FCurve FCurve
struct Strip Strip
#define USER_EXPERIMENTAL_TEST(userdef, member)
unsigned int U
Definition btGjkEpa3.h:78
constexpr bool is_empty() const
constexpr const char * c_str() const
void append(const T &value)
void extend(Span< T > array)
const Layer * layer(int64_t index) const
const Slot * slot(int64_t index) const
blender::Span< const Layer * > layers() const
bool has_keyframes(slot_handle_t action_slot_handle) const ATTR_WARN_UNUSED_RESULT
blender::Span< const Slot * > slots() const
const FCurve * fcurve(int64_t index) const
void fcurve_remove_by_index(int64_t fcurve_array_index)
blender::Span< const bActionGroup * > channel_groups() const
const Strip * strip(int64_t index) const
blender::Span< const ChannelBag * > channelbags() const
const T & data(const Action &owning_action) const
ChannelBag & channelbag_ensure(Action &action)
Vector< FCurve * > fcurves_for_action_slot(bAction *action, slot_handle_t slot_handle)
static Vector< FCurveType * > fcurves_all_templated(ActionType &action)
Vector< bActionGroup * > channel_groups_for_assigned_slot(AnimData *adt)
Vector< const FCurve * > fcurves_all(const bAction *action)
static Strip * first_keyframe_strip(Action &action)
bool action_fcurves_remove(bAction &action, slot_handle_t slot_handle, StringRefNull rna_path_prefix)
Vector< FCurve * > fcurves_for_assigned_action(AnimData *adt)
ChannelBag * channelbag_get(Action &action)
bool assigned_action_has_keyframes(AnimData *adt)
Vector< bActionGroup * > channel_groups_all(bAction *action)
static Vector< FCurveType * > fcurves_for_action_slot_templated(ActionType &action, const slot_handle_t slot_handle)
bool action_treat_as_legacy(const bAction &action)
void assert_baklava_phase_1_invariants(const Action &action)
Span< FCurve * > fcurves_for_action_slot(Action &action, slot_handle_t slot_handle)
decltype(::ActionSlot::handle) slot_handle_t
const animrig::ChannelBag * channelbag_for_action_slot(const Action &action, slot_handle_t slot_handle)
Vector< T * > listbase_to_vector(ListBase &list)
__int64 int64_t
Definition stdint.h:89
bAction * action
int32_t slot_handle
char * rna_path
void * first
ListBase curves
ListBase groups