Commit Graph

341 Commits

Author SHA1 Message Date
Christoph Lendenfeld
34a18c7608 Anim: Merge Animation operator
This adds the "Merge Animation" (`ANIM_OT_merge_animation`) operator to the 3D viewport.
It merges the animation of all selected objects into the animation of the active object.

On a technical level this moves the `ChannelBag` of the source action into a new slot
on the target action. The Slot name is copied but might differ due to name clashes.
Due to this, the operator is named "Merge Animation" and not "Merge Actions" since
it might not merge the complete actions but only the slots actually used by the selection
in the 3D viewport

This operator will find all related IDs to the selection, i.e. object data, shape keys etc. and merge those as well.
That means this operator can also be used to JUST merge the actions of the active object and its data.

### Caveats
Because there may be more than 1 slot user this might reassign an object that isn't actually selected.
The other option is that when there is more than 1 slot user, the `ChannelBag` is copied instead of moved.
That means moving objects that share a slot one by one would result in a loss of slot sharing and
data duplication. I think it's better to respect the artist decision of "these things use the same animation"
in this case. (open to opinions though)

Design task: #126937

Pull Request: https://projects.blender.org/blender/blender/pulls/127414
2024-09-20 15:08:16 +02:00
Nathan Vegdahl
b200d1f975 Anim: remove strip data as well when an action strip is removed
This is a follow up to #126559. In that PR, strip data is never deleted even
when the strip that uses it is. Thus, the strip data array just keeps growing as
more strips are added, and never shrinks.

This PR implements that deletion. The approach is simple: remove the strip data
from the array using a swap-remove that swaps in the last item in the data
array, and then loop over the strips in the action to update any that were
referencing that swapped-in item. Additionally, before removal we check to make
sure the data item isn't still being used by any strips, and if it is then we
don't remove it.

Pull Request: https://projects.blender.org/blender/blender/pulls/127837
2024-09-20 13:07:15 +02:00
Sybren A. Stüvel
b51d60a226 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
2024-09-20 10:30:15 +02:00
Sybren A. Stüvel
615cb46412 Anim: add Action Slot selector to Action Constraint
Add slotted Actions support to Action constraints.

The user interface can be improved once #127751 lands.

Ref: #120406
Pull Request: https://projects.blender.org/blender/blender/pulls/127749
2024-09-20 08:07:15 +02:00
Campbell Barton
0fc27c8d81 Cleanup: spelling in comments 2024-09-20 13:14:57 +10:00
Sybren A. Stüvel
3fcd153d89 Anim: fix unit test when built without experimental features
The `ActionQueryTest` unit test was unconditionally creating a layered
Action, which fails the test when Blender was built without experimental
features.

Pull Request: https://projects.blender.org/blender/blender/pulls/127840
2024-09-19 14:47:59 +02:00
Sybren A. Stüvel
823ee1ac92 Anim: add F-Curve getter functions that work with legacy & layered Actions
Add some F-Curve getter functions that work in all these situations:

- Built without experimental features.
- Built with experimental features, and called with legacy Action.
- Built with experimental features, and called with layered Action.

No functional changes, just useful tools for migrating to the new
Actions API.

Ref: #120406

Pull Request: https://projects.blender.org/blender/blender/pulls/127841
2024-09-19 14:46:25 +02:00
Nathan Vegdahl
91fd95bad4 Cleanup: make strip_keyframe_data_append() doc comment accurate 2024-09-19 13:56:19 +02:00
Nathan Vegdahl
7acdb8f90d Fix: compiler warning from using memcpy on non-trivial type
Also return a pointer from `Layer::duplicate_with_shallow_strip_copies()`
rather than a reference, since it doesn't maintain ownership of the
returned item.
2024-09-17 18:55:30 +02:00
Nathan Vegdahl
e0d5379ef8 Anim: change how action strip data is stored
This updates the layered action data model to store strip data differently.  Specifically:

- `Strip` is now just a single, POD type that only stores the data common to all
  strips, such as start/end frames.
- The data that might be of a completely different nature between strips (e.g.
  keyframe data vs modifier data) is now stored in arrays on the action itself.
- `Strip`s indicate their type with an enum, and specify their data with an
  index into the array on the action that stores data for that type.

This approach requires a little more data juggling, but has the advantage of
making `Strip`s themselves super simple POD types, and also opening the door to
trivial strip instancing later on: instances are just strips that point at the
same data.

The intention is that the RNA API remains the same: from RNA's perspective there
is no data storage separate from the strips, and a strip's data is presented as
fields and methods directly on the strip itself. Different strip types will be
presented as different subtypes of `ActionStrip`, each with their own fields and
methods specific to their underlying data's type. However, this PR doesn't
implement that sub-typing, leaving it for a future PR. It does, however, put the
fields and methods of the one strip type we have so far directly on the strip,
which avoids changing the APIs we have so far.

This PR implements the bulk of this new approach, and everything should be
functional and working correctly. However, there are two TODO items left over
that will be implemented in forthcoming PRs:

- Type refinement in the RNA api. This PR actually removes the existing type
  refinement code that was implemented in terms of the inheritance tree of the
  actual C++ types, and this will need to be reimplemented in terms of the new
  data model. The RNA API still works without the type refinement since there
  are only keyframe strips right now, but it will be needed in preparation for
  more strip types down the road.
- Strip data deletion. This PR only deletes data from the strip data arrays when
  the whole action is deleted, and otherwise just accumulates strip data as more
  and more strips are added, never removing the data when the corresponding
  strips get removed. That's fine in the short term, especially since we only
  support single strips right now. But it does need to be implemented in
  preparation for proper layered actions.

Pull Request: https://projects.blender.org/blender/blender/pulls/126559
2024-09-17 17:31:09 +02:00
Sybren A. Stüvel
d5a1b02c5d Refactor: Anim, Generic functions for RNA Action Slots / Handles
Refactor the slot assignment & related properties to use as much generic
code as possible. This'll make it much easier to add Action+Slot
properties to other data-blocks in the future (currently just planned
for the Action Constraint).

Pull Request: https://projects.blender.org/blender/blender/pulls/127720
2024-09-17 11:03:06 +02:00
Campbell Barton
65d71c2672 Cleanup: spelling in comments 2024-09-17 17:28:02 +10:00
Sybren A. Stüvel
12fe0dd0cf Anim: make action/slot assignment code more generic
In the `blender::animrig` namespace, add two new functions
`generic_assign_action()` and `generic_assign_action_slot()`. These are
now used as basis for (un)assigning Actions and Action slots, both
directly on the ID and for NLA strips.

The method `Action::assign_id()` has been removed, in favour of free
functions for (un)assigning Actions and slots.

This is almost a non-functional change. The only thing that's different
is when both an Action and a slot should get assigned in one go.

Old behaviour: the slot would be inspected, and if not suitable for the
animated ID, the entire operation would be aborted. In other words, any
previously-assigned Action would still be assigned, making this an
atomic operation.

New behaviour: assigning an Action + a slot is no longer atomic. First
the new Action is assigned (which uses the automatic slot selection
based on the name). If after this the given slot cannot be assigned, the
new Action + the auto-selected slot are still kept.

This makes the Action & slot assignment more uniform in behaviour, where
"assign this Action + this slot" as one operation behaves the same as
two sequential operations "assign this Action" + "assign this slot". If
it turns out to be confusing, we can always improve things.

The return code for slot assignment is now more explicit (enum instead
of boolean), so that the caller can decide what to do in case of which
error (like unassigning the slot if the automatic behaviour is
unwanted).

Pull Request: https://projects.blender.org/blender/blender/pulls/127712
2024-09-16 19:31:35 +02:00
Campbell Barton
9b39b4c91c Cleanup: use const pointers/references 2024-09-15 23:14:09 +10:00
Campbell Barton
9be29e1bbc Cleanup: match function & declaration names 2024-09-15 23:14:07 +10:00
Christoph Lendenfeld
cb6ed12ef1 Anim: Reuse action between related data
When inserting keys, look on related IDs for an action to reuse that.
This will make use of the slot system on the new layered action to ensure
the animation data doesn't collide.

This is done on the `id_action_ensure` function since that is the common
function to get an action off an `ID`.

IDs with more than 1 user will be skipped.

"Related ID" in this case is hardcoded with a `switch` statement for each ID type.
The system builds a list starting from the ID that should be keyed and
keeps expanding the list until an action is found or no more
non-duplicate IDs can be added. (This is using linear search for duplicate checks,
but I don't think we will deal with a lot of IDs in this case)

Pull Request: https://projects.blender.org/blender/blender/pulls/126655
2024-09-13 17:57:22 +02:00
Sybren A. Stüvel
7916a33be0 Anim: correctly auto-sync NLA strip length for slotted Action
When syncing the NLA strip length with the Action it uses, use the
length of the assigned action slot. Previously the entire Action was
considered when determining the length.

Pull Request: https://projects.blender.org/blender/blender/pulls/127573
2024-09-13 15:10:46 +02:00
Sybren A. Stüvel
b952782a44 Refactor: Anim, move Action queries from BKE to the animrig::Action class
Move the following BKE functions to the `animrig::Action` class. Some of
those will be extended to support slots in a future commit; for now they
still operate on all F-Curves in the Action.

| Old                             | New                                 |
|---------------------------------|-------------------------------------|
| `BKE_action_frame_range_calc()` | `Action::get_frame_range_of_keys()` |
| `BKE_action_frame_range_get()`  | `Action::get_frame_range()`         |
| `BKE_action_has_motion()`       | `Action::has_keyframes()`           |
| `BKE_action_has_single_frame()` | `Action::has_single_frame()`        |
| `BKE_action_is_cyclic()`        | `Action::is_cyclic()`               |

Implementations have been copied from the BKE functions. The frame range
functions now return `float2` instead of requiring two `float *r_…`
return parameters.

The `has_motion` function is now renamed to `has_keyframes`, as that is
what the implementation was actually testing for.

The functions now no longer are null-safe. The BKE functions handled a
null action pointer, but IMO that doesn't make sense, and in none of the
call sites I could find where this would actually be valid.

No functional changes.

Ref: #127489

Pull Request: https://projects.blender.org/blender/blender/pulls/127512
2024-09-13 15:04:47 +02:00
Sybren A. Stüvel
7cb77d925a Anim: add NLA evaluation of slotted Actions
Add support for slotted Actions to the NLA evaluation code.

This also affects the pose library code and the Action Constraint. These
both share some Action evaluation logic with the NLA. They now
explicitly looks at only the first Action slot. The Action Constraint will
have to be updated to have an explicit slot selector, but that's for another
commit.

Pull Request: https://projects.blender.org/blender/blender/pulls/127425
2024-09-13 12:34:50 +02:00
Sybren A. Stüvel
7cd3f2aabb Refactor: Anim, prepare for slotted Action support to quaternion eval
Refactor to prepare for slotted action support to the evaluation of
quaternion F-Curves.

Since slotted Actions store F-Curves in an array, you cannot iterate over
them any more via the `ListBase` pointer `fcurve.next`. Quaternion
evaluation code has been refactored to work on a span of F-Curves instead
of just getting the first one.

For now, slotted Actions just evaluate their first slot only. A future
commit will add a slot handle parameter to evaluate the correct slot.
2024-09-13 12:34:48 +02:00
Sybren A. Stüvel
9405a47442 Fix: Anim, duplicating Action misses some properties
Duplicating an Action was missing the Slot flags (so they reset to
collapsed and unselected) and the F-Curve group memberships.

Pull Request: https://projects.blender.org/blender/blender/pulls/127560
2024-09-13 12:05:28 +02:00
Campbell Barton
81e2ccbf2b Cleanup: spelling in comments 2024-09-13 10:56:26 +10:00
Sybren A. Stüvel
367cceaab8 Anim: Make it possible to enter/exit NLA tweak mode on slotted Actions
Properly track Action and Slot assignment when entering/exiting NLA
tweak mode.

This doesn't properly sync the length of the NLA strip when exiting
tweak mode. This and more NLA work is tracked at #127489.

Pull Request: https://projects.blender.org/blender/blender/pulls/127498
2024-09-12 16:48:02 +02:00
Sybren A. Stüvel
3417934eff Anim: add Action Slot assignment to NLA strip
For an NLA strip to use a slotted Action, it needs to specify which slot
to use in that action. This is now handled by two new properties on the
strip in DNA & RNA: `action_slot_handle` and `action_slot_name`.

These serve the same purpose as their counterparts on the `AnimData`
struct.

Note that this commit does NOT add NLA evaluation support for slotted
Actions. It merely allows assigning them. Evaluation, tweak mode
support, etc. will be implemented in future commits.

Pull Request: https://projects.blender.org/blender/blender/pulls/127359
2024-09-12 14:08:16 +02:00
Campbell Barton
e00fed43e6 Cleanup: redundant struct declarations 2024-09-11 16:25:25 +10:00
Sybren A. Stüvel
3fdc9e9637 Refactor: convert BKE_action.h to C++
Move the contents of `BKE_action.h` into `BKE_action.hh` and remove
C-isms.

No functional changes.

Pull Request: https://projects.blender.org/blender/blender/pulls/127407
2024-09-10 14:55:47 +02:00
Sybren A. Stüvel
636d83fbea Refactor: convert BKE_nla.h to C++
Rename `BKE_nla.h` to `BKE_nla.hh` and remove C-isms.

No functional changes.

Pull Request: https://projects.blender.org/blender/blender/pulls/127395
2024-09-10 13:41:01 +02:00
Nathan Vegdahl
0b5e878ae1 Refactor: use references in channel group unit tests
@dr.sybren recommended this in the review of #127080, to be consistent with
the more modern C++ style Blender is trying to adhere to in new code.

No functional changes.

Pull Request: https://projects.blender.org/blender/blender/pulls/127343
2024-09-09 14:04:24 +02:00
Christoph Lendenfeld
7cb0e2cd1e Anim: Convert FCurve groups from legacy to layered
When converting a legacy Action to a layered Action,
also convert group memberships.

This is important for bones to retain their structure in
the Channel Box.

Pull Request: https://projects.blender.org/blender/blender/pulls/127188
2024-09-06 17:24:13 +02:00
Nathan Vegdahl
92a7229f67 Anim: implement channel grouping/moving ops for layered actions
This adds layered animation support to the following operators, allowing users to manage the grouping and arrangement of fcurves in the channel list:

- "Group Channels"
- "Ungroup Channels"
- "Move Channels"

Pull Request: https://projects.blender.org/blender/blender/pulls/127080
2024-09-06 16:12:05 +02:00
Nathan Vegdahl
bf373d94fe Fix: crash when deleting layered-action channel groups via the UI
The cause was simple: I missed this operator in the initial layered-action
channel group implementation, so deletion was using the legacy action code
even for layered actions.

This implements the needed code in the deletion operator to handle layered
actions.

Pull Request: https://projects.blender.org/blender/blender/pulls/127242
2024-09-06 14:44:59 +02:00
Sybren A. Stüvel
158b7ae5da Cleanup: Anim, Document that channel_group_create() makes name unique
Document that `ChannelBag::channel_group_create(name)` ensures the group
name is unique within the channelbag.

No functional changes.
2024-09-06 14:33:57 +02:00
Sybren A. Stüvel
f7d4a517e3 Anim: add Action::slot_remove() method to remove an action slot
Add a method to remove a slot from an Action. This is also exposed as
`Action.slots.remove(slot)` to RNA/Python.

Removing a slot deletes all its associated animation data in the Action.
It also un-assigns the slot from any ID that was animated by it. The
Action reference is left untouched.

Pull Request: https://projects.blender.org/blender/blender/pulls/127112
2024-09-05 16:34:01 +02:00
Christoph Lendenfeld
a661a7bf89 Refactor: Move Pose code out of the kernel
Move the functions
* `BKE_pose_apply_action_selected_bones`
* `BKE_pose_apply_action_all_bones`
* and `BKE_pose_apply_action_blend`

out of the blender kernel and into animrig.

This will allow solving #126969 without having to include
animrig code in the blender kernel.

Pull Request: https://projects.blender.org/blender/blender/pulls/126978
2024-09-05 10:41:34 +02:00
Jesse Yurkovich
787eb2b433 Fix: prevent free of nullptr during bone collection undo processing
It's possible for the `bArmature.collection_array` to be null if Bone
Collections were never added after armature creation. This could trip up
undo processing later when we call `MEM_freeN` on the collection.

Use a `MEM_SAFE_FREE` call instead which handles checking for null, as
well as setting to null when complete.

Pull Request: https://projects.blender.org/blender/blender/pulls/126945
2024-09-03 19:19:26 +02:00
Campbell Barton
e34d9eeac7 Cleanup: use C-style comments, double quote Python text 2024-09-03 21:22:34 +10:00
Nathan Vegdahl
580be3862a Fix: deleting fcurve in a group creates inconsistent group state
This issue only applied to layered actions.

The issue was that the `restore_channel_group_invariants()` method was
being called too early in the remove fcurve function, and thus fcurves'
group pointers could end up inconsistent with the membership specified
in the groups.

This commit fixes the issue by moving the call to
`restore_channel_group_invariants()` to the end of the function, where
it belongs.

Pull Request: https://projects.blender.org/blender/blender/pulls/127075
2024-09-02 15:38:34 +02:00
Sybren A. Stüvel
402e87c6d2 Anim: find Action Slot users on embedded IDs
Find Action Slot users on embedded IDs, such as the Node Tree used by a
Material.

Pull Request: https://projects.blender.org/blender/blender/pulls/125666
2024-09-02 11:20:51 +02:00
Campbell Barton
ff3949426c Cleanup: spelling in comments 2024-09-02 16:55:19 +10:00
Nathan Vegdahl
515843ff3a Fix: crash after saving file with 2+ layered-action channel groups
The issue was that the forward compatibility writing code for channel groups in
layered actions was building a temporary legacy listbase, but was not clearing
it properly afterwards. This was then getting caught by an assert that ensured
that layered-action groups didn't have legacy data in them.

The reason the listbase wasn't getting cleared properly is because the
prev/next listbase pointers were getting cleared using a `LISTBASE_FOREACH`
loop, and thus the loop never progressed past the first item.

Additionally, this mistake wasn't just in the channel groups writing code, but
also the forward compatibility writing code for fcurves.

This fixes the issue in both places by switching the loops to
use`LISTBASE_FOREACH_MUTABLE`.

Based on discussion with @dr.sybren, this also removes the assert that caught
the issue. The situation it guards against is actually completely benign, and
the existence of the assert is contrary to the comments in the forward-compat
writing code explaining why its approach is okay.

Pull Request: https://projects.blender.org/blender/blender/pulls/126970
2024-08-30 12:54:41 +02:00
Nathan Vegdahl
1c1e389d4b Refactor: misc improvements to the channel groups code
Addressing post-landed review comments from @dr.sybren in #125774.

These changes are all refactors and cleanups, and should have no functional changes.

Pull Request: https://projects.blender.org/blender/blender/pulls/126822
2024-08-29 19:12:45 +02:00
Nathan Vegdahl
73c1ceb18b Fix: channel groups in duplicated channel bag point to old bag
In layered actions, the channel groups in a channel bag hold a
non-owning pointer to the channel bag they belong to, to allow looking
up the fcurves in the group. However, when a duplicate was made of a
channel bag, those pointers in the (also duplicated) channel groups
weren't updated to point at it, and thus were still pointing at the
original channel bag.

This commit adds the code to properly update those pointers when
duplicating channel bags.

Pull Request: https://projects.blender.org/blender/blender/pulls/126923
2024-08-29 14:33:51 +02:00
Sybren A. Stüvel
c9f147d301 Fix #126783: Anim: keying will select previously-assigned Slot
Fix an issue that was caused by common code used for both these flows:

- 'ensure a slot exists for an ID so keys for it can be inserted' and
- 'assign an Action to an ID'

Both flows search for suitable slots for the ID, but should do so in
subtly different ways. Most importantly, the first case should _not_
search a slot by name (when an Action is already assigned but not a
slot). This is relevant in the following flow:

- Assign an Action to an Object. This auto-selects the most appropriate
  slot (by name).
- Un-assign the slot (for whatever reason it's not desired).
- Insert a key.
- This should create a new slot, and not re-assign the slot just
  un-assigned above.

Pull Request: https://projects.blender.org/blender/blender/pulls/126850
2024-08-29 12:07:58 +02:00
Sybren A. Stüvel
d3c4760617 Cleanup: expand documentation of Action::assign_id()
No functional changes.
2024-08-27 18:08:45 +02:00
Nathan Vegdahl
72aaecae51 Cleanup: improve some code documentation in the animation code 2024-08-27 17:44:50 +02:00
Campbell Barton
40f96afa61 Cleanup: various non-functional changes
- Use const arguments.
- Remove redundant cast.
- Use ELEM macro.
- Use boolean & nullptr literals.
2024-08-26 11:50:12 +10:00
Nathan Vegdahl
02e721275f Fix: make convenience array functions allocate the right type
The functions were allocating arrays of `T *` rather than `T`, and
then were reinterpret-casting to the correct type afterwards. This
coincidentally worked at the current call sites because `T` was always
a pointer type anyway, but the code was logically incorrect and wouldn't
work if anyone tried to use them with a non-pointer `T`.

This commit fixes this by correctly allocating an array of `T` instead,
and removing the unnecessary cast.

Pull Request: https://projects.blender.org/blender/blender/pulls/126656
2024-08-23 10:53:36 +02:00
Campbell Barton
878b52c072 Cleanup: quiet unused variable warning 2024-08-23 13:10:36 +10:00
Campbell Barton
07b11206eb Cleanup: sort cmake file lists 2024-08-23 10:19:53 +10:00
Nathan Vegdahl
df02e7a5e5 Anim: add channel groups to layered actions
This PR adds channel groups (also known as fcurve groups or action groups) to
layered actions.  For layered actions, these groups belong to the `ChannelBag`s
and can vary by bag.

From a user perspective, the goal is for these to function just like channel
groups from legacy actions.  However, internally they are implemented a little
differently: legacy actions store both channel groups and fcurves in a listbase,
and groups indicate what fcurves are in them with a listbase that points
directly into the larger fcurve listbase.  Layered actions, on the other hand,
store both fcurves and channel groups in an array, and groups indicate what
fcurves are in them by indexing into the fcurve array.

Despite taking this different approach, we still reuse the `bActionGroup` struct
for the new channel groups, just adding the necessary fields for index-based
fcurve membership as described above.

This PR does not implement all of the functionality needed to reach feature
parity with legacy action channel groups, but implements the main core and gets
them basically working.

It's easier to list the things that *haven't* been implemented yet:

- Operators for letting the user manually create/remove/move channel groups.
- Keyframe selection in the action/dopesheet editor on channel group rows
  themselves are not yet working correctly.
- Handling channel groups in legacy/layered action conversion operators.
- Making the legacy `action.groups` property work on single-layer-single-strip
  layered actions.

Those are left for future PRs.  Other than that, in theory everything should be
working now.

Pull Request: https://projects.blender.org/blender/blender/pulls/125774
2024-08-22 17:13:12 +02:00