Anim: add functions for asserting Project Baklava phase-1 invariants

This is implemented as an overloaded function,
`assert_baklava_phase_1_invariants()`, with variants for `Action`, `Layer`, and
`Strip`.

The invariants asserted are those that are specific to phase 1 and which will
later be lifted as more features (such as animation layers, additional strip
types, etc.) are added. The intention is for this to serve as a kind of todo
marker for later phases *and* to help ensure that the phase-1 invariants
currently hold at runtime.

In addition to adding the overloaded function itself, this commit also uses it
in a couple of places in the keyframing code.  Upcoming work on the keyframing
code will be using it more.

This is based on a discussion with @dr.sybren.

Pull Request: https://projects.blender.org/blender/blender/pulls/123830
This commit is contained in:
Nathan Vegdahl
2024-06-28 11:06:34 +02:00
committed by Nathan Vegdahl
parent cae1faec12
commit c83727f0bd
3 changed files with 66 additions and 12 deletions

View File

@@ -672,6 +672,37 @@ FCurve *action_fcurve_ensure(Main *bmain,
*/
FCurve *action_fcurve_find(bAction *act, FCurveDescriptor fcurve_descriptor);
/**
* Assert the invariants of Project Baklava phase 1.
*
* For an action the invariants are that it:
* - Is a legacy action.
* - OR has zero layers.
* - OR has a single layer that adheres to the phase 1 invariants for layers.
*
* For a layer the invariants are that it:
* - Has zero strips.
* - OR has a single strip that adheres to the phase 1 invariants for strips.
*
* For a strip the invariants are that it:
* - Is a keyframe strip.
* - AND is infinite.
* - AND has no time offset (i.e. aligns with scene time).
*
* This simultaneously serves as a todo marker for later phases of Project
* Baklava and ensures that the phase-1 invariants hold at runtime.
*
* TODO: these functions should be changed to assert fewer and fewer assumptions
* as we progress through the phases of Project Baklava and more and more of the
* new animation system is implemented. Finally, they should be removed entirely
* when the full system is completely implemented.
*/
void assert_baklava_phase_1_invariants(const Action &action);
/** \copydoc assert_baklava_phase_1_invariants(const Action &) */
void assert_baklava_phase_1_invariants(const Layer &layer);
/** \copydoc assert_baklava_phase_1_invariants(const Action &) */
void assert_baklava_phase_1_invariants(const Strip &strip);
} // namespace blender::animrig
/* Wrap functions for the DNA structs. */

View File

@@ -434,15 +434,11 @@ bool Action::is_binding_animated(const binding_handle_t binding_handle) const
Layer *Action::get_layer_for_keyframing()
{
/* TODO: handle multiple layers. */
assert_baklava_phase_1_invariants(*this);
if (this->layers().is_empty()) {
return nullptr;
}
if (this->layers().size() > 1) {
std::fprintf(stderr,
"Action '%s' has multiple layers, which isn't handled by keyframing code yet.",
this->id.name);
}
return this->layer(0);
}
@@ -1238,4 +1234,35 @@ FCurve *action_fcurve_ensure(Main *bmain,
return fcu;
}
void assert_baklava_phase_1_invariants(const Action &action)
{
if (action.is_action_legacy()) {
return;
}
if (action.layers().is_empty()) {
return;
}
BLI_assert(action.layers().size() == 1);
assert_baklava_phase_1_invariants(*action.layer(0));
}
void assert_baklava_phase_1_invariants(const Layer &layer)
{
if (layer.strips().is_empty()) {
return;
}
BLI_assert(layer.strips().size() == 1);
assert_baklava_phase_1_invariants(*layer.strip(0));
}
void assert_baklava_phase_1_invariants(const Strip &strip)
{
BLI_assert(strip.type() == Strip::Type::Keyframe);
BLI_assert(strip.is_infinite());
BLI_assert(strip.frame_offset == 0.0);
}
} // namespace blender::animrig

View File

@@ -862,14 +862,10 @@ static SingleKeyingResult insert_key_layer(Layer &layer,
const KeyframeSettings &key_settings,
const eInsertKeyFlags insert_key_flags)
{
/* TODO: we currently assume there will always be precisely one strip, which
* is infinite and has no time offset. This will not hold true in the future
* when we add support for multiple strips. */
assert_baklava_phase_1_invariants(layer);
BLI_assert(layer.strips().size() == 1);
Strip *strip = layer.strip(0);
BLI_assert(strip->is_infinite());
BLI_assert(strip->frame_offset == 0.0);
Strip *strip = layer.strip(0);
return strip->as<KeyframeStrip>().keyframe_insert(binding,
{rna_path, key_data.array_index, prop_subtype},
key_data.position,