This commit takes the 'Slotted Actions' out of the experimental phase.
As a result:
- All newly created Actions will be slotted Actions.
- Legacy Actions loaded from disk will be versioned to slotted Actions.
- The new Python API for slots, layers, strips, and channel bags is
available.
- The legacy Python API for accessing F-Curves and Action Groups is
still available, and will operate on the F-Curves/Groups for the first
slot only.
- Creating an Action by keying (via the UI, operators, or the
`rna_struct.keyframe_insert` function) will try and share Actions
between related data-blocks. See !126655 for more info about this.
- Assigning an Action to a data-block will auto-assign a suitable Action
Slot. The logic for this is described below. However, There are cases
where this does _not_ automatically assign a slot, and thus the Action
will effectively _not_ animate the data-block. Effort has been spent
to make Action selection work both reliably for Blender users as well
as keep the behaviour the same for Python scripts. Where these two
goals did not converge, reliability and understandability for users
was prioritised.
Auto-selection of the Action Slot upon assigning the Action works as
follows. The first rule to find a slot wins.
1. The data-block remembers the slot name that was last assigned. If the
newly assigned Action has a slot with that name, it is chosen.
2. If the Action has a slot with the same name as the data-block, it is
chosen.
3. If the Action has only one slot, and it has never been assigned to
anything, it is chosen.
4. If the Action is assigned to an NLA strip or an Action constraint,
and the Action has a single slot, and that slot has a suitable ID
type, it is chosen.
This last step is what I was referring to with "Where these two goals
did not converge, reliability and understandability for users was
prioritised." For regular Action assignments (like via the Action
selectors in the Properties editor) this rule doesn't apply, even though
with legacy Actions the final state ("it is animated by this Action")
differs from the final state with slotted Actions ("it has no slot so is
not animated"). This is done to support the following workflow:
- Create an Action by animating Cube.
- In order to animate Suzanne with that same Action, assign the Action
to Suzanne.
- Start keying Suzanne. This auto-creates and auto-assigns a new slot
for Suzanne.
If rule 4. above would apply in this case, the 2nd step would
automatically select the Cube slot for Suzanne as well, which would
immediately overwrite Suzanne's properties with the Cube animation.
Technically, this commit:
- removes the `WITH_ANIM_BAKLAVA` build flag,
- removes the `use_animation_baklava` experimental flag in preferences,
- updates the code to properly deal with the fact that empty Actions are
now always considered slotted/layered Actions (instead of that relying
on the user preference).
Note that 'slotted Actions' and 'layered Actions' are the exact same
thing, just focusing on different aspects (slot & layers) of the new
data model.
The "Baklava phase 1" assumptions are still asserted. This means that:
- an Action can have zero or one layer,
- that layer can have zero or one strip,
- that strip must be of type 'keyframe' and be infinite with zero
offset.
The code to handle legacy Actions is NOT removed in this commit. It will
be removed later. For now it's likely better to keep it around as
reference to the old behaviour in order to aid in some inevitable
bugfixing.
Ref: #120406
`BKE_animdata_fix_paths_remove()` now calls into the new function
`animrig::legacy::action_fcurves_remove()`, which works for both
legacy and slotted Actions.
Also I updated the documentation of the BKE function so that it's clear
what it's actually doing.
No functional changes for legacy Actions.
Ref: #123424
Pull Request: https://projects.blender.org/blender/blender/pulls/128252
Reduce cognitive complexity of `BKE_animdata_fix_paths_remove()` by
returning early, returning literals (instead of variables) when the
returned value is known, and just calling `BKE_animdata_from_id()` instead
of re-implementing it here.
No functional changes.
When assigning an Action with the new API:
- check the Actions ID type (if it is a legacy Action), and
- check whether the ID is in NLA tweak mode.
This means that action assignment can fail, so the
`animrig::assign_action()` and `animrig::unassign_action()` functions
now return a `[[nodiscard]] bool`.
Part of `generic_assign_action()` has now also been shielded with an
`#ifdef WITH_ANIM_BAKLAVA` just to be sure.
This also includes a change in `BKE_animdata_free()`. That function now
first exits NLA tweak mode (if enabled) before freeing the Actions. This
makes it possible to simply un-assign the assigned Action, as all the
NLA tweakmode stuff has already been taken care of by the responsible
function.
Pull Request: https://projects.blender.org/blender/blender/pulls/128199
Previously we were using a bespoke hodgepodge of
`Action::is_action_legacy()` and `Action::is_action_layered()`,
sometimes in combination with checking for the Baklava feature flag,
when what we really meant is "Should this action be treated as legacy
or not?"
This commit changes the places where that's semantically what we meant
to use `action_treat_as_legacy()`. Some of those places were already
correct, using a compound conditional, but some of them weren't, and
thus were not always branching correctly. For those latter cases,
this commit is a bug fix.
Importantly, not all uses of bare `Action::is_action_legacy()` or
`Action::is_action_layered()` are semantically incorrect: there are many
places where that is the right thing to do. This commit takes care not
to touch those places.
Pull Request: https://projects.blender.org/blender/blender/pulls/128174
This bug was introduced in #126561. The issue was that the UI action
selectors no longer ensured that animdata existed before attempting
to assign an action, which would then cause the assignment to fail.
However, this was only the case in Blender builds without experimental
features, since the new Baklava code paths would otherwise be taken,
which *do* handle this correctly.
This fixes the issue by ensuring animdata in the non-experimental code
paths again.
Pull Request: https://projects.blender.org/blender/blender/pulls/128083
Because we're moving to layered actions, which don't store their
fcurves in a list base, we need to update the places that assume the old
listbase-based structure.
This commit addresses the low-hanging fruit where code was previously
using the `LISTBASE_FOREACH` macro on a listbase of fcurves and it was
fairly obvious how to correctly update the code with minimal changes.
Other cases that either weren't immediately obvious or required
non-trivial code changes (or both) have been left for future PRs.
Additionally, uses of the list base that didn't use `LISTBASE_FOREACH`
were not investigated as part of this PR, whether trivial to update or
not.
Ref: #123424
Pull Request: https://projects.blender.org/blender/blender/pulls/127920
Instead of assigning Actions by direct pointer manipulation (and the
corresponding juggling of user counts), call `animrig::assign_action()`
and `animrig::unassign_action()`.
These functions not only correctly handle user counts, but also ensure
that slot assignments & user tracking works. The former always happens,
the latter only when building with experimental features enabled.
Because (un)assigning slotted Actions need the animated ID (instead of
just the `AnimData *`), more functions now require an `OwnedAnimData`.
Note that there is still some user count juggling. This is caused by
`BKE_id_new()`, and by extension `BKE_action_add`, returning an ID with
user count = 1, even though that ID is not yet used. A todo task #128017
has been made to change `BKE_action_add()` so that the Action it returns
can be directly fed into `animrig::assign_action()`.
This PR updates the following areas:
- Creating a node group by grouping animated nodes, as this has to move
the animation data. This PR just handles the assignment of a new
Action.
- Temporary Action creation for ungrouping node groups.
- Versioning of pre-2.5 animation data.
No functional changes.
Ref: #123424
Pull Request: https://projects.blender.org/blender/blender/pulls/128026
Instead of simply reassigning the `adt->action` and `adt->tmpact` pointers,
the code now uses the `animrig::assign_action()` and `assign_tmpaction()`.
This way the slot user maps should be properly updated.
Pull Request: https://projects.blender.org/blender/blender/pulls/128030
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
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
Use snake style naming for all the kernel nodes functions.
Omit kernel prefix in the names since of the using namespace.
Use full forms of the terms
('iter' -> 'iterator', 'ntree' -> 'node_tree', 'rem' -> 'remove', ...).
Pull Request: https://projects.blender.org/blender/blender/pulls/126416
Since the code only does anything if both substrings are found, implement
an early-out if either of them isn't found.
This seems like a micro-optimization at first, but since the current node
socket versioning requires looping over all AnimData in the file, this adds
up to e.g. 1.9sec saved when loading the Spring benchmark file.
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
Rename 'Binding' to 'Slot'. The old term was causing all kind of
confusion, and 'slot' was considered to be a better term for the
intended functionality.
This commit breaks existing blend files that were using the new layered
Action for their animation. The animation data will be lost due to the
rename, as there is no versioning code or DNA renaming logic. At this
time the new system is still marked as experimental, so shouldn't be
used for anything serious anyway.
Pull Request: https://projects.blender.org/blender/blender/pulls/124170
Keep track of which IDs are animated by which Action Binding. This will
be necessary for display in the Action editor, where animation data that
is unrelated to the active object can be shown (when "show all bindings"
is on).
Note: animation evaluation will not be using this cache, at least not in
the near future. Potentially when we introduce animation-level
constraints this will change, but that's for the future.
The user cache isn't actually used in this commit. It will be used soon
in !122672.
Pull Request: https://projects.blender.org/blender/blender/pulls/123187
Pull Request: https://projects.blender.org/blender/blender/pulls/123187
Move all header file into namespace.
Unnecessary namespaces was removed from implementations file.
Part of forward declarations in header was moved in the top part
of file just to do not have a lot of separate namespaces.
Pull Request: https://projects.blender.org/blender/blender/pulls/121637
The new/experimental, layered `Animation` data-block is merged with the
existing `bAction` data-block.
The `Animation` data-block is considerably newer than `bAction`, so the
supporting code that was written for it is also more modern. When moving
that code into `bAction`, I chose to keep the modernity where possible,
and thus some of the old code has been updated as well. Things like
preferring references over pointers.
The `Animation` data-block is now gone from DNA, the main database, etc.
As this was still an experimental feature, there is no versioning code
to convert any of that to Actions.
The DNA struct `bAction` now has a C++ wrapper `animrig::Action`, that
can be obtained via `some_action->wrap()`.
`animrig::Action` has functions `is_empty()`, `is_action_legacy()`, and
`is_action_layered()`. They **all** return `true` when the Action is
empty, as in that case none of the data that makes an action either
'legacy' or 'layered' is there.
The 'animation filtering' code (for showing things in the dope sheet,
graph editor, etc) that I wrote for `Animation` is intentionally kept
around. These types now target 'layered actions' and the
already-existing ones 'legacy actions'. A future PR may merge these two
together, but given how much work it was to add something new there, I'd
rather wait until the dust has settled on this commit.
There are plenty of variables (and some comments) named `anim` or
`animation` that now are of type `animrig::Action`. I haven't renamed
them all, to keep the noise level low in this commit (it's already big
enough). This can be done in a followup, non-functional PR.
Related task: #121355
Pull Request: https://projects.blender.org/blender/blender/pulls/121357
Advanced ID copying code can now take a `new_owner_id` ID pointer parameter,
and use it to set the relevant 'loopback' pointer to its owner ID by the
copy code itself.
Besides avoiding the need for all code copying embedded IDs to set the
loopback pointer themselves, this also means that `lib_id` copying code
itself does not need to use `IDWALK_IGNORE_MISSING_OWNER_ID` anymore.
This change is not expected to have any effect in current codebase.
This makes the read and write API functions match more closely, and adds
asserts to check that the data size is as expected.
There are still a few places remaining that use BLO_read_data_address
and similar generic functions, these should eventually be replaced as well.
Pull Request: https://projects.blender.org/blender/blender/pulls/120994
Fix linking & library-overriding with NLA Tweak Mode enabled. This is a
two-pronged approach:
- When linking an animated ID from a library file, and it happens to be
in NLA Tweak Mode, it is forced out of tweak mode. This ensures that
the correct Action is loaded, and that all the NLA flags are set
correctly to display the NLA animation (instead of only the tweaked
strip).
- For library overrides there is now a post-process step that runs after
all 'apply' functions have been run. This is necessary to ensure that
all the flags and pointers that NLA Tweak Mode depends on are actually
set correctly and consistently.
This also adds one utility function `BKE_nla_debug_print_flags()` that
is by now unused. It was very useful in debugging this, though, and I
think it'll be useful in the future as well.
Design task: #120573
Pull Request: https://projects.blender.org/blender/blender/pulls/120830
`BKE_animdata_fix_paths_rename` would tag the owner ID itself
(`ID_RECALC_SYNC_TO_EVAL`) upon renaming when a corresponding fcurve was
found/fixed, however the action itself wasnt tagged. "The action is an
own datablock, meaning, changes to f-curves need to copy those changes
to all evaluated versions of the action datablock" (wording from
4045730d58).
(this is also the reason the action would "fix" itself after entering
tweakmode on it in the NLA, since that ripples down to
`ANIM_list_elem_update` -- which does the tagging on the action then).
Part of #104055
Pull Request: https://projects.blender.org/blender/blender/pulls/120292
Expand the `AnimData` struct with an `Animation *` + an
`binding_stable_index` field, and properly handle those relations.
This also adds functionality for actually pointing animated IDs to
`Animation` data-blocks, and automatically hooking up the relevant
`Binding`.
The Depsgraph code is extended to take these new relations into account,
but doesn't trigger any animation evaluation yet.
For more info, see #113594.
Pull Request: https://projects.blender.org/blender/blender/pulls/118677
Introduce new DNA for the `Animation` data-block and its sub-data.
This includes the blenkernel code for reading & writing to blend files,
and for memory management (freeing, duplicating). Minimal C++ wrappers
are included, with just the functionality needed for blenkernel to do
its job.
The Outliner code is extended so that it knows about the new data-type,
nothing more.
For more info, see issue #113594.
Pull Request: https://projects.blender.org/blender/blender/pulls/119077
Seems to work OK in basic cases, but needs more work when copying
outside of Main at least.
Note: There is no behavioral changes expected from this commit.
Note that there are at least two known usecases for this change:
* Liboverrides, as with recursive resync and proxies conversion it
often ends up creating 'virtual' linked data that does not actually
exists in the library blend files.
* Complex versionning code (`do_versions_after_setup`) when it needs
to create new IDs (currently handling linked data that way is just not
supported!).
Implements #107847.
Split `BKE_fcurve_blend_write(writer, listbase)` into two functions:
- `BKE_fcurve_blend_write_data(writer, fcurve)` for the data of a single
F-Curve, and
- `BKE_fcurve_blend_write_listbase(writer, listbase)` for writing a list
of F-Curves.
And the same for `BKE_fcurve_blend_read_data()`.
This is necessary for the upcoming Animation data-block, which will
store F-Curves as arrays instead of `ListBase`s.
No functional changes.
The depsgraph CoW mechanism is a bit of a misnomer. It creates an
evaluated copy for data-blocks regardless of whether the copy will
actually be written to. The point is to have physical separation between
original and evaluated data. This is in contrast to the commonly used
performance improvement of keeping a user count and copying data
implicitly when it needs to be changed. In Blender code we call this
"implicit sharing" instead. Importantly, the dependency graph has no
idea about the _actual_ CoW behavior in Blender.
Renaming this functionality in the despgraph removes some of the
confusion that comes up when talking about this, and will hopefully
make the depsgraph less confusing to understand initially too. Wording
like "the evaluated copy" (as opposed to the original data-block) has
also become common anyway.
Pull Request: https://projects.blender.org/blender/blender/pulls/118338
There are a couple of functions that create rna pointers. For example
`RNA_main_pointer_create` and `RNA_pointer_create`. Currently, those
take an output parameter `r_ptr` as last argument. This patch changes
it so that the functions actually return a` PointerRNA` instead of using
the output parameters.
This has a few benefits:
* Output parameters should only be used when there is an actual benefit.
Otherwise, one should default to returning the value.
* It's simpler to use the API in the large majority of cases (note that this
patch reduces the number of lines of code).
* It allows the `PointerRNA` to be const on the call-site, if that is desired.
No performance regression has been measured in production files.
If one of these functions happened to be called in a hot loop where
there is a regression, the solution should be to use an inline function
there which allows the compiler to optimize it even better.
Pull Request: https://projects.blender.org/blender/blender/pulls/111976
The `lib_link` callback cannot always be fully replaced/removed, as in
some case it is also doing some validation checks, or data editing based
on the result of lib_linking internal ID pointers.
The callback has been renamed for that purpose, from `read_lib` to
`read_after_liblink`. It is now called after all ID pointers have been
fully lib-linked for the current ID, but still before the call to
`do_versions_after_linking`.
This change should not have any behavioral effect. Although in theory
the side-effect of this commit (to split lib linking itself, and the
validation/further processing code) into two completely separated steps
could have some effects, in practice none are expected, and tests did
not show any changes in behavior either..
Part of implementing #105134: Removal of readfile's lib_link & expand code.