owned this note
owned this note
Published
Linked with GitHub
# State of Blender's Keyframing Code + Where We Want To Go
## Current State
Callgraph diagram of Blender's keyframing code (incomplete):
```mermaid
flowchart TD
entry_points{"Entry Points (rna function, ui functions, \n operators, baking functions, etc.)"}
insert_keyframe["<b>insert_keyframe()</b> -- animrig/keyframing.cc"]
insert_key_rna["<b>insert_key_rna()</b> -- animrig/keyframing.cc"]
insert_key_action["<b>insert_key_action()</b> -- animrig/keyframing.cc"]
insert_keyframe_value["static <b>insert_keyframe_value()</b> -- animrig/keyframing.cc"]
insert_keyframe_fcurve_value["static <b>insert_keyframe_fcurve_value()</b> -- animrig/keyframing.cc"]
insert_keyframe_direct["<b>insert_keyframe_direct()</b> -- animrig/keyframing.cc"]
ANIM_apply_keyingset["<b>ANIM_apply_keyingset()</b> -- editors/animation/keyingsets.cc"]
insert_key_to_keying_set_path["static <b>insert_key_to_keying_set_path</b> -- editors/animation/keyingsets.cc"]
autokeyframe_object["<b>autokeyframe_object()</b> -- animrig/intern/keyframing_auto.cc"]
autokeyframe_pose_channel["<b>autokeyframe_pose_channel()</b> -- animrig/intern/keyframing_auto.cc"]
autokeyframe_property["<b>autokeyframe_property()</b> -- animrig/intern/keyframing_auto.cc"]
insert_key["static <b>insert_key()</b> -- editors/animation/keyframing.cc"]
insert_key_with_keyingset["static <b>insert_key_with_keyingset()</b> -- editors/animation/keyframing.cc"]
insert_vert_fcurve["<b>insert_vert_fcurve()</b> -- animrig/intern/fcurve.cc"]
entry_points --> autokeyframe_object
entry_points --> autokeyframe_pose_channel
entry_points --> autokeyframe_property
entry_points --> insert_key
entry_points --> insert_key_with_keyingset
entry_points --> insert_keyframe_direct
entry_points --> insert_vert_fcurve
insert_key_with_keyingset --> ANIM_apply_keyingset
ANIM_apply_keyingset --> insert_key_to_keying_set_path
insert_key_to_keying_set_path --> insert_keyframe
autokeyframe_property --> insert_keyframe
autokeyframe_property --> insert_keyframe_direct
autokeyframe_object --> insert_key_rna
autokeyframe_object --> ANIM_apply_keyingset
autokeyframe_pose_channel --> insert_key_rna
autokeyframe_pose_channel --> ANIM_apply_keyingset
insert_key --> insert_key_rna
insert_key_rna --> insert_key_action
insert_key_action --> insert_keyframe_fcurve_value
insert_keyframe --> insert_keyframe_fcurve_value
insert_keyframe_fcurve_value --> insert_keyframe_value
insert_keyframe_direct --> insert_keyframe_value
insert_keyframe_value --> insert_vert_fcurve
```
## Where We Want to End Up...? (WIP)
Note: rectangles represent a single specific function, diamonds represent a broad collection of functions or a module.
```mermaid
flowchart TD
unknown{"???"}
animation_editors{"Animation editor keyframe insertion: \ngraph editor, dope sheet, driver editor, etc."}
user_level_keying{"3D viewport etc. keyframe insertion: \nmanual, auto, buttons, keying sets"}
key_rna_paths["Key a set of RNA paths. Dispatches to the appropriate keying code for each RNA path."]
key_action_legacy["Keyframe legacy action"]
key_action_layered["Keyframe layered action"]
key_direct_property["Keyframe properties that don't use the action system. E.g. NLA properties."]
shared_keyframing_function["Shared FCurve keyframing function that handles user-level flags that are shared among the above callers."]
baking{"Baking code"}
fcurve_manipulation{"Fcurve manipulation tools \n(e.g. butterworth filter)"}
low_level{"Low-level FCurve functions"}
animation_editors --> unknown
user_level_keying --> key_rna_paths
key_rna_paths --> key_action_legacy
key_rna_paths --> key_action_layered
key_rna_paths --> key_direct_property
key_action_legacy --> shared_keyframing_function
key_action_layered --> shared_keyframing_function
key_direct_property --> shared_keyframing_function
baking --> low_level
fcurve_manipulation --> low_level
shared_keyframing_function --> low_level
```
### Questions
- How do the animation editors fit into this? Especially when they aren't editing actions (e.g. the drivers editor, etc.).
# Initial Refactors
1. Merge `insert_keyframe()` and `insert_key_rna()` into a single function.
# Discussion from blender.chat
**Nathan Vegdahl**
@ChristophLendenfeld I'm looking into what it would take to merge insert_keyframe() and insert_key_rna() as we had discussed before. Making a thread here to discuss.
It looks to me like there are two main interface differences between them:
- insert_keyframe() only keys a single property/path at a time, whereas insert_key_rna() takes a list.
- insert_keyframe() additionally takes an action group name, whereas insert_key_rna() does not.
Other than that, as far as I can tell they're effectively identical in their interfaces. Some of the parameters are derived in one but explicitly passed in the other, etc. But fundamentally they're passed the same total information other than those differences.
For difference 1: I was initially thinking this would mean we'd still want two functions: one for keying multiple properties and one for keying a single property. However, since insert_key_rna() takes a Span of paths, it turns out it's perfectly safe (confirmed by JacquesLucke) to just pass it an initializer list with a single item. Which means it's just about as convenient to call with a single item as an array of items.
Example here (the std::move isn't necessary, it just prevents an unnecessary copy):
https://projects.blender.org/blender/blender/commit/1c2501d7d0d0b72574827014b121021a03ea98a3
So I think we can just stick with the Span-based interface, and avoid a single-item-only function altogether.
For difference 2: I'm less sure, and will need to do some more investigation about how it's used and whether it's actually necessary or not. If it's not actually needed, then that makes things easy. And if it's used in a fairly trivial way, we might be able to just use a simple wrapper function. But otherwise it might be a little more hairy.
**ChristophLendenfeld**
for 2. It's tricky to remove, since keying sets have the ability to define a group so they need a way to pass that in
but yes I agree they should be merged
seems like difference 1 is no longer an issue if I read this right?
**Nathan Vegdahl**
Correct, I don't think difference 1 is an issue at all. Thanks to the awesomeness of blender::Span.
And now that I've said it out loud, I think difference 2 shouldn't be too much of a problem either. We don't need a group per path for the way it's actually used, so it could just be a single group despite the function taking a span of paths. And we could make it an optional argument, I think.
We might find a way to split it out better later, but I think that would be a reasonable initial refactor, at least.
**ChristophLendenfeld**
ah yes you only need a single group, and I think it is reasonable to add that as an optional parameter for now. I say for now because defining how an fcurve is grouped ON the fcurve rubs me the wrong way. That's a GUI setting at best.
actually I am wondering if we need to pass the group in the keyframe insertion code or if keying sets can just deal with that themselves. So it becomes a 2 step process.
1. Insert keys
2. if the curve is new, set the group
**Nathan Vegdahl**
Yeah, that may well be the way to go, ultimately. dr.sybren also has some ideas about fcurve groups that I think are good. But as a first step, I think just making it an optional argument at least gets us closer to where we want to be. And we can change that later.
Thanks for the discussion! This was super helpful. 🙂