diff --git a/source/blender/animrig/intern/action.cc b/source/blender/animrig/intern/action.cc index f627ab527a8..6876ad37ba7 100644 --- a/source/blender/animrig/intern/action.cc +++ b/source/blender/animrig/intern/action.cc @@ -1829,6 +1829,12 @@ void ChannelBag::fcurve_move(FCurve &fcurve, int to_fcurve_index) void ChannelBag::fcurves_clear() { dna::array::clear(&this->fcurve_array, &this->fcurve_array_num, nullptr, fcurve_ptr_destructor); + + /* Since all F-Curves are gone, the groups are all empty. */ + for (bActionGroup *group : channel_groups()) { + group->fcurve_range_start = 0; + group->fcurve_range_length = 0; + } } SingleKeyingResult StripKeyframeData::keyframe_insert(Main *bmain, diff --git a/tests/python/bl_animation_keyframing.py b/tests/python/bl_animation_keyframing.py index dee531a0d0e..884a9c375bd 100644 --- a/tests/python/bl_animation_keyframing.py +++ b/tests/python/bl_animation_keyframing.py @@ -13,6 +13,16 @@ blender -b --factory-startup --python tests/python/bl_animation_keyframing.py -- """ +def enable_experimental_animation_baklava(): + bpy.context.preferences.view.show_developer_ui = True + bpy.context.preferences.experimental.use_animation_baklava = True + + +def disable_experimental_animation_baklava(): + bpy.context.preferences.view.show_developer_ui = False + bpy.context.preferences.experimental.use_animation_baklava = False + + def _fcurve_paths_match(fcurves: list, expected_paths: list) -> bool: data_paths = list(set([fcurve.data_path for fcurve in fcurves])) data_paths.sort() @@ -191,6 +201,57 @@ class InsertKeyTest(AbstractKeyframingTest, unittest.TestCase): self.assertFalse(fcurve.keyframe_points[0].select_control_point) self.assertTrue(fcurve.keyframe_points[1].select_control_point) + def test_keyframe_insert_py_func(self): + # Create a Bézier curve. + curve_data = bpy.data.curves.new("Curve", 'CURVE') + spline = curve_data.splines.new('BEZIER') + spline.bezier_points.add(2) + spline.bezier_points[0].co = (-1, 0, 0) + spline.bezier_points[1].co = (1, 0, 0) + + curve_object = bpy.data.objects.new("Curve", curve_data) + bpy.context.scene.collection.objects.link(curve_object) + + # Test on ID sub-data. + # self.assertTrue(curve_data.splines[0].bezier_points[0].keyframe_insert('co')) + + # cu_fcurves = curve_data.animation_data.action.fcurves + + # self.assertEqual(len(cu_fcurves), 3, + # "Keying 'location' without any array index should have created 3 F-Curves") + # self.assertEqual(3 * ['splines[0].bezier_points[0].co'], [fcurve.data_path for fcurve in cu_fcurves]) + # self.assertEqual([0, 1, 2], [fcurve.array_index for fcurve in cu_fcurves]) + + # Test on the Object directly. + self.assertTrue(curve_object.keyframe_insert('rotation_quaternion', index=-1)) + + ob_fcurves = curve_object.animation_data.action.fcurves + + self.assertEqual(len(ob_fcurves), 4, + "Keying 'rotation_quaternion' with index=-1 should have created 4 F-Curves") + self.assertEqual(4 * ['rotation_quaternion'], [fcurve.data_path for fcurve in ob_fcurves]) + self.assertEqual([0, 1, 2, 3], [fcurve.array_index for fcurve in ob_fcurves]) + + ob_fcurves.clear() + + self.assertTrue(curve_object.keyframe_insert('scale', index=2)) + self.assertEqual(len(ob_fcurves), 1, + "Keying 'scale' with index=2 should have created 1 F-Curve") + self.assertEqual('scale', ob_fcurves[0].data_path) + self.assertEqual(2, ob_fcurves[0].array_index) + + +class LayeredInsertKeyTest(InsertKeyTest): + @classmethod + def setUpClass(cls) -> None: + enable_experimental_animation_baklava() + super().setUpClass() + + @classmethod + def tearDownClass(cls) -> None: + disable_experimental_animation_baklava() + super().tearDownClass() + class VisualKeyingTest(AbstractKeyframingTest, unittest.TestCase): """ Check if visual keying produces the correct keyframe values. """