From 9155f2336ba4a1dbdc7f0112ad73d1116619bb41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 23 Jul 2024 08:10:19 +0200 Subject: [PATCH] Anim: rebuild depsgraph relations when creating a new F-Curve When a new F-Curve is created on a layered Action, tag the dependency graph for rebuilding its relationships. This is necessary as the F-Curve may be animating a depsgraph component that was previously not animated, and thus that relation needs to be constructed. This was already in place for legacy Actions, and simply overlooked for the new layered ones. Pull Request: https://projects.blender.org/blender/blender/pulls/125236 --- source/blender/animrig/ANIM_action.hh | 34 ++++++++++++++--- source/blender/animrig/intern/action.cc | 26 +++++++++---- source/blender/animrig/intern/action_test.cc | 19 ++++++---- .../blender/animrig/intern/evaluation_test.cc | 38 +++++++++---------- source/blender/animrig/intern/keyframing.cc | 15 +++++--- .../editors/animation/anim_filter_test.cc | 18 +++++---- source/blender/editors/animation/anim_ops.cc | 1 + source/blender/makesrna/intern/rna_action.cc | 7 ++-- .../blender/makesrna/intern/rna_animation.cc | 1 + 9 files changed, 103 insertions(+), 56 deletions(-) diff --git a/source/blender/animrig/ANIM_action.hh b/source/blender/animrig/ANIM_action.hh index 492442f9a98..96c9117be97 100644 --- a/source/blender/animrig/ANIM_action.hh +++ b/source/blender/animrig/ANIM_action.hh @@ -675,7 +675,8 @@ class KeyframeStrip : public ::KeyframeActionStrip { /** Return the channelbag's index, or -1 if there is none for this slot handle. */ int64_t find_channelbag_index(const ChannelBag &channelbag) const; - SingleKeyingResult keyframe_insert(const Slot &slot, + SingleKeyingResult keyframe_insert(Main *bmain, + const Slot &slot, FCurveDescriptor fcurve_descriptor, float2 time_value, const KeyframeSettings &settings, @@ -713,15 +714,27 @@ class ChannelBag : public ::ActionChannelBag { /** * Find an FCurve matching the fcurve descriptor, or create one if it doesn't * exist. + * + * \param bmain Used to tag the dependency graph(s) for relationship + * rebuilding. This is necessary when adding a new F-Curve, as a + * previously-unanimated depsgraph component may become animated now. Can be + * nullptr, in which case the tagging is skipped and is left as the + * responsibility of the caller. */ - FCurve &fcurve_ensure(FCurveDescriptor fcurve_descriptor); + FCurve &fcurve_ensure(Main *bmain, FCurveDescriptor fcurve_descriptor); /** * Create an F-Curve, but only if it doesn't exist yet in this ChannelBag. * * \return the F-Curve it it was created, or nullptr if it already existed. + * + * \param bmain Used to tag the dependency graph(s) for relationship + * rebuilding. This is necessary when adding a new F-Curve, as a + * previously-unanimated depsgraph component may become animated now. Can be + * nullptr, in which case the tagging is skipped and is left as the + * responsibility of the caller. */ - FCurve *fcurve_create_unique(FCurveDescriptor fcurve_descriptor); + FCurve *fcurve_create_unique(Main *bmain, FCurveDescriptor fcurve_descriptor); /** * Remove an F-Curve from the ChannelBag. @@ -742,9 +755,16 @@ class ChannelBag : public ::ActionChannelBag { /** * Create an F-Curve. * - * Assumes that there is no such F-Curve yet on this ChannelBag. + * Assumes that there is no such F-Curve yet on this ChannelBag. If it is + * uncertain whether this is the case, use `fcurve_create_unique()` instead. + * + * \param bmain Used to tag the dependency graph(s) for relationship + * rebuilding. This is necessary when adding a new F-Curve, as a + * previously-unanimated depsgraph component may become animated now. Can be + * nullptr, in which case the tagging is skipped and is left as the + * responsibility of the caller. */ - FCurve &fcurve_create(FCurveDescriptor fcurve_descriptor); + FCurve &fcurve_create(Main *bmain, FCurveDescriptor fcurve_descriptor); }; static_assert(sizeof(ChannelBag) == sizeof(::ActionChannelBag), "DNA struct and its C++ wrapper must have the same size"); @@ -848,6 +868,10 @@ Vector fcurves_all(Action &action); * nullptr for layered actions. See the comments in the implementation for more * details. * + * \note This function also ensures that dependency graph relationships are + * rebuilt. This is necessary when adding a new F-Curve, as a + * previously-unanimated depsgraph component may become animated now. + * * \param ptr: RNA pointer for the struct the fcurve is being looked up/created * for. For legacy actions this is optional and may be null. * diff --git a/source/blender/animrig/intern/action.cc b/source/blender/animrig/intern/action.cc index 3fd277b1388..466385139b0 100644 --- a/source/blender/animrig/intern/action.cc +++ b/source/blender/animrig/intern/action.cc @@ -1124,23 +1124,23 @@ FCurve *ChannelBag::fcurve_find(const FCurveDescriptor fcurve_descriptor) return animrig::fcurve_find(fcurves, fcurve_descriptor); } -FCurve &ChannelBag::fcurve_ensure(const FCurveDescriptor fcurve_descriptor) +FCurve &ChannelBag::fcurve_ensure(Main *bmain, const FCurveDescriptor fcurve_descriptor) { if (FCurve *existing_fcurve = this->fcurve_find(fcurve_descriptor)) { return *existing_fcurve; } - return this->fcurve_create(fcurve_descriptor); + return this->fcurve_create(bmain, fcurve_descriptor); } -FCurve *ChannelBag::fcurve_create_unique(FCurveDescriptor fcurve_descriptor) +FCurve *ChannelBag::fcurve_create_unique(Main *bmain, FCurveDescriptor fcurve_descriptor) { if (this->fcurve_find(fcurve_descriptor)) { return nullptr; } - return &this->fcurve_create(fcurve_descriptor); + return &this->fcurve_create(bmain, fcurve_descriptor); } -FCurve &ChannelBag::fcurve_create(FCurveDescriptor fcurve_descriptor) +FCurve &ChannelBag::fcurve_create(Main *bmain, FCurveDescriptor fcurve_descriptor) { FCurve *new_fcurve = create_fcurve_for_channel(fcurve_descriptor); @@ -1149,6 +1149,11 @@ FCurve &ChannelBag::fcurve_create(FCurveDescriptor fcurve_descriptor) } grow_array_and_append(&this->fcurve_array, &this->fcurve_array_num, new_fcurve); + + if (bmain) { + DEG_relations_tag_update(bmain); + } + return *new_fcurve; } @@ -1167,6 +1172,10 @@ bool ChannelBag::fcurve_remove(FCurve &fcurve_to_remove) dna::array::remove_index( &this->fcurve_array, &this->fcurve_array_num, nullptr, fcurve_index, fcurve_ptr_destructor); + /* As an optimisation, this function could call `DEG_relations_tag_update(bmain)` to prune any + * relationships that are now no longer necessary. This is not needed for correctness of the + * depsgraph evaluation results though. */ + return true; } @@ -1175,7 +1184,8 @@ void ChannelBag::fcurves_clear() dna::array::clear(&this->fcurve_array, &this->fcurve_array_num, nullptr, fcurve_ptr_destructor); } -SingleKeyingResult KeyframeStrip::keyframe_insert(const Slot &slot, +SingleKeyingResult KeyframeStrip::keyframe_insert(Main *bmain, + const Slot &slot, const FCurveDescriptor fcurve_descriptor, const float2 time_value, const KeyframeSettings &settings, @@ -1185,7 +1195,7 @@ SingleKeyingResult KeyframeStrip::keyframe_insert(const Slot &slot, * allow. */ FCurve *fcurve = nullptr; if (key_insertion_may_create_fcurve(insert_key_flags)) { - fcurve = &this->channelbag_for_slot_ensure(slot).fcurve_ensure(fcurve_descriptor); + fcurve = &this->channelbag_for_slot_ensure(slot).fcurve_ensure(bmain, fcurve_descriptor); } else { ChannelBag *channels = this->channelbag_for_slot(slot); @@ -1438,7 +1448,7 @@ FCurve *action_fcurve_ensure(Main *bmain, assert_baklava_phase_1_invariants(action); KeyframeStrip &strip = action.layer(0)->strip(0)->as(); - return &strip.channelbag_for_slot_ensure(slot).fcurve_ensure(fcurve_descriptor); + return &strip.channelbag_for_slot_ensure(slot).fcurve_ensure(bmain, fcurve_descriptor); } /* Try to find f-curve matching for this setting. diff --git a/source/blender/animrig/intern/action_test.cc b/source/blender/animrig/intern/action_test.cc index 20cd22af2ad..f3eacd286c2 100644 --- a/source/blender/animrig/intern/action_test.cc +++ b/source/blender/animrig/intern/action_test.cc @@ -144,9 +144,9 @@ TEST_F(ActionLayersTest, add_strip) /* Add some keys to check that also the strip data is freed correctly. */ const KeyframeSettings settings = get_keyframe_settings(false); Slot &slot = action->slot_add(); - strip.as().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings); + strip.as().keyframe_insert(bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings); another_strip.as().keyframe_insert( - slot, {"location", 0}, {1.0f, 47.0f}, settings); + bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings); } TEST_F(ActionLayersTest, remove_strip) @@ -159,9 +159,12 @@ TEST_F(ActionLayersTest, remove_strip) /* Add some keys to check that also the strip data is freed correctly. */ const KeyframeSettings settings = get_keyframe_settings(false); Slot &slot = action->slot_add(); - strip0.as().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings); - strip1.as().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings); - strip2.as().keyframe_insert(slot, {"location", 0}, {1.0f, 47.0f}, settings); + strip0.as().keyframe_insert( + bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings); + strip1.as().keyframe_insert( + bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings); + strip2.as().keyframe_insert( + bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings); EXPECT_TRUE(layer.strip_remove(strip1)); EXPECT_EQ(2, layer.strips().size()); @@ -555,7 +558,7 @@ TEST_F(ActionLayersTest, KeyframeStrip__keyframe_insert) const KeyframeSettings settings = get_keyframe_settings(false); SingleKeyingResult result_loc_a = key_strip.keyframe_insert( - slot, {"location", 0}, {1.0f, 47.0f}, settings); + bmain, slot, {"location", 0}, {1.0f, 47.0f}, settings); ASSERT_EQ(SingleKeyingResult::SUCCESS, result_loc_a) << "Expected keyframe insertion to be successful"; @@ -566,7 +569,7 @@ TEST_F(ActionLayersTest, KeyframeStrip__keyframe_insert) /* Insert a second key, should insert into the same FCurve as before. */ SingleKeyingResult result_loc_b = key_strip.keyframe_insert( - slot, {"location", 0}, {5.0f, 47.1f}, settings); + bmain, slot, {"location", 0}, {5.0f, 47.1f}, settings); EXPECT_EQ(SingleKeyingResult::SUCCESS, result_loc_b); ASSERT_EQ(1, channels->fcurves().size()) << "Expect insertion with the same (slot/rna " "path/array index) tuple to go into the same FCurve"; @@ -579,7 +582,7 @@ TEST_F(ActionLayersTest, KeyframeStrip__keyframe_insert) /* Insert another key for another property, should create another FCurve. */ SingleKeyingResult result_rot = key_strip.keyframe_insert( - slot, {"rotation_quaternion", 0}, {1.0f, 0.25f}, settings); + bmain, slot, {"rotation_quaternion", 0}, {1.0f, 0.25f}, settings); EXPECT_EQ(SingleKeyingResult::SUCCESS, result_rot); ASSERT_EQ(2, channels->fcurves().size()) << "Expected a second FCurve to be created."; EXPECT_EQ(2, channels->fcurves()[0]->totvert); diff --git a/source/blender/animrig/intern/evaluation_test.cc b/source/blender/animrig/intern/evaluation_test.cc index cd1e5d0ab9b..1eefc8568c6 100644 --- a/source/blender/animrig/intern/evaluation_test.cc +++ b/source/blender/animrig/intern/evaluation_test.cc @@ -149,10 +149,10 @@ TEST_F(AnimationEvaluationTest, evaluate_layer__keyframes) KeyframeStrip &key_strip = strip.as(); /* Set some keys. */ - key_strip.keyframe_insert(*slot, {"location", 0}, {1.0f, 47.1f}, settings); - key_strip.keyframe_insert(*slot, {"location", 0}, {5.0f, 47.5f}, settings); - key_strip.keyframe_insert(*slot, {"rotation_euler", 1}, {1.0f, 0.0f}, settings); - key_strip.keyframe_insert(*slot, {"rotation_euler", 1}, {5.0f, 3.14f}, settings); + key_strip.keyframe_insert(bmain, *slot, {"location", 0}, {1.0f, 47.1f}, settings); + key_strip.keyframe_insert(bmain, *slot, {"location", 0}, {5.0f, 47.5f}, settings); + key_strip.keyframe_insert(bmain, *slot, {"rotation_euler", 1}, {1.0f, 0.0f}, settings); + key_strip.keyframe_insert(bmain, *slot, {"rotation_euler", 1}, {5.0f, 3.14f}, settings); /* Set the animated properties to some values. These should not be overwritten * by the evaluation itself. */ @@ -189,9 +189,9 @@ TEST_F(AnimationEvaluationTest, strip_boundaries__single_strip) /* Set some keys. */ KeyframeStrip &key_strip = strip.as(); - key_strip.keyframe_insert(*slot, {"location", 0}, {1.0f, 47.0f}, settings); - key_strip.keyframe_insert(*slot, {"location", 0}, {5.0f, 327.0f}, settings); - key_strip.keyframe_insert(*slot, {"location", 0}, {10.0f, 48.0f}, settings); + key_strip.keyframe_insert(bmain, *slot, {"location", 0}, {1.0f, 47.0f}, settings); + key_strip.keyframe_insert(bmain, *slot, {"location", 0}, {5.0f, 327.0f}, settings); + key_strip.keyframe_insert(bmain, *slot, {"location", 0}, {10.0f, 48.0f}, settings); /* Evaluate the layer to see how it handles the boundaries + something in between. */ EXPECT_TRUE(test_evaluate_layer("location", 0, {1.0f, 47.0f})); @@ -213,15 +213,15 @@ TEST_F(AnimationEvaluationTest, strip_boundaries__nonoverlapping) /* Set some keys. */ { KeyframeStrip &key_strip1 = strip1.as(); - key_strip1.keyframe_insert(*slot, {"location", 0}, {1.0f, 47.0f}, settings); - key_strip1.keyframe_insert(*slot, {"location", 0}, {5.0f, 327.0f}, settings); - key_strip1.keyframe_insert(*slot, {"location", 0}, {10.0f, 48.0f}, settings); + key_strip1.keyframe_insert(bmain, *slot, {"location", 0}, {1.0f, 47.0f}, settings); + key_strip1.keyframe_insert(bmain, *slot, {"location", 0}, {5.0f, 327.0f}, settings); + key_strip1.keyframe_insert(bmain, *slot, {"location", 0}, {10.0f, 48.0f}, settings); } { KeyframeStrip &key_strip2 = strip2.as(); - key_strip2.keyframe_insert(*slot, {"location", 0}, {1.0f, 47.0f}, settings); - key_strip2.keyframe_insert(*slot, {"location", 0}, {5.0f, 327.0f}, settings); - key_strip2.keyframe_insert(*slot, {"location", 0}, {10.0f, 48.0f}, settings); + key_strip2.keyframe_insert(bmain, *slot, {"location", 0}, {1.0f, 47.0f}, settings); + key_strip2.keyframe_insert(bmain, *slot, {"location", 0}, {5.0f, 327.0f}, settings); + key_strip2.keyframe_insert(bmain, *slot, {"location", 0}, {10.0f, 48.0f}, settings); } /* Check Strip 1. */ @@ -253,15 +253,15 @@ TEST_F(AnimationEvaluationTest, strip_boundaries__overlapping_edge) /* Set some keys. */ { KeyframeStrip &key_strip1 = strip1.as(); - key_strip1.keyframe_insert(*slot, {"location", 0}, {1.0f, 47.0f}, settings); - key_strip1.keyframe_insert(*slot, {"location", 0}, {5.0f, 327.0f}, settings); - key_strip1.keyframe_insert(*slot, {"location", 0}, {10.0f, 48.0f}, settings); + key_strip1.keyframe_insert(bmain, *slot, {"location", 0}, {1.0f, 47.0f}, settings); + key_strip1.keyframe_insert(bmain, *slot, {"location", 0}, {5.0f, 327.0f}, settings); + key_strip1.keyframe_insert(bmain, *slot, {"location", 0}, {10.0f, 48.0f}, settings); } { KeyframeStrip &key_strip2 = strip2.as(); - key_strip2.keyframe_insert(*slot, {"location", 0}, {1.0f, 47.0f}, settings); - key_strip2.keyframe_insert(*slot, {"location", 0}, {5.0f, 327.0f}, settings); - key_strip2.keyframe_insert(*slot, {"location", 0}, {10.0f, 48.0f}, settings); + key_strip2.keyframe_insert(bmain, *slot, {"location", 0}, {1.0f, 47.0f}, settings); + key_strip2.keyframe_insert(bmain, *slot, {"location", 0}, {5.0f, 327.0f}, settings); + key_strip2.keyframe_insert(bmain, *slot, {"location", 0}, {10.0f, 48.0f}, settings); } /* Check Strip 1. */ diff --git a/source/blender/animrig/intern/keyframing.cc b/source/blender/animrig/intern/keyframing.cc index b7adf0b3e02..b984b6557dd 100644 --- a/source/blender/animrig/intern/keyframing.cc +++ b/source/blender/animrig/intern/keyframing.cc @@ -877,7 +877,8 @@ struct KeyInsertData { int array_index; }; -static SingleKeyingResult insert_key_layer(Layer &layer, +static SingleKeyingResult insert_key_layer(Main *bmain, + Layer &layer, const Slot &slot, const std::string &rna_path, const std::optional prop_subtype, @@ -889,14 +890,16 @@ static SingleKeyingResult insert_key_layer(Layer &layer, BLI_assert(layer.strips().size() == 1); Strip *strip = layer.strip(0); - return strip->as().keyframe_insert(slot, + return strip->as().keyframe_insert(bmain, + slot, {rna_path, key_data.array_index, prop_subtype}, key_data.position, key_settings, insert_key_flags); } -static CombinedKeyingResult insert_key_layered_action(Action &action, +static CombinedKeyingResult insert_key_layered_action(Main *bmain, + Action &action, PointerRNA *rna_pointer, const blender::Span rna_paths, const float scene_frame, @@ -955,7 +958,8 @@ static CombinedKeyingResult insert_key_layered_action(Action &action, } const KeyInsertData key_data = {{scene_frame, rna_values[property_index]}, property_index}; - const SingleKeyingResult result = insert_key_layer(*layer, + const SingleKeyingResult result = insert_key_layer(bmain, + *layer, slot, *rna_path_id_to_prop, prop_subtype, @@ -1002,7 +1006,8 @@ CombinedKeyingResult insert_keyframes(Main *bmain, KeyframeSettings key_settings = get_keyframe_settings( (insert_key_flags & INSERTKEY_NO_USERPREF) == 0); key_settings.keyframe_type = key_type; - return insert_key_layered_action(action, + return insert_key_layered_action(bmain, + action, struct_pointer, rna_paths, scene_frame.value_or(anim_eval_context.eval_time), diff --git a/source/blender/editors/animation/anim_filter_test.cc b/source/blender/editors/animation/anim_filter_test.cc index 3d29da5ed3b..4e89098a2a3 100644 --- a/source/blender/editors/animation/anim_filter_test.cc +++ b/source/blender/editors/animation/anim_filter_test.cc @@ -77,13 +77,15 @@ TEST_F(ActionFilterTest, slots_expanded_or_not) /* Create multiple FCurves for multiple Slots. */ const KeyframeSettings settings = get_keyframe_settings(false); ASSERT_EQ(SingleKeyingResult::SUCCESS, - key_strip.keyframe_insert(bind_cube, {"location", 0}, {1.0f, 0.25f}, settings)); + key_strip.keyframe_insert(bmain, bind_cube, {"location", 0}, {1.0f, 0.25f}, settings)); ASSERT_EQ(SingleKeyingResult::SUCCESS, - key_strip.keyframe_insert(bind_cube, {"location", 1}, {1.0f, 0.25f}, settings)); - ASSERT_EQ(SingleKeyingResult::SUCCESS, - key_strip.keyframe_insert(bind_suzanne, {"location", 0}, {1.0f, 0.25f}, settings)); - ASSERT_EQ(SingleKeyingResult::SUCCESS, - key_strip.keyframe_insert(bind_suzanne, {"location", 1}, {1.0f, 0.25f}, settings)); + key_strip.keyframe_insert(bmain, bind_cube, {"location", 1}, {1.0f, 0.25f}, settings)); + ASSERT_EQ( + SingleKeyingResult::SUCCESS, + key_strip.keyframe_insert(bmain, bind_suzanne, {"location", 0}, {1.0f, 0.25f}, settings)); + ASSERT_EQ( + SingleKeyingResult::SUCCESS, + key_strip.keyframe_insert(bmain, bind_suzanne, {"location", 1}, {1.0f, 0.25f}, settings)); ChannelBag *cube_channel_bag = key_strip.channelbag_for_slot(bind_cube); ASSERT_NE(nullptr, cube_channel_bag); @@ -232,9 +234,9 @@ TEST_F(ActionFilterTest, layered_action_active_fcurves) /* Create multiple FCurves. */ const KeyframeSettings settings = get_keyframe_settings(false); ASSERT_EQ(SingleKeyingResult::SUCCESS, - key_strip.keyframe_insert(bind_cube, {"location", 0}, {1.0f, 0.25f}, settings)); + key_strip.keyframe_insert(bmain, bind_cube, {"location", 0}, {1.0f, 0.25f}, settings)); ASSERT_EQ(SingleKeyingResult::SUCCESS, - key_strip.keyframe_insert(bind_cube, {"location", 1}, {1.0f, 0.25f}, settings)); + key_strip.keyframe_insert(bmain, bind_cube, {"location", 1}, {1.0f, 0.25f}, settings)); /* Set one F-Curve as the active one, and the other as inactive. The latter is necessary because * by default the first curve is automatically marked active, but that's too trivial a test case diff --git a/source/blender/editors/animation/anim_ops.cc b/source/blender/editors/animation/anim_ops.cc index 8febfd43ae7..d175e0f2b3a 100644 --- a/source/blender/editors/animation/anim_ops.cc +++ b/source/blender/editors/animation/anim_ops.cc @@ -740,6 +740,7 @@ static int slot_unassign_object_exec(bContext *C, wmOperator * /*op*/) Object *object = CTX_data_active_object(C); animrig::unassign_slot(object->id); + DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr); return OPERATOR_FINISHED; } diff --git a/source/blender/makesrna/intern/rna_action.cc b/source/blender/makesrna/intern/rna_action.cc index 07da59b96a9..9126943555b 100644 --- a/source/blender/makesrna/intern/rna_action.cc +++ b/source/blender/makesrna/intern/rna_action.cc @@ -513,7 +513,7 @@ static bool rna_KeyframeActionStrip_key_insert(ID *id, const animrig::KeyframeSettings settings = animrig::get_keyframe_settings(true); const animrig::SingleKeyingResult result = key_strip.keyframe_insert( - slot, {rna_path, array_index}, {time, value}, settings, INSERTKEY_NOFLAGS); + bmain, slot, {rna_path, array_index}, {time, value}, settings, INSERTKEY_NOFLAGS); const bool ok = result == animrig::SingleKeyingResult::SUCCESS; if (ok) { @@ -565,6 +565,7 @@ static int rna_iterator_ChannelBag_fcurves_length(PointerRNA *ptr) } static FCurve *rna_ChannelBag_fcurve_new(ActionChannelBag *dna_channelbag, + Main *bmain, ReportList *reports, const char *data_path, const int index) @@ -576,7 +577,7 @@ static FCurve *rna_ChannelBag_fcurve_new(ActionChannelBag *dna_channelbag, } animrig::ChannelBag &self = dna_channelbag->wrap(); - FCurve *fcurve = self.fcurve_create_unique({data_path, index}); + FCurve *fcurve = self.fcurve_create_unique(bmain, {data_path, index}); if (!fcurve) { BKE_reportf(reports, RPT_ERROR, @@ -1758,7 +1759,7 @@ static void rna_def_channelbag_fcurves(BlenderRNA *brna, PropertyRNA *cprop) func = RNA_def_function(srna, "new", "rna_ChannelBag_fcurve_new"); RNA_def_function_ui_description(func, "Add an F-Curve to the channelbag"); - RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_flag(func, FUNC_USE_MAIN | FUNC_USE_REPORTS); parm = RNA_def_string(func, "data_path", nullptr, 0, "Data Path", "F-Curve data path to use"); RNA_def_parameter_flags(parm, PropertyFlag(0), PARM_REQUIRED); RNA_def_int(func, "index", 0, 0, INT_MAX, "Index", "Array index", 0, INT_MAX); diff --git a/source/blender/makesrna/intern/rna_animation.cc b/source/blender/makesrna/intern/rna_animation.cc index c2003096f22..52e3c469a6e 100644 --- a/source/blender/makesrna/intern/rna_animation.cc +++ b/source/blender/makesrna/intern/rna_animation.cc @@ -1714,6 +1714,7 @@ static void rna_def_animdata(BlenderRNA *brna) "Action Slot", "The slot identifies which sub-set of the Action is considered to be for this " "data-block, and its name is used to find the right slot when assigning an Action"); + RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN, "rna_AnimData_dependency_update"); # endif