From 9ff2ccd350a97889ed28ac91bd6ccc142fcd4d5b Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Fri, 29 Aug 2025 17:56:38 +1000 Subject: [PATCH] Fix: incorrect handling of 3x3 matrices with RNA get/set callbacks Thanks to @mont29 for spotting the error. --- source/blender/python/intern/bpy_props.cc | 4 +-- tests/python/bl_pyapi_prop_array.py | 37 +++++++++++++++++++---- 2 files changed, 33 insertions(+), 8 deletions(-) diff --git a/source/blender/python/intern/bpy_props.cc b/source/blender/python/intern/bpy_props.cc index e092449f0f6..4c7664e9fcc 100644 --- a/source/blender/python/intern/bpy_props.cc +++ b/source/blender/python/intern/bpy_props.cc @@ -545,8 +545,8 @@ static bool bpy_prop_array_is_matrix_compatible_ex(int subtype, const BPyPropArrayLength *array_len_info) { return ((subtype == PROP_MATRIX) && (array_len_info->dims_len == 2) && - ((array_len_info->dims[0] >= 2) && (array_len_info->dims[0] >= 4)) && - ((array_len_info->dims[1] >= 2) && (array_len_info->dims[1] >= 4))); + ((array_len_info->dims[0] >= 2) && (array_len_info->dims[0] <= 4)) && + ((array_len_info->dims[1] >= 2) && (array_len_info->dims[1] <= 4))); } static bool bpy_prop_array_is_matrix_compatible(PropertyRNA *prop, diff --git a/tests/python/bl_pyapi_prop_array.py b/tests/python/bl_pyapi_prop_array.py index 2aaf4e0ba7c..c1bddebd5bd 100644 --- a/tests/python/bl_pyapi_prop_array.py +++ b/tests/python/bl_pyapi_prop_array.py @@ -49,6 +49,19 @@ def seq_items_as_dims(data): return ((len(data),) + seq_items_as_dims(data[0])) if hasattr(data, "__len__") else () +def matrix_with_repeating_digits(dims_x, dims_y): + """ + Create an array with easily identifier able unique elements: + When: dims_x=4, dims_y=3 results in: + ((1, 2, 3, 4), (11, 22, 33, 44), (111, 222, 333, 444)) + """ + prev = (0,) * dims_x + return tuple([ + (prev := tuple(((10 ** yi) * xi) + prev[i] for i, xi in enumerate(range(1, dims_x + 1)))) + for yi in range(dims_y) + ]) + + # ----------------------------------------------------------------------------- # Tests @@ -463,20 +476,20 @@ class TestPropArrayMultiDimensional(unittest.TestCase): self.assertEqual(data_as_tuple, data_native) del id_type.temp - def test_matrix(self): - data = ((1, 2, 3, 4), (11, 22, 33, 44), (111, 222, 333, 444), (1111, 2222, 3333, 4444),) + def _test_matrix(self, dim_x, dim_y): + data = matrix_with_repeating_digits(dim_x, dim_y) data_native = seq_items_xform(data, lambda v: float(v)) - id_type.temp = FloatVectorProperty(size=(4, 4), subtype='MATRIX', default=data_native) + id_type.temp = FloatVectorProperty(size=(dim_x, dim_y), subtype='MATRIX', default=data_native) data_as_tuple = seq_items_as_tuple(id_inst.temp) self.assertEqual(data_as_tuple, data_native) del id_type.temp - def test_matrix_with_callbacks(self): + def _test_matrix_with_callbacks(self, dim_x, dim_y): # """ # Internally matrices have rows/columns swapped, # This test ensures this is being done properly. # """ - data = ((1, 2, 3, 4), (11, 22, 33, 44), (111, 222, 333, 444), (1111, 2222, 3333, 4444),) + data = matrix_with_repeating_digits(dim_x, dim_y) data_native = seq_items_xform(data, lambda v: float(v)) local_data = {"array": data} @@ -486,12 +499,24 @@ class TestPropArrayMultiDimensional(unittest.TestCase): def set_fn(id_arg, value): local_data["array"] = value - id_type.temp = FloatVectorProperty(size=(4, 4), subtype='MATRIX', get=get_fn, set=set_fn) + id_type.temp = FloatVectorProperty(size=(dim_x, dim_y), subtype='MATRIX', get=get_fn, set=set_fn) id_inst.temp = data_native data_as_tuple = seq_items_as_tuple(id_inst.temp) self.assertEqual(data_as_tuple, data_native) del id_type.temp + def test_matrix_3x3(self): + self._test_matrix(3, 3) + + def test_matrix_4x4(self): + self._test_matrix(4, 4) + + def _test_matrix_with_callbacks_3x3(self): + self._test_matrix_with_callbacks(self, 3, 3) + + def _test_matrix_with_callbacks_4x4(self): + self._test_matrix_with_callbacks(self, 4, 4) + class TestPropArrayDynamicAssign(unittest.TestCase): """