We've had a bunch of inconsistency between `channel_bag` and `channelbag` in the
code base. After discussion with @dr.sybren, we decided to standardize on
`channelbag` and also rename the camelcase `ChannelBag` to `Channelbag` to be
consistent with that.
This PR implements those changes.
Note that the reason we standardized on `channelbag` rather than `channel_bag`
is because it makes things clearer when stringing multiple terms together in
type and function names. For example, in `channelbag_fcurves_move()` it makes
it clear that `channelbag` describes one thing, rather than `channel` and `bag`
being two separate things.
No functional changes intended.
Pull Request: https://projects.blender.org/blender/blender/pulls/130988
`Action.slots.new()` in the Python API previously took either an ID or nothing
as a parameter. In the former case it would create a slot with the appropriate
`id_root` and name for that ID. In the latter case it would create a default
slot with an unspecified `id_root` and default name.
This had several issues:
1. You couldn't create a slot with a specific `id_root` without already having
an ID of that type. In theory this isn't a problem, but in practice in larger
scripts/addons you don't necessarily have such an ID on hand at the call
site.
2. You couldn't directly create a slot with a desired name without an existing
ID with that name. This isn't so important, since you can always just set the
name afterwards. But it's a bit annoying.
3. Most other `new()` APIs in Blender *require* you to specify the name of the
item being created. So calling this with no parameters was violating that
norm.
4. Ideally, we want to eliminate unspecified `id_root`s, since they cause other
weirdness in the API such as slot identifiers changing upon slot assignment.
To resolve these issues, and just generally to make the API more
straightforward, this PR changes `slots.new()` to take two required parameters:
an ID type and a name. For example:
`slots.new(id_type='CAMERA', name="My Camera Data Slot")`.
This fully specifies everything needed for the slot identifier upon creation,
and doesn't require any outside data items to create a slot with the desired
type and name.
In the future if we decide we still want a `for_id`-style slot creation API, we
can reintroduce it as a separate function.
Ref: #130892
Pull Request: https://projects.blender.org/blender/blender/pulls/130970
`AnimData`, NLA strips, and action constraints all have an `action_slot_name`
field in RNA. The purpose of this field is to store the identifier of the most
recently assigned slot, so that it can be used for auto-assignment when later
assigning different actions.
However, this field name is misleading in two ways:
1. In accordance with #130740, it's actually the slot *identifier*, not name.
2. It could be mistaken as a way to rename the currently assigned slot, which it
is not.
To resolve both of those issues, we're renaming the field to
`last_slot_identifier`, which better communicates its actual nature.
As a bonus, this also ends up decluttering Python autocomplete when looking
for things related to action_slot.
Ref: #130892
Pull Request: https://projects.blender.org/blender/blender/pulls/130911
This PR renames `ActionSlot::name` to `ActionSlot::identifier` for both DNA and
RNA, and also renames related methods, functions, constants, and comments.
The purpose of this rename is to help make it clear that this is not a "name"
in the traditional sense, but rather is a composite of the slot name + id type
for lookup purposes.
Ref: #130892
Pull Request: https://projects.blender.org/blender/blender/pulls/130740
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
This implements versioning code to go from legacy to layered action.
The versioning is only triggered when the experimental flag for
Multi-Slot actions is enabled.
All the actions are converted in place, which should be fine because
of backwards and forwards compatibility with layered actions.
Pull Request: https://projects.blender.org/blender/blender/pulls/127842
The `Action.groups` RNA functions now work with layered Actions as well.
They just expose / operate on the groups of the channelbag that belongs
to the first slot of the Action.
Pull Request: https://projects.blender.org/blender/blender/pulls/127241
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
Add an Action Slot selector to the Action editor's header, next to the
Action selector. The selector shows all slots in the action that are
suitable for animating objects (as the Action editor itself is limited
to showing the Action of the active object).
This also considerably simplifies the 'Animation Debug' panel, as some
debugging code has been removed, as well as the display of any animation
layers. The latter can be reintroduced (if necessary) when multi-layer
animation support is added. Most importantly, it removes the
WindowManager property that was used as a hack to assign layered Actions
to objects.
API change: the RNA property `AnimData.slot` is now a pointer property
that reflects the actual slot (it used to be an enum property).
Some small changes to the UI code were necessary to make the selector
show the slot's display name (and not their internal name).
Pull Request: https://projects.blender.org/blender/blender/pulls/125416
These functions can now be called on layered Actions:
- `action.fcurves.new(data_path, array_index)`
- `action.fcurves.find(data_path, array_index)`
- `action.fcurves.remove(fcurve)`
- `action.fcurves.clear()`
These will operate on the first keyframe strip (searching layers bottom
to top), and then its channelbag for the first slot.
If necessary, `fcurves.new()` will create the layer, keyframe strip,
channelbag, and slot.
This backward compatibility layer only kicks in if either of these is
true:
- The Action is empty AND the experimental flag is enabled, or
- The Action already has a layer or a slot (i.e. is already considered
'layered').
If none of these conditions hold, `action.fcurves` just gives access to
the legacy data.
Ref: #124714
Pull Request: https://projects.blender.org/blender/blender/pulls/124996
Add F-Curve management functions on ChannelBags
(`channelbag.fcurves.xxx`) that are very similar to the legacy Action
functions `Action.fcurves.xxx`.
```python
channelbag = strip.channelbags.new(slot)
fcurve = channelbag.fcurves.new("rotation_quaternion", index=1)
assert channelbag.fcurves[0] == fcurve
channelbag.fcurves.remove(fcurve)
channelbag.fcurves.clear()
```
Pull Request: https://projects.blender.org/blender/blender/pulls/124987
RNA API for creating & removing channelbags, as well as a path function
to construct RNA paths for channelbags.
```python
action = bpy.data.actions.new('TestAction')
slot = action.slots.new()
slot.name = 'OBTest'
layer = action.layers.new(name="Layer")
strip = layer.strips.new(type='KEYFRAME')
# New in this commit:
channelbag = strip.channelbags.new(slot)
strip.channelbags.remove(channelbag)
```
Pull Request: https://projects.blender.org/blender/blender/pulls/124793
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
Add guards to the RNA code to prevent the creation of legacy data on a
layered Action, and vice versa.
On a legacy Action, it is now impossible to create new layers or bindings.
On a layered Action, it's now impossible to create legacy F-Curves or
groups.
Refactor: Anim: rename bl_animation_id.py to bl_animation_action.py
The `Animation` datablock is no more, and this file tests `Action`.
No functional changes.
Pull Request: https://projects.blender.org/blender/blender/pulls/122483