Files
test/source/blender/animrig/intern/nla.cc
Sybren A. Stüvel 76bddb41df Anim: Fix NLA Strip Action assignment
When creating a new NLA strip for an action, as well as when setting
`strip.action` via RNA, use the generic action-assignment code. This
ensures that the slot selection follows the same logic as other Action
assignments.

If the generic slot selection doesn't find a suitable slot, and there is
a single slot on that Action of a suitable ID type, always assign it.
This is to support the following scenario:

- Python script creates an Action and adds F-Curves via the legacy API.
- This creates a slot 'XXSlot'.
- The script creates multiple NLA strips for that Action.
- The desired result is that these strips get the same Slot assigned as
  well.

The generic code doesn't work for this, because:

- The first strip assignment would see the slot `XXSlot` (`XX`
  indicating "not bound to any ID type yet"). Because that slot has
  never been used, it will be assigned (which is good). This assignment
  would change its name to, for example, `OBSlot`.

- The second strip assignment would not see a 'virgin' slot, and thus
  not auto-select `OBSlot`. This behaviour makes sense when assigning
  Actions in the Action editor (assigning an Action that already
  animates 'Cube' to 'Suzanne' should not assign the 'OBCube' slot to
  Suzanne), but for the NLA I feel that it could be a bit more
  'enthousiastic' in auto-picking a slot to support the above case.

This is preparation for the removal of the 'Slotted Actions'
experimental flag, and getting the new code to run as compatibly as
possible with the legacy code.

The return value of `animrig::nla::assign_action()` has changed a bit.
It used to indicate whether a slot was auto-selected; it now indicates
whether the Action assignment was successful. Whether a slot was
assigned or not can be seen at `strip.action_slot`.

Pull Request: https://projects.blender.org/blender/blender/pulls/128892
2024-10-14 13:45:02 +02:00

87 lines
3.1 KiB
C++

/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup animrig
*/
#include "ANIM_nla.hh"
#include "BKE_anim_data.hh"
#include "BKE_lib_id.hh"
#include "BKE_nla.hh"
#include "BLI_string_utf8.h"
namespace blender::animrig::nla {
bool assign_action(NlaStrip &strip, Action &action, ID &animated_id)
{
if (!generic_assign_action(
animated_id, &action, strip.act, strip.action_slot_handle, strip.action_slot_name))
{
return false;
}
/* For the NLA, the auto slot selection gets one more fallback option (compared to the generic
* code). This is to support the following scenario:
*
* - Python script creates an Action, and adds some F-Curves via the legacy API.
* - This creates a slot 'XXSlot'.
* - The script creates multiple NLA strips for that Action.
* - The desired result is that these strips get the same Slot assigned as well.
*
* The generic code doesn't work for this. The first strip assignment would see the slot
* `XXSlot`, and because it has never been used, just use it. This would change its name to, for
* example, `OBSlot`. The second strip assignment would not see a 'virgin' slot, and thus not
* auto-select `OBSlot`. This behaviour makes sense when assigning Actions in the Action editor
* (it shouldn't automatically pick the first slot of matching ID type), but for the NLA I
* (Sybren) feel that it could be a bit more 'enthousiastic' in auto-picking a slot.
*/
if (strip.action_slot_handle == Slot::unassigned && action.slots().size() == 1) {
Slot *first_slot = action.slot(0);
if (first_slot->is_suitable_for(animated_id)) {
const ActionSlotAssignmentResult result = assign_action_slot(strip, first_slot, animated_id);
BLI_assert_msg(result == ActionSlotAssignmentResult::OK,
"Assigning a slot that we know is suitable should work");
UNUSED_VARS_NDEBUG(result);
}
}
/* Regardless of slot auto-selection, the Action assignment worked just fine. */
return true;
}
void unassign_action(NlaStrip &strip, ID &animated_id)
{
const bool ok = generic_assign_action(
animated_id, nullptr, strip.act, strip.action_slot_handle, strip.action_slot_name);
BLI_assert_msg(ok, "Un-assigning an Action from an NLA strip should always work.");
UNUSED_VARS_NDEBUG(ok);
}
ActionSlotAssignmentResult assign_action_slot(NlaStrip &strip,
Slot *slot_to_assign,
ID &animated_id)
{
BLI_assert(strip.act);
return generic_assign_action_slot(
slot_to_assign, animated_id, strip.act, strip.action_slot_handle, strip.action_slot_name);
}
ActionSlotAssignmentResult assign_action_slot_handle(NlaStrip &strip,
const slot_handle_t slot_handle,
ID &animated_id)
{
BLI_assert(strip.act);
Action &action = strip.act->wrap();
Slot *slot_to_assign = action.slot_for_handle(slot_handle);
return assign_action_slot(strip, slot_to_assign, animated_id);
}
} // namespace blender::animrig::nla