Anim: add iterator over Action Slot uses, with references
Add an iterator `foreach_action_slot_use_with_references(ID, callback)` that provides references to the found `bAction` pointer and slot handle. That way the callback can assign another Action or slot when it sees fit, without having to know exactly what the source of this info is (could be a direct assignment, but also an NLA strip or Action Constraint). Ref: #127844 Pull Request: https://projects.blender.org/blender/blender/pulls/127871
This commit is contained in:
@@ -57,4 +57,17 @@ bool foreach_action_slot_use(
|
||||
const ID &animated_id,
|
||||
FunctionRef<bool(const Action &action, slot_handle_t slot_handle)> callback);
|
||||
|
||||
/**
|
||||
* Same as foreach_action_slot_use(), except that it reports some pointers so the callback can
|
||||
* modify which Action/slot is assigned.
|
||||
*
|
||||
* \see blender::animrig::generic_assign_action
|
||||
* \see blender::animrig::generic_assign_action_slot
|
||||
* \see blender::animrig::generic_assign_action_slot_handle
|
||||
*/
|
||||
bool foreach_action_slot_use_with_references(
|
||||
ID &animated_id,
|
||||
FunctionRef<bool(bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *slot_name)>
|
||||
callback);
|
||||
|
||||
} // namespace blender::animrig
|
||||
|
||||
@@ -51,12 +51,31 @@ bool foreach_action_slot_use(
|
||||
const ID &animated_id,
|
||||
FunctionRef<bool(const Action &action, slot_handle_t slot_handle)> callback)
|
||||
{
|
||||
|
||||
const auto forward_to_callback = [&](bAction *&action_ptr_ref,
|
||||
const slot_handle_t &slot_handle_ref,
|
||||
char * /*slot_name*/) -> bool {
|
||||
if (!action_ptr_ref) {
|
||||
return true;
|
||||
}
|
||||
return callback(const_cast<const Action &>(action_ptr_ref->wrap()), slot_handle_ref);
|
||||
};
|
||||
|
||||
return foreach_action_slot_use_with_references(const_cast<ID &>(animated_id),
|
||||
forward_to_callback);
|
||||
}
|
||||
|
||||
bool foreach_action_slot_use_with_references(
|
||||
ID &animated_id,
|
||||
FunctionRef<bool(bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *slot_name)>
|
||||
callback)
|
||||
{
|
||||
AnimData *adt = BKE_animdata_from_id(&animated_id);
|
||||
|
||||
if (adt) {
|
||||
if (adt->action) {
|
||||
/* Direct assignment. */
|
||||
if (!callback(adt->action->wrap(), adt->slot_handle)) {
|
||||
if (!callback(adt->action, adt->slot_handle, adt->slot_name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -64,7 +83,7 @@ bool foreach_action_slot_use(
|
||||
/* NLA strips. */
|
||||
const bool looped_until_last_strip = bke::nla::foreach_strip_adt(*adt, [&](NlaStrip *strip) {
|
||||
if (strip->act) {
|
||||
if (!callback(strip->act->wrap(), strip->action_slot_handle)) {
|
||||
if (!callback(strip->act, strip->action_slot_handle, strip->action_slot_name)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -96,7 +115,9 @@ bool foreach_action_slot_use(
|
||||
if (!constraint_data->act) {
|
||||
return true;
|
||||
}
|
||||
return callback(constraint_data->act->wrap(), constraint_data->action_slot_handle);
|
||||
return callback(constraint_data->act,
|
||||
constraint_data->action_slot_handle,
|
||||
constraint_data->action_slot_name);
|
||||
};
|
||||
|
||||
/* Visit Object constraints. */
|
||||
|
||||
@@ -107,4 +107,47 @@ TEST_F(ActionIteratorsTest, iterate_all_fcurves_of_slot)
|
||||
});
|
||||
ASSERT_TRUE(invalid_slot_fcurves.is_empty());
|
||||
}
|
||||
|
||||
TEST_F(ActionIteratorsTest, foreach_action_slot_use_with_references)
|
||||
{
|
||||
/* Create a cube and assign the Action + a slot. */
|
||||
Object *cube = static_cast<Object *>(BKE_id_new(bmain, ID_OB, "OBCube"));
|
||||
Slot *slot_cube = assign_action_ensure_slot_for_keying(*action, cube->id);
|
||||
ASSERT_NE(slot_cube, nullptr);
|
||||
|
||||
/* Create another Action with slot to assign. */
|
||||
Action &other_action =
|
||||
static_cast<bAction *>(BKE_id_new(bmain, ID_AC, "ACAnotherAction"))->wrap();
|
||||
Slot &another_slot = other_action.slot_add();
|
||||
|
||||
std::optional<ActionSlotAssignmentResult> slot_assignment_result;
|
||||
|
||||
const auto assign_other_action =
|
||||
[&](bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *slot_name) -> bool {
|
||||
/* Assign the other Action. */
|
||||
generic_assign_action(cube->id, &other_action, action_ptr_ref, slot_handle_ref, slot_name);
|
||||
|
||||
/* Assign the slot of the other Action. */
|
||||
slot_assignment_result = generic_assign_action_slot(
|
||||
&another_slot, cube->id, action_ptr_ref, slot_handle_ref, slot_name);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
foreach_action_slot_use_with_references(cube->id, assign_other_action);
|
||||
|
||||
/* Check the result, the slot assignment should have been changed. */
|
||||
ASSERT_TRUE(slot_assignment_result.has_value());
|
||||
EXPECT_EQ(ActionSlotAssignmentResult::OK, slot_assignment_result.value());
|
||||
|
||||
std::optional<std::pair<Action *, Slot *>> action_and_slot = get_action_slot_pair(cube->id);
|
||||
|
||||
ASSERT_TRUE(action_and_slot.has_value());
|
||||
EXPECT_EQ(&other_action, action_and_slot->first)
|
||||
<< "Expected Action " << other_action.id.name << " but found "
|
||||
<< action_and_slot->first->id.name;
|
||||
EXPECT_EQ(&another_slot, action_and_slot->second)
|
||||
<< "Expected Slot " << another_slot.name << " but found " << action_and_slot->second->name;
|
||||
}
|
||||
|
||||
} // namespace blender::animrig::tests
|
||||
|
||||
Reference in New Issue
Block a user