Refactor: rename "Animation data-block" to "Action"

Rename "Animation data-block" to "Action" or "Layered Action", where
appropriate. Some uses of the term actually refer to the `AnimData`
struct, in which case they were left as-is.

No real functional changes, just changing some messages & descriptions.

Pull Request: https://projects.blender.org/blender/blender/pulls/124170
This commit is contained in:
Sybren A. Stüvel 2024-07-05 17:01:50 +02:00
parent c0364efec0
commit 0aa75ab57b
24 changed files with 360 additions and 360 deletions

@ -113,7 +113,7 @@ def _wm_selected_action_update(wm, context):
def register_props(): def register_props():
# Due to this hackyness, the WindowManager will increase the user count of # Due to this hackyness, the WindowManager will increase the user count of
# the pointed-to Animation data-block. # the pointed-to Action.
WindowManager.selected_action = PointerProperty( WindowManager.selected_action = PointerProperty(
type=bpy.types.Action, type=bpy.types.Action,
name="Action", name="Action",

@ -101,7 +101,7 @@ class Action : public ::bAction {
*/ */
bool is_action_layered() const; bool is_action_layered() const;
/* Animation Layers access. */ /* Action Layers access. */
blender::Span<const Layer *> layers() const; blender::Span<const Layer *> layers() const;
blender::MutableSpan<Layer *> layers(); blender::MutableSpan<Layer *> layers();
const Layer *layer(int64_t index) const; const Layer *layer(int64_t index) const;
@ -110,7 +110,7 @@ class Action : public ::bAction {
Layer &layer_add(StringRefNull name); Layer &layer_add(StringRefNull name);
/** /**
* Remove the layer from this animation. * Remove the layer from this Action.
* *
* After this call, the passed reference is no longer valid, as the memory * After this call, the passed reference is no longer valid, as the memory
* will have been freed. Any strips on the layer will be freed too. * will have been freed. Any strips on the layer will be freed too.
@ -125,7 +125,7 @@ class Action : public ::bAction {
*/ */
void layer_ensure_at_least_one(); void layer_ensure_at_least_one();
/* Animation Slot access. */ /* Action Slot access. */
blender::Span<const Slot *> slots() const; blender::Span<const Slot *> slots() const;
blender::MutableSpan<Slot *> slots(); blender::MutableSpan<Slot *> slots();
const Slot *slot(int64_t index) const; const Slot *slot(int64_t index) const;
@ -146,8 +146,8 @@ class Action : public ::bAction {
* Set the slot name, ensure it is unique, and propagate the new name to * Set the slot name, ensure it is unique, and propagate the new name to
* all data-blocks that use it. * all data-blocks that use it.
* *
* This has to be done on the Animation level to ensure each slot has a * This has to be done on the Action level to ensure each slot has a
* unique name within the Animation. * unique name within the Action.
* *
* \note This does NOT ensure the first two characters match the ID type of * \note This does NOT ensure the first two characters match the ID type of
* this slot. This is the caller's responsibility. * this slot. This is the caller's responsibility.
@ -191,7 +191,7 @@ class Action : public ::bAction {
/** /**
* Create a new slot, named after the given ID, and limited to the ID's type. * Create a new slot, named after the given ID, and limited to the ID's type.
* *
* Note that this assigns neither this Animation nor the new Slot to the ID. This function * Note that this assigns neither this Action nor the new Slot to the ID. This function
* merely initializes the Slot itself to suitable values to start animating this ID. * merely initializes the Slot itself to suitable values to start animating this ID.
*/ */
Slot &slot_add_for_id(const ID &animated_id); Slot &slot_add_for_id(const ID &animated_id);
@ -216,21 +216,21 @@ class Action : public ::bAction {
*/ */
Slot &slot_ensure_for_id(const ID &animated_id); Slot &slot_ensure_for_id(const ID &animated_id);
/** Assign this animation to the ID. /** Assign this Action to the ID.
* *
* \param slot: The slot this ID should be animated by, may be nullptr if it is to be * \param slot: The slot this ID should be animated by, may be nullptr if it is to be
* assigned later. In that case, the ID will not actually receive any animation. * assigned later. In that case, the ID will not actually receive any animation.
* \param animated_id: The ID that should be animated by this Animation data-block. * \param animated_id: The ID that should be animated by this Action.
* *
* \return whether the assignment was successful. * \return whether the assignment was successful.
*/ */
bool assign_id(Slot *slot, ID &animated_id); bool assign_id(Slot *slot, ID &animated_id);
/** /**
* Unassign this Animation from the animated ID. * Unassign this Action from the animated ID.
* *
* \param animated_id: ID that is animated by this Animation. Calling this * \param animated_id: ID that is animated by this Action. Calling this
* function when this ID is _not_ animated by this Animation is not allowed, * function when this ID is _not_ animated by this Action is not allowed,
* and considered a bug. * and considered a bug.
*/ */
void unassign_id(ID &animated_id); void unassign_id(ID &animated_id);
@ -238,19 +238,19 @@ class Action : public ::bAction {
/** /**
* Find the slot that best matches the animated ID. * Find the slot that best matches the animated ID.
* *
* If the ID is already animated by this Animation, by matching this * If the ID is already animated by this Action, by matching this
* Animation's slots with (in order): * Action's slots with (in order):
* *
* - `animated_id.adt->slot_handle`, * - `animated_id.adt->slot_handle`,
* - `animated_id.adt->slot_name`, * - `animated_id.adt->slot_name`,
* - `animated_id.name`. * - `animated_id.name`.
* *
* Note that this is different from #slot_for_id, which does not use the * Note that this is different from #slot_for_id, which does not use the
* slot name, and only works when this Animation is already assigned. */ * slot name, and only works when this Action is already assigned. */
Slot *find_suitable_slot_for(const ID &animated_id); Slot *find_suitable_slot_for(const ID &animated_id);
/** /**
* Return whether this Animation actually has any animation data for the given slot. * Return whether this Action actually has any animation data for the given slot.
*/ */
bool is_slot_animated(slot_handle_t slot_handle) const; bool is_slot_animated(slot_handle_t slot_handle) const;
@ -264,7 +264,7 @@ class Action : public ::bAction {
Layer *get_layer_for_keyframing(); Layer *get_layer_for_keyframing();
protected: protected:
/** Return the layer's index, or -1 if not found in this animation. */ /** Return the layer's index, or -1 if not found in this Action. */
int64_t find_layer_index(const Layer &layer) const; int64_t find_layer_index(const Layer &layer) const;
private: private:
@ -283,7 +283,7 @@ class Action : public ::bAction {
/** /**
* Set the slot's ID type to that of the animated ID, ensure the name * Set the slot's ID type to that of the animated ID, ensure the name
* prefix is set accordingly, and that the name is unique within the * prefix is set accordingly, and that the name is unique within the
* Animation. * Action.
* *
* \note This assumes that the slot has no ID type set yet. If it does, it * \note This assumes that the slot has no ID type set yet. If it does, it
* is considered a bug to call this function. * is considered a bug to call this function.
@ -575,7 +575,7 @@ class Slot : public ::ActionSlot {
/** /**
* Ensure the first two characters of the name match the ID type. * Ensure the first two characters of the name match the ID type.
* *
* \note This does NOT ensure name uniqueness within the Animation. That is * \note This does NOT ensure name uniqueness within the Action. That is
* the responsibility of the caller. * the responsibility of the caller.
*/ */
void name_ensure_prefix(); void name_ensure_prefix();
@ -677,7 +677,7 @@ static_assert(sizeof(ChannelBag) == sizeof(::ActionChannelBag),
"DNA struct and its C++ wrapper must have the same size"); "DNA struct and its C++ wrapper must have the same size");
/** /**
* Assign the animation to the ID. * Assign the Action to the ID.
* *
* This will will make a best-effort guess as to which slot to use, in this * This will will make a best-effort guess as to which slot to use, in this
* order; * order;
@ -691,9 +691,9 @@ static_assert(sizeof(ChannelBag) == sizeof(::ActionChannelBag),
* *
* \return `false` if the assignment was not possible (for example the ID is of a type that cannot * \return `false` if the assignment was not possible (for example the ID is of a type that cannot
* be animated). If the above fall-through case of "no slot found" is reached, this function * be animated). If the above fall-through case of "no slot found" is reached, this function
* will still return `true` as the Animation was successfully assigned. * will still return `true` as the Action was successfully assigned.
*/ */
bool assign_animation(Action &anim, ID &animated_id); bool assign_action(Action &action, ID &animated_id);
/** /**
* Return whether the given Action can be assigned to the ID. * Return whether the given Action can be assigned to the ID.
@ -706,10 +706,10 @@ bool is_action_assignable_to(const bAction *dna_action, ID_Type id_code);
/** /**
* Ensure that this ID is no longer animated. * Ensure that this ID is no longer animated.
*/ */
void unassign_animation(ID &animated_id); void unassign_action(ID &animated_id);
/** /**
* Clear the animation slot of this ID. * Clear the Action slot of this ID.
* *
* `adt.slot_handle_name` is updated to reflect the current name of the * `adt.slot_handle_name` is updated to reflect the current name of the
* slot, before un-assigning. This is to ensure that the stored name reflects * slot, before un-assigning. This is to ensure that the stored name reflects
@ -717,14 +717,14 @@ void unassign_animation(ID &animated_id);
* *
* \param animated_id: the animated ID. * \param animated_id: the animated ID.
* *
* \note this does not clear the Animation pointer, just the slot handle. * \note this does not clear the Action pointer, just the slot handle.
*/ */
void unassign_slot(ID &animated_id); void unassign_slot(ID &animated_id);
/** /**
* Return the Animation of this ID, or nullptr if it has none. * Return the Action of this ID, or nullptr if it has none.
*/ */
Action *get_animation(ID &animated_id); Action *get_action(ID &animated_id);
/** /**
* Get the Action and the Slot that animate this ID. * Get the Action and the Slot that animate this ID.
@ -740,33 +740,33 @@ std::optional<std::pair<Action *, Slot *>> get_action_slot_pair(ID &animated_id)
/** /**
* Return the F-Curves for this specific slot handle. * Return the F-Curves for this specific slot handle.
* *
* This is just a utility function, that's intended to become obsolete when multi-layer animation * This is just a utility function, that's intended to become obsolete when multi-layer Actions
* is introduced. However, since Blender currently only supports a single layer with a single * are introduced. However, since Blender currently only supports a single layer with a single
* strip, of a single type, this function can be used. * strip, of a single type, this function can be used.
* *
* The use of this function is also an indicator for code that will have to be altered when * The use of this function is also an indicator for code that will have to be altered when
* multi-layered animation is getting implemented. * multi-layered Actions are getting implemented.
*/ */
Span<FCurve *> fcurves_for_animation(Action &anim, slot_handle_t slot_handle); Span<FCurve *> fcurves_for_action_slot(Action &action, slot_handle_t slot_handle);
Span<const FCurve *> fcurves_for_animation(const Action &anim, slot_handle_t slot_handle); Span<const FCurve *> fcurves_for_action_slot(const Action &action, slot_handle_t slot_handle);
/** /**
* Return all F-Curves in the Action. * Return all F-Curves in the Action.
* *
* This works for both legacy and layered Actions. * This works for both legacy and layered Actions.
* *
* This is a utility function whose purpose is unclear after multi-layer animation is introduced. * This is a utility function whose purpose is unclear after multi-layer Actions are introduced.
* It might still be useful, it might not be. * It might still be useful, it might not be.
* The use of this function is an indicator for code that might have to be altered when * The use of this function is an indicator for code that might have to be altered when
* multi-layered animation is getting implemented. * multi-layered Actions are getting implemented.
*/ */
Vector<const FCurve *> fcurves_all(const Action &action); Vector<const FCurve *> fcurves_all(const Action &action);
Vector<FCurve *> fcurves_all(Action &action); Vector<FCurve *> fcurves_all(Action &action);
/** /**
* Get (or add relevant data to be able to do so) F-Curve from the given Action, * Get (or add relevant data to be able to do so) an F-Curve from the given Action,
* for the given Animation Data block. This assumes that all the destinations are valid. * for the given animated data-block. This assumes that all the destinations are valid.
* \param ptr: can be a null pointer. * \param ptr: can be a null pointer.
*/ */
FCurve *action_fcurve_ensure(Main *bmain, FCurve *action_fcurve_ensure(Main *bmain,

@ -5,7 +5,7 @@
/** \file /** \file
* \ingroup animrig * \ingroup animrig
* *
* \brief Animation data-block evaluation. * \brief Layered Action evaluation.
*/ */
#pragma once #pragma once
@ -26,10 +26,10 @@ namespace blender::animrig {
* \param flush_to_original: when true, look up the original data-block (assuming * \param flush_to_original: when true, look up the original data-block (assuming
* the given one is an evaluated copy) and update that too. * the given one is an evaluated copy) and update that too.
*/ */
void evaluate_and_apply_animation(PointerRNA &animated_id_ptr, void evaluate_and_apply_action(PointerRNA &animated_id_ptr,
Action &animation, Action &action,
slot_handle_t slot_handle, slot_handle_t slot_handle,
const AnimationEvalContext &anim_eval_context, const AnimationEvalContext &anim_eval_context,
bool flush_to_original); bool flush_to_original);
} // namespace blender::animrig } // namespace blender::animrig

@ -52,7 +52,7 @@ namespace blender::animrig {
namespace { namespace {
/** /**
* Default name for animation slots. The first two characters in the name indicate the ID type * Default name for action slots. The first two characters in the name indicate the ID type
* of whatever is animated by it. * of whatever is animated by it.
* *
* Since the ID type may not be determined when the slot is created, the prefix starts out at * Since the ID type may not be determined when the slot is created, the prefix starts out at
@ -95,7 +95,7 @@ template<typename T> static void grow_array(T **array, int *num, const int add_n
BLI_assert(add_num > 0); BLI_assert(add_num > 0);
const int new_array_num = *num + add_num; const int new_array_num = *num + add_num;
T *new_array = reinterpret_cast<T *>( T *new_array = reinterpret_cast<T *>(
MEM_cnew_array<T *>(new_array_num, "animrig::animation/grow_array")); MEM_cnew_array<T *>(new_array_num, "animrig::action/grow_array"));
blender::uninitialized_relocate_n(*array, *num, new_array); blender::uninitialized_relocate_n(*array, *num, new_array);
MEM_SAFE_FREE(*array); MEM_SAFE_FREE(*array);
@ -123,7 +123,7 @@ template<typename T> static void shrink_array(T **array, int *num, const int shr
*num = new_array_num; *num = new_array_num;
} }
/* ----- Animation implementation ----------- */ /* ----- Action implementation ----------- */
bool Action::is_empty() const bool Action::is_empty() const
{ {
@ -262,19 +262,19 @@ const Slot *Action::slot_for_handle(const slot_handle_t handle) const
return nullptr; return nullptr;
} }
static void anim_slot_name_ensure_unique(Action &animation, Slot &slot) static void slot_name_ensure_unique(Action &action, Slot &slot)
{ {
/* Cannot capture parameters by reference in the lambda, as that would change its signature /* Cannot capture parameters by reference in the lambda, as that would change its signature
* and no longer be compatible with BLI_uniquename_cb(). That's why this struct is necessary. */ * and no longer be compatible with BLI_uniquename_cb(). That's why this struct is necessary. */
struct DupNameCheckData { struct DupNameCheckData {
Action &anim; Action &action;
Slot &slot; Slot &slot;
}; };
DupNameCheckData check_data = {animation, slot}; DupNameCheckData check_data = {action, slot};
auto check_name_is_used = [](void *arg, const char *name) -> bool { auto check_name_is_used = [](void *arg, const char *name) -> bool {
DupNameCheckData *data = static_cast<DupNameCheckData *>(arg); DupNameCheckData *data = static_cast<DupNameCheckData *>(arg);
for (const Slot *slot : data->anim.slots()) { for (const Slot *slot : data->action.slots()) {
if (slot == &data->slot) { if (slot == &data->slot) {
/* Don't compare against the slot that's being renamed. */ /* Don't compare against the slot that's being renamed. */
continue; continue;
@ -302,9 +302,9 @@ void Action::slot_name_set(Main &bmain, Slot &slot, const StringRefNull new_name
void Action::slot_name_define(Slot &slot, const StringRefNull new_name) void Action::slot_name_define(Slot &slot, const StringRefNull new_name)
{ {
BLI_assert_msg(StringRef(new_name).size() >= Slot::name_length_min, BLI_assert_msg(StringRef(new_name).size() >= Slot::name_length_min,
"Animation Slots must be large enough for a 2-letter ID code + the display name"); "Action Slots must be large enough for a 2-letter ID code + the display name");
STRNCPY_UTF8(slot.name, new_name.c_str()); STRNCPY_UTF8(slot.name, new_name.c_str());
anim_slot_name_ensure_unique(*this, slot); slot_name_ensure_unique(*this, slot);
} }
void Action::slot_name_propagate(Main &bmain, const Slot &slot) void Action::slot_name_propagate(Main &bmain, const Slot &slot)
@ -322,7 +322,7 @@ void Action::slot_name_propagate(Main &bmain, const Slot &slot)
AnimData *adt = BKE_animdata_from_id(id); AnimData *adt = BKE_animdata_from_id(id);
if (!adt || adt->action != this) { if (!adt || adt->action != this) {
/* Not animated by this Animation. */ /* Not animated by this Action. */
continue; continue;
} }
if (adt->slot_handle != slot.handle) { if (adt->slot_handle != slot.handle) {
@ -352,7 +352,7 @@ Slot &Action::slot_allocate()
{ {
Slot &slot = *MEM_new<Slot>(__func__); Slot &slot = *MEM_new<Slot>(__func__);
this->last_slot_handle++; this->last_slot_handle++;
BLI_assert_msg(this->last_slot_handle > 0, "Animation Slot handle overflow"); BLI_assert_msg(this->last_slot_handle > 0, "Action Slot handle overflow");
slot.handle = this->last_slot_handle; slot.handle = this->last_slot_handle;
/* Set the default flags. These cannot be set via the 'DNA defaults' system, /* Set the default flags. These cannot be set via the 'DNA defaults' system,
@ -373,7 +373,7 @@ Slot &Action::slot_add()
/* Append the Slot to the Action. */ /* Append the Slot to the Action. */
grow_array_and_append<::ActionSlot *>(&this->slot_array, &this->slot_array_num, &slot); grow_array_and_append<::ActionSlot *>(&this->slot_array, &this->slot_array_num, &slot);
anim_slot_name_ensure_unique(*this, slot); slot_name_ensure_unique(*this, slot);
/* If this is the first slot in this Action, it means that it could have /* If this is the first slot in this Action, it means that it could have
* been used as a legacy Action before. As a result, this->idroot may be * been used as a legacy Action before. As a result, this->idroot may be
@ -444,7 +444,7 @@ bool Action::is_slot_animated(const slot_handle_t slot_handle) const
return false; return false;
} }
Span<const FCurve *> fcurves = fcurves_for_animation(*this, slot_handle); Span<const FCurve *> fcurves = fcurves_for_action_slot(*this, slot_handle);
return !fcurves.is_empty(); return !fcurves.is_empty();
} }
@ -468,7 +468,7 @@ bool Action::assign_id(Slot *slot, ID &animated_id)
if (adt->action && adt->action != this) { if (adt->action && adt->action != this) {
/* The caller should unassign the ID from its existing animation first, or /* The caller should unassign the ID from its existing animation first, or
* use the top-level function `assign_animation(anim, ID)`. */ * use the top-level function `assign_action(anim, ID)`. */
return false; return false;
} }
@ -520,7 +520,7 @@ bool Action::assign_id(Slot *slot, ID &animated_id)
void Action::slot_name_ensure_prefix(Slot &slot) void Action::slot_name_ensure_prefix(Slot &slot)
{ {
slot.name_ensure_prefix(); slot.name_ensure_prefix();
anim_slot_name_ensure_unique(*this, slot); slot_name_ensure_unique(*this, slot);
} }
void Action::slot_setup_for_id(Slot &slot, const ID &animated_id) void Action::slot_setup_for_id(Slot &slot, const ID &animated_id)
@ -747,12 +747,12 @@ void Slot::users_invalidate(Main &bmain)
/* ----- Functions ----------- */ /* ----- Functions ----------- */
bool assign_animation(Action &anim, ID &animated_id) bool assign_action(Action &action, ID &animated_id)
{ {
unassign_animation(animated_id); unassign_action(animated_id);
Slot *slot = anim.find_suitable_slot_for(animated_id); Slot *slot = action.find_suitable_slot_for(animated_id);
return anim.assign_id(slot, animated_id); return action.assign_id(slot, animated_id);
} }
bool is_action_assignable_to(const bAction *dna_action, const ID_Type id_code) bool is_action_assignable_to(const bAction *dna_action, const ID_Type id_code)
@ -779,13 +779,13 @@ bool is_action_assignable_to(const bAction *dna_action, const ID_Type id_code)
return true; return true;
} }
void unassign_animation(ID &animated_id) void unassign_action(ID &animated_id)
{ {
Action *anim = get_animation(animated_id); Action *action = get_action(animated_id);
if (!anim) { if (!action) {
return; return;
} }
anim->unassign_id(animated_id); action->unassign_id(animated_id);
} }
void unassign_slot(ID &animated_id) void unassign_slot(ID &animated_id)
@ -809,7 +809,7 @@ void unassign_slot(ID &animated_id)
} }
/* TODO: rename to get_action(). */ /* TODO: rename to get_action(). */
Action *get_animation(ID &animated_id) Action *get_action(ID &animated_id)
{ {
AnimData *adt = BKE_animdata_from_id(&animated_id); AnimData *adt = BKE_animdata_from_id(&animated_id);
if (!adt) { if (!adt) {
@ -1179,14 +1179,14 @@ const FCurve *ChannelBag::fcurve_find(const StringRefNull rna_path, const int ar
/* Utility function implementations. */ /* Utility function implementations. */
static const animrig::ChannelBag *channelbag_for_animation(const Action &anim, static const animrig::ChannelBag *channelbag_for_action_slot(const Action &action,
const slot_handle_t slot_handle) const slot_handle_t slot_handle)
{ {
if (slot_handle == Slot::unassigned) { if (slot_handle == Slot::unassigned) {
return nullptr; return nullptr;
} }
for (const animrig::Layer *layer : anim.layers()) { for (const animrig::Layer *layer : action.layers()) {
for (const animrig::Strip *strip : layer->strips()) { for (const animrig::Strip *strip : layer->strips()) {
switch (strip->type()) { switch (strip->type()) {
case animrig::Strip::Type::Keyframe: { case animrig::Strip::Type::Keyframe: {
@ -1203,25 +1203,26 @@ static const animrig::ChannelBag *channelbag_for_animation(const Action &anim,
return nullptr; return nullptr;
} }
static animrig::ChannelBag *channelbag_for_animation(Action &anim, const slot_handle_t slot_handle) static animrig::ChannelBag *channelbag_for_action_slot(Action &action,
const slot_handle_t slot_handle)
{ {
const animrig::ChannelBag *const_bag = channelbag_for_animation(const_cast<const Action &>(anim), const animrig::ChannelBag *const_bag = channelbag_for_action_slot(
slot_handle); const_cast<const Action &>(action), slot_handle);
return const_cast<animrig::ChannelBag *>(const_bag); return const_cast<animrig::ChannelBag *>(const_bag);
} }
Span<FCurve *> fcurves_for_animation(Action &anim, const slot_handle_t slot_handle) Span<FCurve *> fcurves_for_action_slot(Action &action, const slot_handle_t slot_handle)
{ {
animrig::ChannelBag *bag = channelbag_for_animation(anim, slot_handle); animrig::ChannelBag *bag = channelbag_for_action_slot(action, slot_handle);
if (!bag) { if (!bag) {
return {}; return {};
} }
return bag->fcurves(); return bag->fcurves();
} }
Span<const FCurve *> fcurves_for_animation(const Action &anim, const slot_handle_t slot_handle) Span<const FCurve *> fcurves_for_action_slot(const Action &action, const slot_handle_t slot_handle)
{ {
const animrig::ChannelBag *bag = channelbag_for_animation(anim, slot_handle); const animrig::ChannelBag *bag = channelbag_for_action_slot(action, slot_handle);
if (!bag) { if (!bag) {
return {}; return {};
} }

@ -27,7 +27,7 @@ namespace blender::animrig::tests {
class ActionLayersTest : public testing::Test { class ActionLayersTest : public testing::Test {
public: public:
Main *bmain; Main *bmain;
Action *anim; Action *action;
Object *cube; Object *cube;
Object *suzanne; Object *suzanne;
@ -48,7 +48,7 @@ class ActionLayersTest : public testing::Test {
void SetUp() override void SetUp() override
{ {
bmain = BKE_main_new(); bmain = BKE_main_new();
anim = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACÄnimåtië")); action = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACÄnimåtië"));
cube = BKE_object_add_only_object(bmain, OB_EMPTY, "Küüübus"); cube = BKE_object_add_only_object(bmain, OB_EMPTY, "Küüübus");
suzanne = BKE_object_add_only_object(bmain, OB_EMPTY, "OBSuzanne"); suzanne = BKE_object_add_only_object(bmain, OB_EMPTY, "OBSuzanne");
} }
@ -61,12 +61,12 @@ class ActionLayersTest : public testing::Test {
TEST_F(ActionLayersTest, add_layer) TEST_F(ActionLayersTest, add_layer)
{ {
Layer &layer = anim->layer_add("layer name"); Layer &layer = action->layer_add("layer name");
EXPECT_EQ(anim->layer(0), &layer); EXPECT_EQ(action->layer(0), &layer);
EXPECT_EQ("layer name", std::string(layer.name)); EXPECT_EQ("layer name", std::string(layer.name));
EXPECT_EQ(1.0f, layer.influence) << "Expected DNA defaults to be used."; EXPECT_EQ(1.0f, layer.influence) << "Expected DNA defaults to be used.";
EXPECT_EQ(0, anim->layer_active_index) EXPECT_EQ(0, action->layer_active_index)
<< "Expected newly added layer to become the active layer."; << "Expected newly added layer to become the active layer.";
ASSERT_EQ(0, layer.strips().size()) << "Expected newly added layer to have no strip."; ASSERT_EQ(0, layer.strips().size()) << "Expected newly added layer to have no strip.";
} }
@ -76,19 +76,20 @@ TEST_F(ActionLayersTest, add_layer__reset_idroot)
/* An empty Action is a valid legacy Action, and thus can have its idroot set to a non-zero /* An empty Action is a valid legacy Action, and thus can have its idroot set to a non-zero
* value. If such an Action gets a layer, it no longer is a valid legacy Action, and thus its * value. If such an Action gets a layer, it no longer is a valid legacy Action, and thus its
* idtype should be reset to zero. */ * idtype should be reset to zero. */
anim->idroot = ID_CA; /* Fake that this was assigned to a camera data-block. */ action->idroot = ID_CA; /* Fake that this was assigned to a camera data-block. */
ASSERT_NE(0, anim->idroot) << "anim->idroot should not be zero at the start of this test."; ASSERT_NE(0, action->idroot) << "action->idroot should not be zero at the start of this test.";
anim->layer_add("layer name"); action->layer_add("layer name");
EXPECT_EQ(0, anim->idroot) << "anim->idroot should get reset when the Action becomes layered."; EXPECT_EQ(0, action->idroot)
<< "action->idroot should get reset when the Action becomes layered.";
} }
TEST_F(ActionLayersTest, remove_layer) TEST_F(ActionLayersTest, remove_layer)
{ {
Layer &layer0 = anim->layer_add("Test Læür nul"); Layer &layer0 = action->layer_add("Test Læür nul");
Layer &layer1 = anim->layer_add("Test Læür één"); Layer &layer1 = action->layer_add("Test Læür één");
Layer &layer2 = anim->layer_add("Test Læür twee"); Layer &layer2 = action->layer_add("Test Læür twee");
/* Add some strips to check that they are freed correctly too (implicitly by the /* Add some strips to check that they are freed correctly too (implicitly by the
* memory leak checker). */ * memory leak checker). */
@ -99,27 +100,27 @@ TEST_F(ActionLayersTest, remove_layer)
{ /* Test removing a layer that is not owned. */ { /* Test removing a layer that is not owned. */
Action *other_anim = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACOtherAnim")); Action *other_anim = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACOtherAnim"));
Layer &other_layer = other_anim->layer_add("Another Layer"); Layer &other_layer = other_anim->layer_add("Another Layer");
EXPECT_FALSE(anim->layer_remove(other_layer)) EXPECT_FALSE(action->layer_remove(other_layer))
<< "Removing a layer not owned by the animation should be gracefully rejected"; << "Removing a layer not owned by the Action should be gracefully rejected";
BKE_id_free(bmain, &other_anim->id); BKE_id_free(bmain, &other_anim->id);
} }
EXPECT_TRUE(anim->layer_remove(layer1)); EXPECT_TRUE(action->layer_remove(layer1));
EXPECT_EQ(2, anim->layers().size()); EXPECT_EQ(2, action->layers().size());
EXPECT_STREQ(layer0.name, anim->layer(0)->name); EXPECT_STREQ(layer0.name, action->layer(0)->name);
EXPECT_STREQ(layer2.name, anim->layer(1)->name); EXPECT_STREQ(layer2.name, action->layer(1)->name);
EXPECT_TRUE(anim->layer_remove(layer2)); EXPECT_TRUE(action->layer_remove(layer2));
EXPECT_EQ(1, anim->layers().size()); EXPECT_EQ(1, action->layers().size());
EXPECT_STREQ(layer0.name, anim->layer(0)->name); EXPECT_STREQ(layer0.name, action->layer(0)->name);
EXPECT_TRUE(anim->layer_remove(layer0)); EXPECT_TRUE(action->layer_remove(layer0));
EXPECT_EQ(0, anim->layers().size()); EXPECT_EQ(0, action->layers().size());
} }
TEST_F(ActionLayersTest, add_strip) TEST_F(ActionLayersTest, add_strip)
{ {
Layer &layer = anim->layer_add("Test Læür"); Layer &layer = action->layer_add("Test Læür");
Strip &strip = layer.strip_add(Strip::Type::Keyframe); Strip &strip = layer.strip_add(Strip::Type::Keyframe);
ASSERT_EQ(1, layer.strips().size()); ASSERT_EQ(1, layer.strips().size());
@ -140,7 +141,7 @@ TEST_F(ActionLayersTest, add_strip)
/* Add some keys to check that also the strip data is freed correctly. */ /* Add some keys to check that also the strip data is freed correctly. */
const KeyframeSettings settings = get_keyframe_settings(false); const KeyframeSettings settings = get_keyframe_settings(false);
Slot &slot = anim->slot_add(); Slot &slot = action->slot_add();
strip.as<KeyframeStrip>().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings); strip.as<KeyframeStrip>().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings);
another_strip.as<KeyframeStrip>().keyframe_insert( another_strip.as<KeyframeStrip>().keyframe_insert(
slot, {"location", 0}, {1.0f, 47.0f}, settings); slot, {"location", 0}, {1.0f, 47.0f}, settings);
@ -148,14 +149,14 @@ TEST_F(ActionLayersTest, add_strip)
TEST_F(ActionLayersTest, remove_strip) TEST_F(ActionLayersTest, remove_strip)
{ {
Layer &layer = anim->layer_add("Test Læür"); Layer &layer = action->layer_add("Test Læür");
Strip &strip0 = layer.strip_add(Strip::Type::Keyframe); Strip &strip0 = layer.strip_add(Strip::Type::Keyframe);
Strip &strip1 = layer.strip_add(Strip::Type::Keyframe); Strip &strip1 = layer.strip_add(Strip::Type::Keyframe);
Strip &strip2 = layer.strip_add(Strip::Type::Keyframe); Strip &strip2 = layer.strip_add(Strip::Type::Keyframe);
/* Add some keys to check that also the strip data is freed correctly. */ /* Add some keys to check that also the strip data is freed correctly. */
const KeyframeSettings settings = get_keyframe_settings(false); const KeyframeSettings settings = get_keyframe_settings(false);
Slot &slot = anim->slot_add(); Slot &slot = action->slot_add();
strip0.as<KeyframeStrip>().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings); strip0.as<KeyframeStrip>().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings);
strip1.as<KeyframeStrip>().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings); strip1.as<KeyframeStrip>().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings);
strip2.as<KeyframeStrip>().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings); strip2.as<KeyframeStrip>().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings);
@ -173,7 +174,7 @@ TEST_F(ActionLayersTest, remove_strip)
EXPECT_EQ(0, layer.strips().size()); EXPECT_EQ(0, layer.strips().size());
{ /* Test removing a strip that is not owned. */ { /* Test removing a strip that is not owned. */
Layer &other_layer = anim->layer_add("Another Layer"); Layer &other_layer = action->layer_add("Another Layer");
Strip &other_strip = other_layer.strip_add(Strip::Type::Keyframe); Strip &other_strip = other_layer.strip_add(Strip::Type::Keyframe);
EXPECT_FALSE(layer.strip_remove(other_strip)) EXPECT_FALSE(layer.strip_remove(other_strip))
@ -183,7 +184,7 @@ TEST_F(ActionLayersTest, remove_strip)
TEST_F(ActionLayersTest, add_remove_strip_of_concrete_type) TEST_F(ActionLayersTest, add_remove_strip_of_concrete_type)
{ {
Layer &layer = anim->layer_add("Test Læür"); Layer &layer = action->layer_add("Test Læür");
KeyframeStrip &key_strip = layer.strip_add<KeyframeStrip>(); KeyframeStrip &key_strip = layer.strip_add<KeyframeStrip>();
/* key_strip is of type KeyframeStrip, but should be implicitly converted to a /* key_strip is of type KeyframeStrip, but should be implicitly converted to a
@ -194,8 +195,8 @@ TEST_F(ActionLayersTest, add_remove_strip_of_concrete_type)
TEST_F(ActionLayersTest, add_slot) TEST_F(ActionLayersTest, add_slot)
{ {
{ /* Creating an 'unused' Slot should just be called 'Slot'. */ { /* Creating an 'unused' Slot should just be called 'Slot'. */
Slot &slot = anim->slot_add(); Slot &slot = action->slot_add();
EXPECT_EQ(1, anim->last_slot_handle); EXPECT_EQ(1, action->last_slot_handle);
EXPECT_EQ(1, slot.handle); EXPECT_EQ(1, slot.handle);
EXPECT_STREQ("XXSlot", slot.name); EXPECT_STREQ("XXSlot", slot.name);
@ -203,8 +204,8 @@ TEST_F(ActionLayersTest, add_slot)
} }
{ /* Creating a Slot for a specific ID should name it after the ID. */ { /* Creating a Slot for a specific ID should name it after the ID. */
Slot &slot = anim->slot_add_for_id(cube->id); Slot &slot = action->slot_add_for_id(cube->id);
EXPECT_EQ(2, anim->last_slot_handle); EXPECT_EQ(2, action->last_slot_handle);
EXPECT_EQ(2, slot.handle); EXPECT_EQ(2, slot.handle);
EXPECT_STREQ(cube->id.name, slot.name); EXPECT_STREQ(cube->id.name, slot.name);
@ -217,33 +218,34 @@ TEST_F(ActionLayersTest, add_slot__reset_idroot)
/* An empty Action is a valid legacy Action, and thus can have its idroot set /* An empty Action is a valid legacy Action, and thus can have its idroot set
* to a non-zero value. If such an Action gets a slot, it no longer is a * to a non-zero value. If such an Action gets a slot, it no longer is a
* valid legacy Action, and thus its idtype should be reset to zero. */ * valid legacy Action, and thus its idtype should be reset to zero. */
anim->idroot = ID_CA; /* Fake that this was assigned to a camera data-block. */ action->idroot = ID_CA; /* Fake that this was assigned to a camera data-block. */
ASSERT_NE(0, anim->idroot) << "anim->idroot should not be zero at the start of this test."; ASSERT_NE(0, action->idroot) << "action->idroot should not be zero at the start of this test.";
anim->slot_add(); action->slot_add();
EXPECT_EQ(0, anim->idroot) << "anim->idroot should get reset when the Action becomes layered."; EXPECT_EQ(0, action->idroot)
<< "action->idroot should get reset when the Action becomes layered.";
} }
TEST_F(ActionLayersTest, add_slot_multiple) TEST_F(ActionLayersTest, add_slot_multiple)
{ {
Slot &bind_cube = anim->slot_add(); Slot &bind_cube = action->slot_add();
Slot &bind_suzanne = anim->slot_add(); Slot &bind_suzanne = action->slot_add();
EXPECT_TRUE(anim->assign_id(&bind_cube, cube->id)); EXPECT_TRUE(action->assign_id(&bind_cube, cube->id));
EXPECT_TRUE(anim->assign_id(&bind_suzanne, suzanne->id)); EXPECT_TRUE(action->assign_id(&bind_suzanne, suzanne->id));
EXPECT_EQ(2, anim->last_slot_handle); EXPECT_EQ(2, action->last_slot_handle);
EXPECT_EQ(1, bind_cube.handle); EXPECT_EQ(1, bind_cube.handle);
EXPECT_EQ(2, bind_suzanne.handle); EXPECT_EQ(2, bind_suzanne.handle);
} }
TEST_F(ActionLayersTest, anim_assign_id) TEST_F(ActionLayersTest, action_assign_id)
{ {
/* Assign to the only, 'virgin' Slot, should always work. */ /* Assign to the only, 'virgin' Slot, should always work. */
Slot &slot_cube = anim->slot_add(); Slot &slot_cube = action->slot_add();
ASSERT_NE(nullptr, slot_cube.runtime); ASSERT_NE(nullptr, slot_cube.runtime);
ASSERT_STREQ(slot_cube.name, "XXSlot"); ASSERT_STREQ(slot_cube.name, "XXSlot");
ASSERT_TRUE(anim->assign_id(&slot_cube, cube->id)); ASSERT_TRUE(action->assign_id(&slot_cube, cube->id));
EXPECT_EQ(slot_cube.handle, cube->adt->slot_handle); EXPECT_EQ(slot_cube.handle, cube->adt->slot_handle);
EXPECT_STREQ(slot_cube.name, "OBSlot"); EXPECT_STREQ(slot_cube.name, "OBSlot");
EXPECT_STREQ(slot_cube.name, cube->adt->slot_name) EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
@ -253,7 +255,7 @@ TEST_F(ActionLayersTest, anim_assign_id)
<< "Expecting Cube to be registered as animated by its slot."; << "Expecting Cube to be registered as animated by its slot.";
/* Assign another ID to the same Slot. */ /* Assign another ID to the same Slot. */
ASSERT_TRUE(anim->assign_id(&slot_cube, suzanne->id)); ASSERT_TRUE(action->assign_id(&slot_cube, suzanne->id));
EXPECT_STREQ(slot_cube.name, "OBSlot"); EXPECT_STREQ(slot_cube.name, "OBSlot");
EXPECT_STREQ(slot_cube.name, cube->adt->slot_name) EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
<< "The slot name should be copied to the adt"; << "The slot name should be copied to the adt";
@ -261,45 +263,45 @@ TEST_F(ActionLayersTest, anim_assign_id)
EXPECT_TRUE(slot_cube.users(*bmain).contains(&cube->id)) EXPECT_TRUE(slot_cube.users(*bmain).contains(&cube->id))
<< "Expecting Suzanne to be registered as animated by the Cube slot."; << "Expecting Suzanne to be registered as animated by the Cube slot.";
{ /* Assign Cube to another animation+slot without unassigning first. */ { /* Assign Cube to another action+slot without unassigning first. */
Action *another_anim = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACOtherAnim")); Action *another_anim = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACOtherAnim"));
Slot &another_slot = another_anim->slot_add(); Slot &another_slot = another_anim->slot_add();
ASSERT_FALSE(another_anim->assign_id(&another_slot, cube->id)) ASSERT_FALSE(another_anim->assign_id(&another_slot, cube->id))
<< "Assigning animation (with this function) when already assigned should fail."; << "Assigning Action (with this function) when already assigned should fail.";
EXPECT_TRUE(slot_cube.users(*bmain).contains(&cube->id)) EXPECT_TRUE(slot_cube.users(*bmain).contains(&cube->id))
<< "Expecting Cube to still be registered as animated by its slot."; << "Expecting Cube to still be registered as animated by its slot.";
} }
{ /* Assign Cube to another slot of the same Animation, this should work. */ { /* Assign Cube to another slot of the same Action, this should work. */
const int user_count_pre = anim->id.us; const int user_count_pre = action->id.us;
Slot &slot_cube_2 = anim->slot_add(); Slot &slot_cube_2 = action->slot_add();
ASSERT_TRUE(anim->assign_id(&slot_cube_2, cube->id)); ASSERT_TRUE(action->assign_id(&slot_cube_2, cube->id));
ASSERT_EQ(anim->id.us, user_count_pre) ASSERT_EQ(action->id.us, user_count_pre)
<< "Assigning to a different slot of the same animation should _not_ change the user " << "Assigning to a different slot of the same Action should _not_ change the user "
"count of that Animation"; "count of that Action";
EXPECT_FALSE(slot_cube.users(*bmain).contains(&cube->id)) EXPECT_FALSE(slot_cube.users(*bmain).contains(&cube->id))
<< "Expecting Cube to no longer be registered as animated by the Cube slot."; << "Expecting Cube to no longer be registered as animated by the Cube slot.";
EXPECT_TRUE(slot_cube_2.users(*bmain).contains(&cube->id)) EXPECT_TRUE(slot_cube_2.users(*bmain).contains(&cube->id))
<< "Expecting Cube to be registered as animated by the 'cube_2' slot."; << "Expecting Cube to be registered as animated by the 'cube_2' slot.";
} }
{ /* Unassign the animation. */ { /* Unassign the Action. */
const int user_count_pre = anim->id.us; const int user_count_pre = action->id.us;
anim->unassign_id(cube->id); action->unassign_id(cube->id);
ASSERT_EQ(anim->id.us, user_count_pre - 1) ASSERT_EQ(action->id.us, user_count_pre - 1)
<< "Unassigning an animation should lower its user count"; << "Unassigning an Action should lower its user count";
ASSERT_EQ(2, anim->slots().size()) << "Expecting the Action to have two Slots"; ASSERT_EQ(2, action->slots().size()) << "Expecting the Action to have two Slots";
EXPECT_FALSE(anim->slot(0)->users(*bmain).contains(&cube->id)) EXPECT_FALSE(action->slot(0)->users(*bmain).contains(&cube->id))
<< "Expecting Cube to no longer be registered as animated by any slot."; << "Expecting Cube to no longer be registered as animated by any slot.";
EXPECT_FALSE(anim->slot(1)->users(*bmain).contains(&cube->id)) EXPECT_FALSE(action->slot(1)->users(*bmain).contains(&cube->id))
<< "Expecting Cube to no longer be registered as animated by any slot."; << "Expecting Cube to no longer be registered as animated by any slot.";
} }
/* Assign Cube to another 'virgin' slot. This should not cause a name /* Assign Cube to another 'virgin' slot. This should not cause a name
* collision between the Slots. */ * collision between the Slots. */
Slot &another_slot_cube = anim->slot_add(); Slot &another_slot_cube = action->slot_add();
ASSERT_TRUE(anim->assign_id(&another_slot_cube, cube->id)); ASSERT_TRUE(action->assign_id(&another_slot_cube, cube->id));
EXPECT_EQ(another_slot_cube.handle, cube->adt->slot_handle); EXPECT_EQ(another_slot_cube.handle, cube->adt->slot_handle);
EXPECT_STREQ("OBSlot.002", another_slot_cube.name) << "The slot should be uniquely named"; EXPECT_STREQ("OBSlot.002", another_slot_cube.name) << "The slot should be uniquely named";
EXPECT_STREQ("OBSlot.002", cube->adt->slot_name) << "The slot name should be copied to the adt"; EXPECT_STREQ("OBSlot.002", cube->adt->slot_name) << "The slot name should be copied to the adt";
@ -308,7 +310,7 @@ TEST_F(ActionLayersTest, anim_assign_id)
/* Create an ID of another type. This should not be assignable to this slot. */ /* Create an ID of another type. This should not be assignable to this slot. */
ID *mesh = static_cast<ID *>(BKE_id_new_nomain(ID_ME, "Mesh")); ID *mesh = static_cast<ID *>(BKE_id_new_nomain(ID_ME, "Mesh"));
EXPECT_FALSE(anim->assign_id(&slot_cube, *mesh)) EXPECT_FALSE(action->assign_id(&slot_cube, *mesh))
<< "Mesh should not be animatable by an Object slot"; << "Mesh should not be animatable by an Object slot";
EXPECT_FALSE(another_slot_cube.users(*bmain).contains(mesh)) EXPECT_FALSE(another_slot_cube.users(*bmain).contains(mesh))
<< "Expecting Mesh to not be registered as animated by the 'slot_cube' slot."; << "Expecting Mesh to not be registered as animated by the 'slot_cube' slot.";
@ -317,28 +319,28 @@ TEST_F(ActionLayersTest, anim_assign_id)
TEST_F(ActionLayersTest, rename_slot) TEST_F(ActionLayersTest, rename_slot)
{ {
Slot &slot_cube = anim->slot_add(); Slot &slot_cube = action->slot_add();
ASSERT_TRUE(anim->assign_id(&slot_cube, cube->id)); ASSERT_TRUE(action->assign_id(&slot_cube, cube->id));
EXPECT_EQ(slot_cube.handle, cube->adt->slot_handle); EXPECT_EQ(slot_cube.handle, cube->adt->slot_handle);
EXPECT_STREQ("OBSlot", slot_cube.name); EXPECT_STREQ("OBSlot", slot_cube.name);
EXPECT_STREQ(slot_cube.name, cube->adt->slot_name) EXPECT_STREQ(slot_cube.name, cube->adt->slot_name)
<< "The slot name should be copied to the adt"; << "The slot name should be copied to the adt";
anim->slot_name_define(slot_cube, "New Slot Name"); action->slot_name_define(slot_cube, "New Slot Name");
EXPECT_STREQ("New Slot Name", slot_cube.name); EXPECT_STREQ("New Slot Name", slot_cube.name);
/* At this point the slot name will not have been copied to the cube /* At this point the slot name will not have been copied to the cube
* AnimData. However, I don't want to test for that here, as it's not exactly * AnimData. However, I don't want to test for that here, as it's not exactly
* desirable behavior, but more of a side-effect of the current * desirable behavior, but more of a side-effect of the current
* implementation. */ * implementation. */
anim->slot_name_propagate(*bmain, slot_cube); action->slot_name_propagate(*bmain, slot_cube);
EXPECT_STREQ("New Slot Name", cube->adt->slot_name); EXPECT_STREQ("New Slot Name", cube->adt->slot_name);
/* Finally, do another rename, do NOT call the propagate function, then /* Finally, do another rename, do NOT call the propagate function, then
* unassign. This should still result in the correct slot name being stored * unassign. This should still result in the correct slot name being stored
* on the ADT. */ * on the ADT. */
anim->slot_name_define(slot_cube, "Even Newer Name"); action->slot_name_define(slot_cube, "Even Newer Name");
anim->unassign_id(cube->id); action->unassign_id(cube->id);
EXPECT_STREQ("Even Newer Name", cube->adt->slot_name); EXPECT_STREQ("Even Newer Name", cube->adt->slot_name);
} }
@ -352,7 +354,7 @@ TEST_F(ActionLayersTest, slot_name_ensure_prefix)
} }
}; };
Slot &raw_slot = anim->slot_add(); Slot &raw_slot = action->slot_add();
AccessibleSlot &slot = static_cast<AccessibleSlot &>(raw_slot); AccessibleSlot &slot = static_cast<AccessibleSlot &>(raw_slot);
ASSERT_STREQ("XXSlot", slot.name); ASSERT_STREQ("XXSlot", slot.name);
ASSERT_EQ(0, slot.idtype); ASSERT_EQ(0, slot.idtype);
@ -367,7 +369,7 @@ TEST_F(ActionLayersTest, slot_name_ensure_prefix)
EXPECT_STREQ("CASlot", slot.name); EXPECT_STREQ("CASlot", slot.name);
/* idtype ME, explicit name of other idtype. */ /* idtype ME, explicit name of other idtype. */
anim->slot_name_define(slot, "CANewName"); action->slot_name_define(slot, "CANewName");
slot.idtype = ID_ME; slot.idtype = ID_ME;
slot.name_ensure_prefix(); slot.name_ensure_prefix();
EXPECT_STREQ("MENewName", slot.name); EXPECT_STREQ("MENewName", slot.name);
@ -380,7 +382,7 @@ TEST_F(ActionLayersTest, slot_name_ensure_prefix)
TEST_F(ActionLayersTest, slot_name_prefix) TEST_F(ActionLayersTest, slot_name_prefix)
{ {
Slot &slot = anim->slot_add(); Slot &slot = action->slot_add();
EXPECT_EQ("XX", slot.name_prefix_for_idtype()); EXPECT_EQ("XX", slot.name_prefix_for_idtype());
slot.idtype = ID_CA; slot.idtype = ID_CA;
@ -389,11 +391,11 @@ TEST_F(ActionLayersTest, slot_name_prefix)
TEST_F(ActionLayersTest, rename_slot_name_collision) TEST_F(ActionLayersTest, rename_slot_name_collision)
{ {
Slot &slot1 = anim->slot_add(); Slot &slot1 = action->slot_add();
Slot &slot2 = anim->slot_add(); Slot &slot2 = action->slot_add();
anim->slot_name_define(slot1, "New Slot Name"); action->slot_name_define(slot1, "New Slot Name");
anim->slot_name_define(slot2, "New Slot Name"); action->slot_name_define(slot2, "New Slot Name");
EXPECT_STREQ("New Slot Name", slot1.name); EXPECT_STREQ("New Slot Name", slot1.name);
EXPECT_STREQ("New Slot Name.001", slot2.name); EXPECT_STREQ("New Slot Name.001", slot2.name);
} }
@ -402,25 +404,25 @@ TEST_F(ActionLayersTest, find_suitable_slot)
{ {
/* === /* ===
* Empty case, no slots exist yet and the ID doesn't even have an AnimData. */ * Empty case, no slots exist yet and the ID doesn't even have an AnimData. */
EXPECT_EQ(nullptr, anim->find_suitable_slot_for(cube->id)); EXPECT_EQ(nullptr, action->find_suitable_slot_for(cube->id));
/* === /* ===
* Slot exists with the same name & type as the ID, but the ID doesn't have any AnimData yet. * Slot exists with the same name & type as the ID, but the ID doesn't have any AnimData yet.
* These should nevertheless be matched up. */ * These should nevertheless be matched up. */
Slot &slot = anim->slot_add(); Slot &slot = action->slot_add();
slot.handle = 327; slot.handle = 327;
STRNCPY_UTF8(slot.name, "OBKüüübus"); STRNCPY_UTF8(slot.name, "OBKüüübus");
slot.idtype = GS(cube->id.name); slot.idtype = GS(cube->id.name);
EXPECT_EQ(&slot, anim->find_suitable_slot_for(cube->id)); EXPECT_EQ(&slot, action->find_suitable_slot_for(cube->id));
/* === /* ===
* Slot exists with the same name & type as the ID, and the ID has an AnimData with the same * Slot exists with the same name & type as the ID, and the ID has an AnimData with the same
* slot name, but a different slot_handle. Since the Animation has not yet been * slot name, but a different slot_handle. Since the Action has not yet been
* assigned to this ID, the slot_handle should be ignored, and the slot name used for * assigned to this ID, the slot_handle should be ignored, and the slot name used for
* matching. */ * matching. */
/* Create a slot with a handle that should be ignored.*/ /* Create a slot with a handle that should be ignored.*/
Slot &other_slot = anim->slot_add(); Slot &other_slot = action->slot_add();
other_slot.handle = 47; other_slot.handle = 47;
AnimData *adt = BKE_animdata_ensure_id(&cube->id); AnimData *adt = BKE_animdata_ensure_id(&cube->id);
@ -428,28 +430,28 @@ TEST_F(ActionLayersTest, find_suitable_slot)
/* Configure adt to use the handle of one slot, and the name of the other. */ /* Configure adt to use the handle of one slot, and the name of the other. */
adt->slot_handle = other_slot.handle; adt->slot_handle = other_slot.handle;
STRNCPY_UTF8(adt->slot_name, slot.name); STRNCPY_UTF8(adt->slot_name, slot.name);
EXPECT_EQ(&slot, anim->find_suitable_slot_for(cube->id)); EXPECT_EQ(&slot, action->find_suitable_slot_for(cube->id));
/* === /* ===
* Same situation as above (AnimData has name of one slot, but the handle of another), * Same situation as above (AnimData has name of one slot, but the handle of another),
* except that the animation data-block has already been assigned. In this case the handle * except that the Action has already been assigned. In this case the handle should take
* should take precedence. */ * precedence. */
adt->action = anim; adt->action = action;
id_us_plus(&anim->id); id_us_plus(&action->id);
EXPECT_EQ(&other_slot, anim->find_suitable_slot_for(cube->id)); EXPECT_EQ(&other_slot, action->find_suitable_slot_for(cube->id));
/* === /* ===
* A slot exists, but doesn't match anything in the anim data of the cube. This should fall * A slot exists, but doesn't match anything in the action data of the cube. This should fall
* back to using the ID name. */ * back to using the ID name. */
adt->slot_handle = 161; adt->slot_handle = 161;
STRNCPY_UTF8(adt->slot_name, "¿¿What's this??"); STRNCPY_UTF8(adt->slot_name, "¿¿What's this??");
EXPECT_EQ(&slot, anim->find_suitable_slot_for(cube->id)); EXPECT_EQ(&slot, action->find_suitable_slot_for(cube->id));
} }
TEST_F(ActionLayersTest, strip) TEST_F(ActionLayersTest, strip)
{ {
constexpr float inf = std::numeric_limits<float>::infinity(); constexpr float inf = std::numeric_limits<float>::infinity();
Layer &layer0 = anim->layer_add("Test Læür nul"); Layer &layer0 = action->layer_add("Test Læür nul");
Strip &strip = layer0.strip_add(Strip::Type::Keyframe); Strip &strip = layer0.strip_add(Strip::Type::Keyframe);
strip.resize(-inf, inf); strip.resize(-inf, inf);
@ -486,9 +488,9 @@ TEST_F(ActionLayersTest, strip)
TEST_F(ActionLayersTest, KeyframeStrip__keyframe_insert) TEST_F(ActionLayersTest, KeyframeStrip__keyframe_insert)
{ {
Slot &slot = anim->slot_add(); Slot &slot = action->slot_add();
EXPECT_TRUE(anim->assign_id(&slot, cube->id)); EXPECT_TRUE(action->assign_id(&slot, cube->id));
Layer &layer = anim->layer_add("Kübus layer"); Layer &layer = action->layer_add("Kübus layer");
Strip &strip = layer.strip_add(Strip::Type::Keyframe); Strip &strip = layer.strip_add(Strip::Type::Keyframe);
KeyframeStrip &key_strip = strip.as<KeyframeStrip>(); KeyframeStrip &key_strip = strip.as<KeyframeStrip>();
@ -533,38 +535,38 @@ TEST_F(ActionLayersTest, is_action_assignable_to)
EXPECT_TRUE(is_action_assignable_to(nullptr, ID_CA)) EXPECT_TRUE(is_action_assignable_to(nullptr, ID_CA))
<< "nullptr Actions should be assignable to any type."; << "nullptr Actions should be assignable to any type.";
EXPECT_TRUE(is_action_assignable_to(anim, ID_OB)) EXPECT_TRUE(is_action_assignable_to(action, ID_OB))
<< "Empty Actions should be assignable to any type."; << "Empty Actions should be assignable to any type.";
EXPECT_TRUE(is_action_assignable_to(anim, ID_CA)) EXPECT_TRUE(is_action_assignable_to(action, ID_CA))
<< "Empty Actions should be assignable to any type."; << "Empty Actions should be assignable to any type.";
/* Make the Action a legacy one. */ /* Make the Action a legacy one. */
FCurve fake_fcurve; FCurve fake_fcurve;
BLI_addtail(&anim->curves, &fake_fcurve); BLI_addtail(&action->curves, &fake_fcurve);
ASSERT_FALSE(anim->is_empty()); ASSERT_FALSE(action->is_empty());
ASSERT_TRUE(anim->is_action_legacy()); ASSERT_TRUE(action->is_action_legacy());
ASSERT_EQ(0, anim->idroot); ASSERT_EQ(0, action->idroot);
EXPECT_TRUE(is_action_assignable_to(anim, ID_OB)) EXPECT_TRUE(is_action_assignable_to(action, ID_OB))
<< "Legacy Actions with idroot=0 should be assignable to any type."; << "Legacy Actions with idroot=0 should be assignable to any type.";
EXPECT_TRUE(is_action_assignable_to(anim, ID_CA)) EXPECT_TRUE(is_action_assignable_to(action, ID_CA))
<< "Legacy Actions with idroot=0 should be assignable to any type."; << "Legacy Actions with idroot=0 should be assignable to any type.";
/* Set the legacy idroot. */ /* Set the legacy idroot. */
anim->idroot = ID_CA; action->idroot = ID_CA;
EXPECT_FALSE(is_action_assignable_to(anim, ID_OB)) EXPECT_FALSE(is_action_assignable_to(action, ID_OB))
<< "Legacy Actions with idroot=ID_CA should NOT be assignable to ID_OB."; << "Legacy Actions with idroot=ID_CA should NOT be assignable to ID_OB.";
EXPECT_TRUE(is_action_assignable_to(anim, ID_CA)) EXPECT_TRUE(is_action_assignable_to(action, ID_CA))
<< "Legacy Actions with idroot=CA should be assignable to ID_CA."; << "Legacy Actions with idroot=CA should be assignable to ID_CA.";
/* Make the Action a layered one. */ /* Make the Action a layered one. */
BLI_poptail(&anim->curves); BLI_poptail(&action->curves);
anim->layer_add("layer"); action->layer_add("layer");
ASSERT_EQ(0, anim->idroot) << "Adding a layer should clear the idroot."; ASSERT_EQ(0, action->idroot) << "Adding a layer should clear the idroot.";
EXPECT_TRUE(is_action_assignable_to(anim, ID_OB)) EXPECT_TRUE(is_action_assignable_to(action, ID_OB))
<< "Layered Actions should be assignable to any type."; << "Layered Actions should be assignable to any type.";
EXPECT_TRUE(is_action_assignable_to(anim, ID_CA)) EXPECT_TRUE(is_action_assignable_to(action, ID_CA))
<< "Layered Actions should be assignable to any type."; << "Layered Actions should be assignable to any type.";
} }

@ -127,7 +127,7 @@ void animdata_fcurve_delete(bAnimContext *ac, AnimData *adt, FCurve *fcu)
animdata_remove_empty_action(adt); animdata_remove_empty_action(adt);
} }
else { else {
/* TODO: support deleting FCurves from Animation data-blocks. */ /* TODO: support deleting FCurves from layered Actions. */
return; return;
} }
} }
@ -200,7 +200,7 @@ const FCurve *fcurve_find_by_rna_path(const AnimData &adt,
const Slot *slot = action.slot_for_handle(adt.slot_handle); const Slot *slot = action.slot_for_handle(adt.slot_handle);
if (!slot) { if (!slot) {
/* No need to inspect anything if this ID does not have an animation Slot. */ /* No need to inspect anything if this ID does not have an Action Slot. */
return nullptr; return nullptr;
} }

@ -35,15 +35,15 @@ void apply_evaluation_result(const EvaluationResult &evaluation_result,
PointerRNA &animated_id_ptr, PointerRNA &animated_id_ptr,
bool flush_to_original); bool flush_to_original);
static EvaluationResult evaluate_animation(PointerRNA &animated_id_ptr, static EvaluationResult evaluate_action(PointerRNA &animated_id_ptr,
Action &animation, Action &action,
const slot_handle_t slot_handle, const slot_handle_t slot_handle,
const AnimationEvalContext &anim_eval_context) const AnimationEvalContext &anim_eval_context)
{ {
EvaluationResult last_result; EvaluationResult last_result;
/* Evaluate each layer in order. */ /* Evaluate each layer in order. */
for (Layer *layer : animation.layers()) { for (Layer *layer : action.layers()) {
if (layer->influence <= 0.0f) { if (layer->influence <= 0.0f) {
/* Don't bother evaluating layers without influence. */ /* Don't bother evaluating layers without influence. */
continue; continue;
@ -69,14 +69,14 @@ static EvaluationResult evaluate_animation(PointerRNA &animated_id_ptr,
return last_result; return last_result;
} }
void evaluate_and_apply_animation(PointerRNA &animated_id_ptr, void evaluate_and_apply_action(PointerRNA &animated_id_ptr,
Action &animation, Action &action,
const slot_handle_t slot_handle, const slot_handle_t slot_handle,
const AnimationEvalContext &anim_eval_context, const AnimationEvalContext &anim_eval_context,
const bool flush_to_original) const bool flush_to_original)
{ {
EvaluationResult evaluation_result = evaluate_animation( EvaluationResult evaluation_result = evaluate_action(
animated_id_ptr, animation, slot_handle, anim_eval_context); animated_id_ptr, action, slot_handle, anim_eval_context);
if (!evaluation_result) { if (!evaluation_result) {
return; return;
} }

@ -54,7 +54,7 @@ class AnimatedProperty {
} }
}; };
/* Evaluated FCurves for some animation slot. /* Evaluated FCurves for some action slot.
* Mapping from property identifier to its float value. * Mapping from property identifier to its float value.
* *
* Can be fed to the evaluation of the next layer, mixed with another strip, or * Can be fed to the evaluation of the next layer, mixed with another strip, or

@ -33,7 +33,7 @@ using namespace blender::animrig::internal;
class AnimationEvaluationTest : public testing::Test { class AnimationEvaluationTest : public testing::Test {
protected: protected:
Main *bmain; Main *bmain;
Action *anim; Action *action;
Object *cube; Object *cube;
Slot *slot; Slot *slot;
Layer *layer; Layer *layer;
@ -60,13 +60,13 @@ class AnimationEvaluationTest : public testing::Test {
void SetUp() override void SetUp() override
{ {
bmain = BKE_main_new(); bmain = BKE_main_new();
anim = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACÄnimåtië")); action = static_cast<Action *>(BKE_id_new(bmain, ID_AC, "ACÄnimåtië"));
cube = BKE_object_add_only_object(bmain, OB_EMPTY, "Küüübus"); cube = BKE_object_add_only_object(bmain, OB_EMPTY, "Küüübus");
slot = &anim->slot_add(); slot = &action->slot_add();
anim->assign_id(slot, cube->id); action->assign_id(slot, cube->id);
layer = &anim->layer_add("Kübus layer"); layer = &action->layer_add("Kübus layer");
/* Make it easier to predict test values. */ /* Make it easier to predict test values. */
settings.interpolation = BEZT_IPO_LIN; settings.interpolation = BEZT_IPO_LIN;

@ -163,7 +163,7 @@ void CombinedKeyingResult::generate_reports(ReportList *reports, const eReportTy
if (this->get_count(SingleKeyingResult::NO_VALID_SLOT) > 0) { if (this->get_count(SingleKeyingResult::NO_VALID_SLOT) > 0) {
const int error_count = this->get_count(SingleKeyingResult::NO_VALID_SLOT); const int error_count = this->get_count(SingleKeyingResult::NO_VALID_SLOT);
errors.append(fmt::format(RPT_("Inserting keys on {:d} data-block(s) has been skipped because " errors.append(fmt::format(RPT_("Inserting keys on {:d} data-block(s) has been skipped because "
"of missing animation slots."), "of missing action slots."),
error_count)); error_count));
} }

@ -307,7 +307,7 @@ int BKE_fcurves_filter(ListBase *dst, ListBase *src, const char *dataPrefix, con
* \note Return pointer parameters (`r_action`, `r_driven` and `r_special`) are all optional and * \note Return pointer parameters (`r_action`, `r_driven` and `r_special`) are all optional and
* may be NULL. * may be NULL.
* *
* \note since Animation data-blocks may have multiple layers all containing an F-Curve for this * \note since Actions may have multiple layers all containing an F-Curve for this
* property, what is returned is a best-effort guess. The topmost layer has priority, and it is * property, what is returned is a best-effort guess. The topmost layer has priority, and it is
* assumed that when it has a strip, it's infinite. * assumed that when it has a strip, it's infinite.
*/ */

@ -396,13 +396,13 @@ static void read_keyframe_strip(BlendDataReader *reader, animrig::KeyframeStrip
} }
} }
static void read_layers(BlendDataReader *reader, animrig::Action &anim) static void read_layers(BlendDataReader *reader, animrig::Action &action)
{ {
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&anim.layer_array)); BLO_read_pointer_array(reader, reinterpret_cast<void **>(&action.layer_array));
for (int layer_idx = 0; layer_idx < anim.layer_array_num; layer_idx++) { for (int layer_idx = 0; layer_idx < action.layer_array_num; layer_idx++) {
BLO_read_struct(reader, ActionLayer, &anim.layer_array[layer_idx]); BLO_read_struct(reader, ActionLayer, &action.layer_array[layer_idx]);
ActionLayer *layer = anim.layer_array[layer_idx]; ActionLayer *layer = action.layer_array[layer_idx];
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&layer->strip_array)); BLO_read_pointer_array(reader, reinterpret_cast<void **>(&layer->strip_array));
for (int strip_idx = 0; strip_idx < layer->strip_array_num; strip_idx++) { for (int strip_idx = 0; strip_idx < layer->strip_array_num; strip_idx++) {
@ -419,13 +419,13 @@ static void read_layers(BlendDataReader *reader, animrig::Action &anim)
} }
} }
static void read_slots(BlendDataReader *reader, animrig::Action &anim) static void read_slots(BlendDataReader *reader, animrig::Action &action)
{ {
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&anim.slot_array)); BLO_read_pointer_array(reader, reinterpret_cast<void **>(&action.slot_array));
for (int i = 0; i < anim.slot_array_num; i++) { for (int i = 0; i < action.slot_array_num; i++) {
BLO_read_struct(reader, ActionSlot, &anim.slot_array[i]); BLO_read_struct(reader, ActionSlot, &action.slot_array[i]);
anim.slot_array[i]->wrap().blend_read_post(); action.slot_array[i]->wrap().blend_read_post();
} }
} }

@ -205,11 +205,11 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act)
#ifdef WITH_ANIM_BAKLAVA #ifdef WITH_ANIM_BAKLAVA
if (!act) { if (!act) {
animrig::unassign_animation(*id); animrig::unassign_action(*id);
return true; return true;
} }
animrig::Action &action = act->wrap(); animrig::Action &action = act->wrap();
return animrig::assign_animation(action, *id); return animrig::assign_action(action, *id);
#else #else
return animdata_set_action(reports, id, &adt->action, act); return animdata_set_action(reports, id, &adt->action, act);
#endif // WITH_ANIM_BAKLAVA #endif // WITH_ANIM_BAKLAVA
@ -259,7 +259,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
/* unlink action (don't free, as it's in its own list) */ /* unlink action (don't free, as it's in its own list) */
if (adt->action) { if (adt->action) {
#ifdef WITH_ANIM_BAKLAVA #ifdef WITH_ANIM_BAKLAVA
blender::animrig::unassign_animation(*id); blender::animrig::unassign_action(*id);
#else #else
id_us_min(&adt->action->id); id_us_min(&adt->action->id);
#endif #endif
@ -270,7 +270,7 @@ void BKE_animdata_free(ID *id, const bool do_id_user)
/* TODO: Linked Actions do not support usage in the NLA yet, so work around this and cleanly /* TODO: Linked Actions do not support usage in the NLA yet, so work around this and cleanly
* unassign the Action by moving it back to `adt->action`. */ * unassign the Action by moving it back to `adt->action`. */
adt->action = adt->tmpact; adt->action = adt->tmpact;
blender::animrig::unassign_animation(*id); blender::animrig::unassign_action(*id);
#else #else
id_us_min(&adt->tmpact->id); id_us_min(&adt->tmpact->id);
#endif #endif

@ -3949,7 +3949,7 @@ void BKE_animsys_evaluate_animdata(ID *id,
else if (adt->action) { else if (adt->action) {
blender::animrig::Action &action = adt->action->wrap(); blender::animrig::Action &action = adt->action->wrap();
if (action.is_action_layered()) { if (action.is_action_layered()) {
blender::animrig::evaluate_and_apply_animation( blender::animrig::evaluate_and_apply_action(
id_ptr, action, adt->slot_handle, *anim_eval_context, flush_to_original); id_ptr, action, adt->slot_handle, *anim_eval_context, flush_to_original);
} }
else { else {

@ -1574,7 +1574,7 @@ void DepsgraphRelationBuilder::build_animdata_curves(ID *id)
OperationKey animation_exit_key(id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT); OperationKey animation_exit_key(id, NodeType::ANIMATION, OperationCode::ANIMATION_EXIT);
add_relation(animation_entry_key, animation_eval_key, "Init -> Eval"); add_relation(animation_entry_key, animation_eval_key, "Init -> Eval");
add_relation(animation_eval_key, animation_exit_key, "Eval -> Exit"); add_relation(animation_eval_key, animation_exit_key, "Eval -> Exit");
/* Wire up dependency from action and Animation datablock. */ /* Wire up dependency from Actions. */
ComponentKey adt_key(id, NodeType::ANIMATION); ComponentKey adt_key(id, NodeType::ANIMATION);
/* Relation from action itself. */ /* Relation from action itself. */
if (adt->action != nullptr) { if (adt->action != nullptr) {

@ -44,7 +44,7 @@ static bool mode_transfer_is_animation_running(const float anim_time)
return anim_time >= 0.0f && anim_time <= MODE_TRANSFER_FLASH_LENGTH; return anim_time >= 0.0f && anim_time <= MODE_TRANSFER_FLASH_LENGTH;
} }
static float mode_transfer_alpha_for_animation_time_get(const float anim_time) static float mode_transfer_alpha_for_action_slot_time_get(const float anim_time)
{ {
if (anim_time > MODE_TRANSFER_FLASH_LENGTH) { if (anim_time > MODE_TRANSFER_FLASH_LENGTH) {
return 0.0f; return 0.0f;
@ -103,7 +103,7 @@ void OVERLAY_mode_transfer_cache_populate(OVERLAY_Data *vedata, Object *ob)
float color[4]; float color[4];
UI_GetThemeColor3fv(TH_VERTEX_SELECT, color); UI_GetThemeColor3fv(TH_VERTEX_SELECT, color);
color[3] = mode_transfer_alpha_for_animation_time_get(animation_time); color[3] = mode_transfer_alpha_for_action_slot_time_get(animation_time);
srgb_to_linearrgb_v4(color, color); srgb_to_linearrgb_v4(color, color);
/* Alpha pre-multiply. */ /* Alpha pre-multiply. */
mul_v3_fl(color, color[3]); mul_v3_fl(color, color[3]);

@ -481,8 +481,8 @@ bool ANIM_animdata_can_have_greasepencil(const eAnimCont_Types type)
* - nlaOk: line or block of code to execute for NLA tracks+strips case * - nlaOk: line or block of code to execute for NLA tracks+strips case
* - driversOk: line or block of code to execute for Drivers case * - driversOk: line or block of code to execute for Drivers case
* - nlaKeysOk: line or block of code for NLA Strip Keyframes case * - nlaKeysOk: line or block of code for NLA Strip Keyframes case
* - keysOk: line or block of code for Keyframes case * - legacyActionOk: line or block of code for Keyframes from legacy Actions
* - animOk: line or block of code for Keyframes from Animation data blocks case * - layeredActionOk: line or block of code for Keyframes from layered Actions
* *
* The checks for the various cases are as follows: * The checks for the various cases are as follows:
* 0) top level: checks for animdata and also that all the F-Curves for the block will be visible * 0) top level: checks for animdata and also that all the F-Curves for the block will be visible
@ -1516,7 +1516,7 @@ static size_t animfilter_action_slot(bAnimContext *ac,
if (show_fcurves_only || expansion_is_ok) { if (show_fcurves_only || expansion_is_ok) {
/* Add list elements for the F-Curves for this Slot. */ /* Add list elements for the F-Curves for this Slot. */
Span<FCurve *> fcurves = animrig::fcurves_for_animation(action, slot.handle); Span<FCurve *> fcurves = animrig::fcurves_for_action_slot(action, slot.handle);
items += animfilter_fcurves_span( items += animfilter_fcurves_span(
ac, anim_data, fcurves, slot.handle, filter_mode, owner_id, &action.id); ac, anim_data, fcurves, slot.handle, filter_mode, owner_id, &action.id);
} }

@ -170,7 +170,7 @@ static short agrp_keyframes_loop(KeyframeEditData *ked,
/* Loop over all keyframes in the layered Action. */ /* Loop over all keyframes in the layered Action. */
static short action_layered_keyframes_loop(KeyframeEditData *ked, static short action_layered_keyframes_loop(KeyframeEditData *ked,
animrig::Action &anim, animrig::Action &action,
animrig::Slot *slot, animrig::Slot *slot,
KeyframeEditFunc key_ok, KeyframeEditFunc key_ok,
KeyframeEditFunc key_cb, KeyframeEditFunc key_cb,
@ -181,7 +181,7 @@ static short action_layered_keyframes_loop(KeyframeEditData *ked,
return 0; return 0;
} }
Span<FCurve *> fcurves = animrig::fcurves_for_animation(anim, slot->handle); Span<FCurve *> fcurves = animrig::fcurves_for_action_slot(action, slot->handle);
for (FCurve *fcurve : fcurves) { for (FCurve *fcurve : fcurves) {
if (ANIM_fcurve_keyframes_loop(ked, fcurve, key_ok, key_cb, fcu_cb)) { if (ANIM_fcurve_keyframes_loop(ked, fcurve, key_ok, key_cb, fcu_cb)) {
return 1; return 1;
@ -421,9 +421,9 @@ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked,
/* This assumes that the ALE_ACTION_LAYERED channel is shown in the dopesheet context, /* This assumes that the ALE_ACTION_LAYERED channel is shown in the dopesheet context,
* underneath the data-block that owns `ale->adt`. So that means that the loop is limited to * underneath the data-block that owns `ale->adt`. So that means that the loop is limited to
* the keys that belong to that slot. */ * the keys that belong to that slot. */
animrig::Action &anim = static_cast<bAction *>(ale->key_data)->wrap(); animrig::Action &action = static_cast<bAction *>(ale->key_data)->wrap();
animrig::Slot *slot = anim.slot_for_handle(ale->adt->slot_handle); animrig::Slot *slot = action.slot_for_handle(ale->adt->slot_handle);
return action_layered_keyframes_loop(ked, anim, slot, key_ok, key_cb, fcu_cb); return action_layered_keyframes_loop(ked, action, slot, key_ok, key_cb, fcu_cb);
#else #else
return 0; return 0;
#endif #endif

@ -1169,7 +1169,7 @@ void action_slot_to_keylist(AnimData *adt,
blender::float2 range) blender::float2 range)
{ {
BLI_assert(GS(action.id.name) == ID_AC); BLI_assert(GS(action.id.name) == ID_AC);
for (FCurve *fcurve : fcurves_for_animation(action, slot_handle)) { for (FCurve *fcurve : fcurves_for_action_slot(action, slot_handle)) {
fcurve_to_keylist(adt, fcurve, keylist, saction_flag, range); fcurve_to_keylist(adt, fcurve, keylist, saction_flag, range);
} }
} }
@ -1186,7 +1186,7 @@ void action_to_keylist(AnimData *adt,
blender::animrig::Action &action = dna_action->wrap(); blender::animrig::Action &action = dna_action->wrap();
/* TODO: move this into fcurves_for_animation(). */ /* TODO: move this into fcurves_for_action_slot(). */
if (action.is_action_legacy()) { if (action.is_action_legacy()) {
LISTBASE_FOREACH (FCurve *, fcu, &action.curves) { LISTBASE_FOREACH (FCurve *, fcu, &action.curves) {
fcurve_to_keylist(adt, fcu, keylist, saction_flag, range); fcurve_to_keylist(adt, fcu, keylist, saction_flag, range);

@ -1182,7 +1182,7 @@ typedef struct ActionStrip {
* *
* This offset determines the difference between "Animation time" (which would * This offset determines the difference between "Animation time" (which would
* typically be the same as the scene time, until the animation system * typically be the same as the scene time, until the animation system
* supports strips referencing other Animation data-blocks). * supports strips referencing other Actions).
*/ */
float frame_offset; float frame_offset;

@ -118,8 +118,8 @@ static animrig::Strip &rna_data_strip(const PointerRNA *ptr)
static void rna_Action_tag_animupdate(Main *, Scene *, PointerRNA *ptr) static void rna_Action_tag_animupdate(Main *, Scene *, PointerRNA *ptr)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
DEG_id_tag_update(&anim.id, ID_RECALC_ANIMATION); DEG_id_tag_update(&action.id, ID_RECALC_ANIMATION);
} }
static animrig::KeyframeStrip &rna_data_keyframe_strip(const PointerRNA *ptr) static animrig::KeyframeStrip &rna_data_keyframe_strip(const PointerRNA *ptr)
@ -145,27 +145,27 @@ static void rna_iterator_array_begin(CollectionPropertyIterator *iter, MutableSp
rna_iterator_array_begin(iter, (void *)items.data(), sizeof(T *), items.size(), 0, nullptr); rna_iterator_array_begin(iter, (void *)items.data(), sizeof(T *), items.size(), 0, nullptr);
} }
static ActionSlot *rna_Action_slots_new(bAction *anim_id, static ActionSlot *rna_Action_slots_new(bAction *dna_action,
bContext *C, bContext *C,
ReportList *reports, ReportList *reports,
ID *id_for_slot) ID *id_for_slot)
{ {
animrig::Action &anim = anim_id->wrap(); animrig::Action &action = dna_action->wrap();
animrig::Slot *slot; animrig::Slot *slot;
if (!anim.is_action_layered()) { if (!action.is_action_layered()) {
BKE_reportf(reports, BKE_reportf(reports,
RPT_ERROR, RPT_ERROR,
"Cannot add slots to a legacy Action '%s'. Convert it to a layered Action first.", "Cannot add slots to a legacy Action '%s'. Convert it to a layered Action first.",
anim.id.name + 2); action.id.name + 2);
return nullptr; return nullptr;
} }
if (id_for_slot) { if (id_for_slot) {
slot = &anim.slot_add_for_id(*id_for_slot); slot = &action.slot_add_for_id(*id_for_slot);
} }
else { else {
slot = &anim.slot_add(); slot = &action.slot_add();
} }
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr); WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
@ -174,14 +174,14 @@ static ActionSlot *rna_Action_slots_new(bAction *anim_id,
static void rna_iterator_action_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) static void rna_iterator_action_layers_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
rna_iterator_array_begin(iter, anim.layers()); rna_iterator_array_begin(iter, action.layers());
} }
static int rna_iterator_action_layers_length(PointerRNA *ptr) static int rna_iterator_action_layers_length(PointerRNA *ptr)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
return anim.layers().size(); return action.layers().size();
} }
static ActionLayer *rna_Action_layers_new(bAction *dna_action, static ActionLayer *rna_Action_layers_new(bAction *dna_action,
@ -189,24 +189,24 @@ static ActionLayer *rna_Action_layers_new(bAction *dna_action,
ReportList *reports, ReportList *reports,
const char *name) const char *name)
{ {
animrig::Action &anim = dna_action->wrap(); animrig::Action &action = dna_action->wrap();
if (!anim.is_action_layered()) { if (!action.is_action_layered()) {
BKE_reportf(reports, BKE_reportf(reports,
RPT_ERROR, RPT_ERROR,
"Cannot add layers to a legacy Action '%s'. Convert it to a layered Action first.", "Cannot add layers to a legacy Action '%s'. Convert it to a layered Action first.",
anim.id.name + 2); action.id.name + 2);
return nullptr; return nullptr;
} }
if (anim.layers().size() >= 1) { if (action.layers().size() >= 1) {
/* Not allowed to have more than one layer, for now. This limitation is in /* Not allowed to have more than one layer, for now. This limitation is in
* place until working with multiple animated IDs is fleshed out better. */ * place until working with multiple animated IDs is fleshed out better. */
BKE_report(reports, RPT_ERROR, "An Animation may not have more than one layer"); BKE_report(reports, RPT_ERROR, "An Action may not have more than one layer");
return nullptr; return nullptr;
} }
animrig::Layer &layer = anim.layer_add(name); animrig::Layer &layer = action.layer_add(name);
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr); WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
return &layer; return &layer;
@ -217,27 +217,27 @@ void rna_Action_layers_remove(bAction *dna_action,
ReportList *reports, ReportList *reports,
ActionLayer *dna_layer) ActionLayer *dna_layer)
{ {
animrig::Action &anim = dna_action->wrap(); animrig::Action &action = dna_action->wrap();
animrig::Layer &layer = dna_layer->wrap(); animrig::Layer &layer = dna_layer->wrap();
if (!anim.layer_remove(layer)) { if (!action.layer_remove(layer)) {
BKE_report(reports, RPT_ERROR, "This layer does not belong to this animation"); BKE_report(reports, RPT_ERROR, "This layer does not belong to this Action");
return; return;
} }
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr); WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
DEG_id_tag_update(&anim.id, ID_RECALC_ANIMATION); DEG_id_tag_update(&action.id, ID_RECALC_ANIMATION);
} }
static void rna_iterator_animation_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) static void rna_iterator_animation_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
rna_iterator_array_begin(iter, anim.slots()); rna_iterator_array_begin(iter, action.slots());
} }
static int rna_iterator_animation_slots_length(PointerRNA *ptr) static int rna_iterator_animation_slots_length(PointerRNA *ptr)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
return anim.slots().size(); return action.slots().size();
} }
static std::optional<std::string> rna_ActionSlot_path(const PointerRNA *ptr) static std::optional<std::string> rna_ActionSlot_path(const PointerRNA *ptr)
@ -264,7 +264,7 @@ int rna_ActionSlot_name_display_length(PointerRNA *ptr)
static void rna_ActionSlot_name_display_set(PointerRNA *ptr, const char *name) static void rna_ActionSlot_name_display_set(PointerRNA *ptr, const char *name)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
animrig::Slot &slot = rna_data_slot(ptr); animrig::Slot &slot = rna_data_slot(ptr);
const StringRef name_ref(name); const StringRef name_ref(name);
@ -275,12 +275,12 @@ static void rna_ActionSlot_name_display_set(PointerRNA *ptr, const char *name)
/* Construct the new internal name, from the slot's type and the given name. */ /* Construct the new internal name, from the slot's type and the given name. */
const std::string internal_name = slot.name_prefix_for_idtype() + name_ref; const std::string internal_name = slot.name_prefix_for_idtype() + name_ref;
anim.slot_name_define(slot, internal_name); action.slot_name_define(slot, internal_name);
} }
static void rna_ActionSlot_name_set(PointerRNA *ptr, const char *name) static void rna_ActionSlot_name_set(PointerRNA *ptr, const char *name)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
animrig::Slot &slot = rna_data_slot(ptr); animrig::Slot &slot = rna_data_slot(ptr);
const StringRef name_ref(name); const StringRef name_ref(name);
@ -302,14 +302,14 @@ static void rna_ActionSlot_name_set(PointerRNA *ptr, const char *name)
} }
} }
anim.slot_name_define(slot, name); action.slot_name_define(slot, name);
} }
static void rna_ActionSlot_name_update(Main *bmain, Scene *, PointerRNA *ptr) static void rna_ActionSlot_name_update(Main *bmain, Scene *, PointerRNA *ptr)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
animrig::Slot &slot = rna_data_slot(ptr); animrig::Slot &slot = rna_data_slot(ptr);
anim.slot_name_propagate(*bmain, slot); action.slot_name_propagate(*bmain, slot);
} }
static std::optional<std::string> rna_ActionLayer_path(const PointerRNA *ptr) static std::optional<std::string> rna_ActionLayer_path(const PointerRNA *ptr)
@ -356,11 +356,8 @@ ActionStrip *rna_ActionStrips_new(ActionLayer *dna_layer,
return &strip; return &strip;
} }
void rna_ActionStrips_remove(ID *animation_id, void rna_ActionStrips_remove(
ActionLayer *dna_layer, ID *action, ActionLayer *dna_layer, bContext *C, ReportList *reports, ActionStrip *dna_strip)
bContext *C,
ReportList *reports,
ActionStrip *dna_strip)
{ {
animrig::Layer &layer = dna_layer->wrap(); animrig::Layer &layer = dna_layer->wrap();
animrig::Strip &strip = dna_strip->wrap(); animrig::Strip &strip = dna_strip->wrap();
@ -370,7 +367,7 @@ void rna_ActionStrips_remove(ID *animation_id,
} }
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr); WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr);
DEG_id_tag_update(animation_id, ID_RECALC_ANIMATION); DEG_id_tag_update(action, ID_RECALC_ANIMATION);
} }
static StructRNA *rna_ActionStrip_refine(PointerRNA *ptr) static StructRNA *rna_ActionStrip_refine(PointerRNA *ptr)
@ -385,17 +382,17 @@ static StructRNA *rna_ActionStrip_refine(PointerRNA *ptr)
static std::optional<std::string> rna_ActionStrip_path(const PointerRNA *ptr) static std::optional<std::string> rna_ActionStrip_path(const PointerRNA *ptr)
{ {
animrig::Action &anim = rna_action(ptr); animrig::Action &action = rna_action(ptr);
animrig::Strip &strip_to_find = rna_data_strip(ptr); animrig::Strip &strip_to_find = rna_data_strip(ptr);
for (animrig::Layer *layer : anim.layers()) { for (animrig::Layer *layer : action.layers()) {
Span<animrig::Strip *> strips = layer->strips(); Span<animrig::Strip *> strips = layer->strips();
const int index = strips.first_index_try(&strip_to_find); const int index = strips.first_index_try(&strip_to_find);
if (index < 0) { if (index < 0) {
continue; continue;
} }
PointerRNA layer_ptr = RNA_pointer_create(&anim.id, &RNA_ActionLayer, layer); PointerRNA layer_ptr = RNA_pointer_create(&action.id, &RNA_ActionLayer, layer);
const std::optional<std::string> layer_path = rna_ActionLayer_path(&layer_ptr); const std::optional<std::string> layer_path = rna_ActionLayer_path(&layer_ptr);
BLI_assert_msg(layer_path, "Every animation layer should have a valid RNA path."); BLI_assert_msg(layer_path, "Every animation layer should have a valid RNA path.");
const std::string strip_path = fmt::format("{}.strips[{}]", *layer_path, index); const std::string strip_path = fmt::format("{}.strips[{}]", *layer_path, index);
@ -1173,7 +1170,7 @@ static void rna_def_action_slots(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "ActionSlots"); RNA_def_property_srna(cprop, "ActionSlots");
srna = RNA_def_struct(brna, "ActionSlots", nullptr); srna = RNA_def_struct(brna, "ActionSlots", nullptr);
RNA_def_struct_sdna(srna, "bAction"); RNA_def_struct_sdna(srna, "bAction");
RNA_def_struct_ui_text(srna, "Action Slots", "Collection of animation slots"); RNA_def_struct_ui_text(srna, "Action Slots", "Collection of action slots");
/* Animation.slots.new(...) */ /* Animation.slots.new(...) */
func = RNA_def_function(srna, "new", "rna_Action_slots_new"); func = RNA_def_function(srna, "new", "rna_Action_slots_new");
@ -1190,7 +1187,7 @@ static void rna_def_action_slots(BlenderRNA *brna, PropertyRNA *cprop)
/* Clear out the PARM_REQUIRED flag, which is set by default for pointer parameters. */ /* Clear out the PARM_REQUIRED flag, which is set by default for pointer parameters. */
RNA_def_parameter_flags(parm, PropertyFlag(0), ParameterFlag(0)); RNA_def_parameter_flags(parm, PropertyFlag(0), ParameterFlag(0));
parm = RNA_def_pointer(func, "slot", "ActionSlot", "", "Newly created animation slot"); parm = RNA_def_pointer(func, "slot", "ActionSlot", "", "Newly created action slot");
RNA_def_function_return(func, parm); RNA_def_function_return(func, parm);
} }
@ -1217,7 +1214,7 @@ static void rna_def_action_layers(BlenderRNA *brna, PropertyRNA *cprop)
nullptr, nullptr,
sizeof(ActionLayer::name) - 1, sizeof(ActionLayer::name) - 1,
"Name", "Name",
"Name of the layer, will be made unique within the Animation data-block"); "Name of the layer, will be made unique within the Action");
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
parm = RNA_def_pointer(func, "layer", "ActionLayer", "", "Newly created animation layer"); parm = RNA_def_pointer(func, "layer", "ActionLayer", "", "Newly created animation layer");
RNA_def_function_return(func, parm); RNA_def_function_return(func, parm);
@ -1240,8 +1237,8 @@ static void rna_def_action_slot(BlenderRNA *brna)
RNA_def_struct_path_func(srna, "rna_ActionSlot_path"); RNA_def_struct_path_func(srna, "rna_ActionSlot_path");
RNA_def_struct_ui_text( RNA_def_struct_ui_text(
srna, srna,
"Animation Slot", "Action slot",
"Identifier for a set of channels in this Animation, that can be used by a data-block " "Identifier for a set of channels in this Action, that can be used by a data-block "
"to specify what it gets animated by"); "to specify what it gets animated by");
prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
@ -1252,7 +1249,7 @@ static void rna_def_action_slot(BlenderRNA *brna)
RNA_def_struct_ui_text( RNA_def_struct_ui_text(
srna, srna,
"Slot Name", "Slot Name",
"Used when connecting an Animation to a data-block, to find the correct slot handle"); "Used when connecting an Action to a data-block, to find the correct slot handle");
prop = RNA_def_property(srna, "name_display", PROP_STRING, PROP_NONE); prop = RNA_def_property(srna, "name_display", PROP_STRING, PROP_NONE);
RNA_def_property_string_funcs(prop, RNA_def_property_string_funcs(prop,
@ -1368,7 +1365,7 @@ static void rna_def_keyframestrip_channelbags(BlenderRNA *brna, PropertyRNA *cpr
RNA_def_struct_ui_text( RNA_def_struct_ui_text(
srna, srna,
"Animation Channels for Slots", "Animation Channels for Slots",
"For each animation slot, a list of animation channels that are meant for that slot"); "For each action slot, a list of animation channels that are meant for that slot");
} }
static void rna_def_action_keyframe_strip(BlenderRNA *brna) static void rna_def_action_keyframe_strip(BlenderRNA *brna)
@ -1378,7 +1375,7 @@ static void rna_def_action_keyframe_strip(BlenderRNA *brna)
srna = RNA_def_struct(brna, "KeyframeActionStrip", "ActionStrip"); srna = RNA_def_struct(brna, "KeyframeActionStrip", "ActionStrip");
RNA_def_struct_ui_text( RNA_def_struct_ui_text(
srna, "Keyframe Animation Strip", "Strip with a set of F-Curves for each animation slot"); srna, "Keyframe Animation Strip", "Strip with a set of F-Curves for each action slot");
prop = RNA_def_property(srna, "channelbags", PROP_COLLECTION, PROP_NONE); prop = RNA_def_property(srna, "channelbags", PROP_COLLECTION, PROP_NONE);
RNA_def_property_struct_type(prop, "ActionChannelBag"); RNA_def_property_struct_type(prop, "ActionChannelBag");
@ -1406,7 +1403,7 @@ static void rna_def_action_keyframe_strip(BlenderRNA *brna)
0, 0,
INT_MAX, INT_MAX,
"Slot Handle", "Slot Handle",
"Number that identifies a specific animation slot", "Number that identifies a specific action slot",
0, 0,
INT_MAX); INT_MAX);
RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED);
@ -1483,7 +1480,7 @@ static void rna_def_action_strip(BlenderRNA *brna)
"KEYFRAME", "KEYFRAME",
0, 0,
"Keyframe", "Keyframe",
"Strip with a set of F-Curves for each animation slot"}, "Strip with a set of F-Curves for each action slot"},
{0, nullptr, 0, nullptr, nullptr}, {0, nullptr, 0, nullptr, nullptr},
}; };
@ -1503,7 +1500,7 @@ static void rna_def_channelbag_for_slot_fcurves(BlenderRNA *brna, PropertyRNA *c
RNA_def_property_srna(cprop, "ActionChannelBagFCurves"); RNA_def_property_srna(cprop, "ActionChannelBagFCurves");
srna = RNA_def_struct(brna, "ActionChannelBagFCurves", nullptr); srna = RNA_def_struct(brna, "ActionChannelBagFCurves", nullptr);
RNA_def_struct_sdna(srna, "bActionChannelBag"); RNA_def_struct_sdna(srna, "bActionChannelBag");
RNA_def_struct_ui_text(srna, "F-Curves", "Collection of F-Curves for a specific animation slot"); RNA_def_struct_ui_text(srna, "F-Curves", "Collection of F-Curves for a specific action slot");
} }
static void rna_def_action_channelbag(BlenderRNA *brna) static void rna_def_action_channelbag(BlenderRNA *brna)
@ -1515,7 +1512,7 @@ static void rna_def_action_channelbag(BlenderRNA *brna)
RNA_def_struct_ui_text( RNA_def_struct_ui_text(
srna, srna,
"Animation Channel Bag", "Animation Channel Bag",
"Collection of animation channels, typically associated with an animation slot"); "Collection of animation channels, typically associated with an action slot");
prop = RNA_def_property(srna, "slot_handle", PROP_INT, PROP_NONE); prop = RNA_def_property(srna, "slot_handle", PROP_INT, PROP_NONE);
RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_clear_flag(prop, PROP_EDITABLE);
@ -1842,7 +1839,7 @@ static void rna_def_action(BlenderRNA *brna)
nullptr, nullptr,
nullptr, nullptr,
nullptr); nullptr);
RNA_def_property_ui_text(prop, "Layers", "The list of layers that make up this Animation"); RNA_def_property_ui_text(prop, "Layers", "The list of layers that make up this Action");
rna_def_action_layers(brna, prop); rna_def_action_layers(brna, prop);
# endif // WITH_ANIM_BAKLAVA # endif // WITH_ANIM_BAKLAVA

@ -111,7 +111,7 @@ const EnumPropertyItem rna_enum_action_slot_item_new = {
"NEW", "NEW",
ICON_ADD, ICON_ADD,
"New", "New",
"Create a new animation slot for this data-block"}; "Create a new action slot for this data-block"};
const EnumPropertyItem rna_enum_action_slot_item_legacy = { const EnumPropertyItem rna_enum_action_slot_item_legacy = {
int(blender::animrig::Slot::unassigned), int(blender::animrig::Slot::unassigned),
"UNASSIGNED", "UNASSIGNED",
@ -183,11 +183,11 @@ static void rna_AnimData_action_set(PointerRNA *ptr, PointerRNA value, ReportLis
bAction *action = static_cast<bAction *>(value.data); bAction *action = static_cast<bAction *>(value.data);
if (!action) { if (!action) {
blender::animrig::unassign_animation(animated_id); blender::animrig::unassign_action(animated_id);
return; return;
} }
blender::animrig::assign_animation(action->wrap(), animated_id); blender::animrig::assign_action(action->wrap(), animated_id);
# else # else
ID *ownerId = ptr->owner_id; ID *ownerId = ptr->owner_id;
BKE_animdata_set_action(nullptr, ownerId, static_cast<bAction *>(value.data)); BKE_animdata_set_action(nullptr, ownerId, static_cast<bAction *>(value.data));
@ -262,23 +262,23 @@ static void rna_AnimData_action_slot_handle_set(
return; return;
} }
blender::animrig::Action *anim = blender::animrig::get_animation(animated_id); blender::animrig::Action *action = blender::animrig::get_action(animated_id);
if (!anim) { if (!action) {
/* No animation to verify the slot handle is valid. As the slot handle /* No Action to verify the slot handle is valid. As the slot handle will be
* will be completely ignored when re-assigning an Animation, better to * completely ignored when re-assigning an Action, better to refuse setting
* refuse setting it altogether. This will make bugs in Python code more obvious. */ * it altogether. This will make bugs in Python code more obvious. */
WM_reportf(RPT_ERROR, WM_reportf(RPT_ERROR,
"Data-block '%s' does not have an animation, cannot set slot handle", "Data-block '%s' does not have an Action, cannot set slot handle",
animated_id.name + 2); animated_id.name + 2);
return; return;
} }
blender::animrig::Slot *slot = anim->slot_for_handle(new_slot_handle); blender::animrig::Slot *slot = action->slot_for_handle(new_slot_handle);
if (!anim->assign_id(slot, animated_id)) { if (!action->assign_id(slot, animated_id)) {
if (slot) { if (slot) {
WM_reportf(RPT_ERROR, WM_reportf(RPT_ERROR,
"Action '%s' slot '%s' (%d) could not be assigned to %s", "Action '%s' slot '%s' (%d) could not be assigned to %s",
anim->id.name + 2, action->id.name + 2,
slot->name, slot->name,
slot->handle, slot->handle,
animated_id.name + 2); animated_id.name + 2);
@ -288,7 +288,7 @@ static void rna_AnimData_action_slot_handle_set(
BLI_assert_unreachable(); BLI_assert_unreachable();
WM_reportf(RPT_ERROR, WM_reportf(RPT_ERROR,
"Action '%s' slot could not be unassigned from %s", "Action '%s' slot could not be unassigned from %s",
anim->id.name + 2, action->id.name + 2,
animated_id.name + 2); animated_id.name + 2);
} }
return; return;
@ -317,46 +317,46 @@ static void rna_AnimData_action_slot_set(PointerRNA *ptr, int value)
const slot_handle_t new_slot_handle = slot_handle_t(value); const slot_handle_t new_slot_handle = slot_handle_t(value);
if (new_slot_handle == Slot::unassigned) { if (new_slot_handle == Slot::unassigned) {
/* No need to check with the Animation, as 'no slot' is always valid. */ /* No need to check with the Action, as 'no slot' is always valid. */
adt.slot_handle = Slot::unassigned; adt.slot_handle = Slot::unassigned;
return; return;
} }
if (!adt.action) { if (!adt.action) {
/* No Action to verify the slot handle is valid. As the slot handle /* No Action to verify the slot handle is valid. As the slot handle will be
* will be completely ignored when re-assigning an Animation, better to * completely ignored when re-assigning an Action, better to refuse setting
* refuse setting it altogether. This will make bugs in Python code more obvious. */ * it altogether. This will make bugs in Python code more obvious. */
WM_reportf(RPT_ERROR, WM_reportf(RPT_ERROR,
"Data-block '%s' does not have an Action, cannot set slot handle", "Data-block '%s' does not have an Action, cannot set slot handle",
animated_id.name + 2); animated_id.name + 2);
return; return;
} }
Action &anim = adt.action->wrap(); Action &action = adt.action->wrap();
Slot *slot = nullptr; Slot *slot = nullptr;
/* TODO: handle legacy Action. */ /* TODO: handle legacy Action. */
BLI_assert(anim.is_action_layered()); BLI_assert(action.is_action_layered());
if (new_slot_handle == slot_items_value_create_new) { if (new_slot_handle == slot_items_value_create_new) {
/* Special case for this enum item. */ /* Special case for this enum item. */
slot = &anim.slot_add_for_id(animated_id); slot = &action.slot_add_for_id(animated_id);
} }
else { else {
slot = anim.slot_for_handle(new_slot_handle); slot = action.slot_for_handle(new_slot_handle);
if (!slot) { if (!slot) {
WM_reportf(RPT_ERROR, WM_reportf(RPT_ERROR,
"Animation '%s' has no slot with handle %d", "Action '%s' has no slot with handle %d",
anim.id.name + 2, action.id.name + 2,
new_slot_handle); new_slot_handle);
return; return;
} }
} }
if (!anim.assign_id(slot, animated_id)) { if (!action.assign_id(slot, animated_id)) {
WM_reportf(RPT_ERROR, WM_reportf(RPT_ERROR,
"Animation '%s' slot '%s' (%d) could not be assigned to %s", "Action '%s' slot '%s' (%d) could not be assigned to %s",
anim.id.name + 2, action.id.name + 2,
slot->name_without_prefix().c_str(), slot->name_without_prefix().c_str(),
slot->handle, slot->handle,
animated_id.name + 2); animated_id.name + 2);
@ -384,10 +384,10 @@ static const EnumPropertyItem *rna_AnimData_action_slot_itemf(bContext * /*C*/,
EnumPropertyItem *items = nullptr; EnumPropertyItem *items = nullptr;
int num_items = 0; int num_items = 0;
const Action &anim = adt.action->wrap(); const Action &action = adt.action->wrap();
bool found_assigned_slot = false; bool found_assigned_slot = false;
for (const Slot *slot : anim.slots()) { for (const Slot *slot : action.slots()) {
item.value = slot->handle; item.value = slot->handle;
item.identifier = slot->name; item.identifier = slot->name;
item.name = slot->name_without_prefix().c_str(); item.name = slot->name_without_prefix().c_str();
@ -403,7 +403,7 @@ static const EnumPropertyItem *rna_AnimData_action_slot_itemf(bContext * /*C*/,
} }
/* Only add the 'New' option when this is a Layered Action. */ /* Only add the 'New' option when this is a Layered Action. */
const bool is_layered = anim.is_action_layered(); const bool is_layered = action.is_action_layered();
if (is_layered) { if (is_layered) {
RNA_enum_item_add(&items, &num_items, &rna_enum_action_slot_item_new); RNA_enum_item_add(&items, &num_items, &rna_enum_action_slot_item_new);
} }

@ -7457,8 +7457,8 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
RNA_def_property_boolean_sdna(prop, nullptr, "use_animation_baklava", 1); RNA_def_property_boolean_sdna(prop, nullptr, "use_animation_baklava", 1);
RNA_def_property_ui_text( RNA_def_property_ui_text(
prop, prop,
"New Animation Data-block", "Multi-Slot Actions",
"The new 'Animation' data-block can contain the animation for multiple data-blocks at once"); "The new 'layered' Action can contain the animation for multiple data-blocks at once");
RNA_def_property_update(prop, 0, "rna_userdef_update"); RNA_def_property_update(prop, 0, "rna_userdef_update");
} }

@ -20,61 +20,61 @@ class ActionSlotAssignmentTest(unittest.TestCase):
def test_action_assignment(self): def test_action_assignment(self):
# Create new Action. # Create new Action.
anim = bpy.data.actions.new('TestAction') action = bpy.data.actions.new('TestAction')
self.assertEqual(0, anim.users) self.assertEqual(0, action.users)
# Assign the animation to the cube, # Assign the animation to the cube,
cube = bpy.data.objects['Cube'] cube = bpy.data.objects['Cube']
cube_adt = cube.animation_data_create() cube_adt = cube.animation_data_create()
cube_adt.action = anim cube_adt.action = action
self.assertEqual(1, anim.users) self.assertEqual(1, action.users)
# Assign the animation to the camera as well. # Assign the animation to the camera as well.
camera = bpy.data.objects['Camera'] camera = bpy.data.objects['Camera']
camera_adt = camera.animation_data_create() camera_adt = camera.animation_data_create()
camera_adt.action = anim camera_adt.action = action
self.assertEqual(2, anim.users) self.assertEqual(2, action.users)
# Unassigning should decrement the user count. # Unassigning should decrement the user count.
cube_adt.action = None cube_adt.action = None
self.assertEqual(1, anim.users) self.assertEqual(1, action.users)
# Deleting the camera should also decrement the user count. # Deleting the camera should also decrement the user count.
bpy.data.objects.remove(camera) bpy.data.objects.remove(camera)
self.assertEqual(0, anim.users) self.assertEqual(0, action.users)
def test_slot_assignment(self): def test_slot_assignment(self):
# Create new Action. # Create new Action.
anim = bpy.data.actions.new('TestAction') action = bpy.data.actions.new('TestAction')
self.assertEqual(0, anim.users) self.assertEqual(0, action.users)
# Assign the animation to the cube, # Assign the Action to the cube,
cube = bpy.data.objects['Cube'] cube = bpy.data.objects['Cube']
cube_adt = cube.animation_data_create() cube_adt = cube.animation_data_create()
cube_adt.action = anim cube_adt.action = action
bind_cube = anim.slots.new(for_id=cube) slot_cube = action.slots.new(for_id=cube)
cube_adt.action_slot_handle = bind_cube.handle cube_adt.action_slot_handle = slot_cube.handle
self.assertEqual(cube_adt.action_slot_handle, bind_cube.handle) self.assertEqual(cube_adt.action_slot_handle, slot_cube.handle)
# Assign the animation to the camera as well. # Assign the Action to the camera as well.
camera = bpy.data.objects['Camera'] camera = bpy.data.objects['Camera']
bind_camera = anim.slots.new(for_id=camera) slot_camera = action.slots.new(for_id=camera)
camera_adt = camera.animation_data_create() camera_adt = camera.animation_data_create()
camera_adt.action = anim camera_adt.action = action
self.assertEqual(camera_adt.action_slot_handle, bind_camera.handle) self.assertEqual(camera_adt.action_slot_handle, slot_camera.handle)
# Unassigning should keep the slot name. # Unassigning should keep the slot name.
cube_adt.action = None cube_adt.action = None
self.assertEqual(cube_adt.action_slot_name, bind_cube.name) self.assertEqual(cube_adt.action_slot_name, slot_cube.name)
# It should not be possible to set the slot handle while the animation is unassigned. # It should not be possible to set the slot handle while the Action is unassigned.
bind_extra = anim.slots.new() slot_extra = action.slots.new()
cube_adt.action_slot_handle = bind_extra.handle cube_adt.action_slot_handle = slot_extra.handle
self.assertNotEqual(cube_adt.action_slot_handle, bind_extra.handle) self.assertNotEqual(cube_adt.action_slot_handle, slot_extra.handle)
class LimitationsTest(unittest.TestCase): class LimitationsTest(unittest.TestCase):
"""Test artificial limitations for the Animation data-block. """Test artificial limitations for the layered Action.
Certain limitations are in place to keep development & testing focused. Certain limitations are in place to keep development & testing focused.
""" """
@ -85,22 +85,22 @@ class LimitationsTest(unittest.TestCase):
anims.remove(anims[0]) anims.remove(anims[0])
def test_initial_layers(self): def test_initial_layers(self):
"""Test that upon creation an Animation has no layers/strips.""" """Test that upon creation an Action has no layers/strips."""
anim = bpy.data.actions.new('TestAction') action = bpy.data.actions.new('TestAction')
self.assertEqual([], anim.layers[:]) self.assertEqual([], action.layers[:])
def test_limited_layers_strips(self): def test_limited_layers_strips(self):
"""Test that there can only be one layer with one strip.""" """Test that there can only be one layer with one strip."""
anim = bpy.data.actions.new('TestAction') action = bpy.data.actions.new('TestAction')
layer = anim.layers.new(name="Layer") layer = action.layers.new(name="Layer")
self.assertEqual([], layer.strips[:]) self.assertEqual([], layer.strips[:])
strip = layer.strips.new(type='KEYFRAME') strip = layer.strips.new(type='KEYFRAME')
# Adding a 2nd layer should be forbidden. # Adding a 2nd layer should be forbidden.
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
anim.layers.new(name="Forbidden Layer") action.layers.new(name="Forbidden Layer")
self.assertEqual([layer], anim.layers[:]) self.assertEqual([layer], action.layers[:])
# Adding a 2nd strip should be forbidden. # Adding a 2nd strip should be forbidden.
with self.assertRaises(RuntimeError): with self.assertRaises(RuntimeError):
@ -110,8 +110,8 @@ class LimitationsTest(unittest.TestCase):
def test_limited_strip_api(self): def test_limited_strip_api(self):
"""Test that strips have no frame start/end/offset properties.""" """Test that strips have no frame start/end/offset properties."""
anim = bpy.data.actions.new('TestAction') action = bpy.data.actions.new('TestAction')
layer = anim.layers.new(name="Layer") layer = action.layers.new(name="Layer")
strip = layer.strips.new(type='KEYFRAME') strip = layer.strips.new(type='KEYFRAME')
self.assertFalse(hasattr(strip, 'frame_start')) self.assertFalse(hasattr(strip, 'frame_start'))
@ -171,9 +171,9 @@ class DataPathTest(unittest.TestCase):
anims.remove(anims[0]) anims.remove(anims[0])
def test_repr(self): def test_repr(self):
anim = bpy.data.actions.new('TestAction') action = bpy.data.actions.new('TestAction')
layer = anim.layers.new(name="Layer") layer = action.layers.new(name="Layer")
self.assertEqual("bpy.data.actions['TestAction'].layers[\"Layer\"]", repr(layer)) self.assertEqual("bpy.data.actions['TestAction'].layers[\"Layer\"]", repr(layer))
strip = layer.strips.new(type='KEYFRAME') strip = layer.strips.new(type='KEYFRAME')