Anim: fix bug in action.fcurves.clear() corrupting F-Curve groups

Calling `action.fcurves.clear()` would clear the F-Curves, but didn't
update the F-Curve groups. This meant that the groups data still had their
original length & offsets into the F-Curves array, causing subsequent
F-Curve creation to crash Blender.

The unit test for this also covers the previous commit.

Pull Request: https://projects.blender.org/blender/blender/pulls/128375
This commit is contained in:
Sybren A. Stüvel
2024-09-30 15:03:46 +02:00
committed by Gitea
parent 420082d4fe
commit d58176e1e0
2 changed files with 67 additions and 0 deletions
+61
View File
@@ -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. """