Python part of multidim. array support for RNA complete.
authorArystanbek Dyussenov <arystan.d@gmail.com>
Sun, 6 Sep 2009 15:13:57 +0000 (15:13 +0000)
committerArystanbek Dyussenov <arystan.d@gmail.com>
Sun, 6 Sep 2009 15:13:57 +0000 (15:13 +0000)
Multidim. arrays can now be modified at any level, for example:

struc.arrayprop = x
struc.arrayprop[i] = x
struc.arrayprop[i][j] = x
struc.arrayprop[i][j][k] = x
etc...

Approriate rvalue type/length checking is done.

To ensure all works correctly, I wrote automated tests in release/test/rna_array.py.

These tests cover: array/item access, assignment on different levels, tests that proper exceptions are thrown on invalid item access/assignment.

The tests use properties of the RNA Test struct defined in rna_test.c. This struct is only compiled when building with BF_UNIT_TEST=1 scons arg.

Currently unit tests are run manually by loading the script in the Text Editor.
Here's the output I have: http://www.pasteall.org/7644

Things to improve here:
- better exception messages when multidim. array assignment fails. Those we have currently are not very useful for multidim.
- add tests for slice assignment

17 files changed:
release/test/rna_array.py [new file with mode: 0644]
source/blender/blenloader/intern/readblenentry.c
source/blender/makesrna/RNA_access.h
source/blender/makesrna/SConscript
source/blender/makesrna/intern/SConscript
source/blender/makesrna/intern/makesrna.c
source/blender/makesrna/intern/rna_access.c
source/blender/makesrna/intern/rna_define.c
source/blender/makesrna/intern/rna_internal.h
source/blender/makesrna/intern/rna_internal_types.h
source/blender/makesrna/intern/rna_main.c
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_test.c [new file with mode: 0644]
source/blender/python/intern/bpy_array.c
source/blender/python/intern/bpy_rna.c
source/blender/python/intern/bpy_rna.h
tools/btools.py

diff --git a/release/test/rna_array.py b/release/test/rna_array.py
new file mode 100644 (file)
index 0000000..9b7c65f
--- /dev/null
@@ -0,0 +1,279 @@
+import unittest
+import random
+
+test= bpy.data.test
+
+# farr - 1-dimensional array of float
+# fdarr - dynamic 1-dimensional array of float
+# fmarr - 3-dimensional ([3][4][5]) array of float
+# fdmarr - dynamic 3-dimensional (ditto size) array of float
+
+# same as above for other types except that the first letter is "i" for int and "b" for bool
+
+class TestArray(unittest.TestCase):
+       # test that assignment works by: assign -> test value
+       # - rvalue = list of float
+       # - rvalue = list of numbers
+       # test.object
+       # bpy.data.test.farr[3], iarr[3], barr[...], fmarr, imarr, bmarr
+
+       def setUp(self):
+               test.farr= (1.0, 2.0, 3.0)
+               test.iarr= (7, 8, 9)
+               test.barr= (False, True, False)
+       
+       # test access
+       # test slice access, negative indices
+       def test_access(self):
+               rvals= ([1.0, 2.0, 3.0], [7, 8, 9], [False, True, False])
+               for arr, rval in zip((test.farr, test.iarr, test.barr), rvals):
+                       self.assertEqual(prop_to_list(arr), rval)
+                       self.assertEqual(arr[0:3], rval)
+                       self.assertEqual(arr[1:2], rval[1:2])
+                       self.assertEqual(arr[-1], arr[2])
+                       self.assertEqual(arr[-2], arr[1])
+                       self.assertEqual(arr[-3], arr[0])
+
+       # fail when index out of bounds
+       def test_access_fail(self):
+               for arr in (test.farr, test.iarr, test.barr):
+                       self.assertRaises(IndexError, lambda : arr[4])
+       
+       # test assignment of a whole array
+       def test_assign_array(self):
+               # should accept int as float
+               test.farr= (1, 2, 3)
+
+       # fail when: unexpected no. of items, invalid item type
+       def test_assign_array_fail(self):
+               def assign_empty_list(arr):
+                       setattr(test, arr, ())
+
+               for arr in ("farr", "iarr", "barr"):
+                       self.assertRaises(ValueError, assign_empty_list, arr)
+
+               def assign_invalid_float():
+                       test.farr= (1.0, 2.0, "3.0")
+
+               def assign_invalid_int():
+                       test.iarr= ("1", 2, 3)
+
+               def assign_invalid_bool():
+                       test.barr= (True, 0.123, False)
+
+               for func in [assign_invalid_float, assign_invalid_int, assign_invalid_bool]:
+                       self.assertRaises(TypeError, func)
+
+               # shouldn't accept float as int
+               def assign_float_as_int():
+                       test.iarr= (1, 2, 3.0)
+               self.assertRaises(TypeError, assign_float_as_int)
+
+               # non-dynamic arrays cannot change size
+               def assign_different_size(arr, val):
+                       setattr(test, arr, val)
+               for arr, val in zip(("iarr", "farr", "barr"), ((1, 2), (1.0, 2.0), (True, False))):
+                       self.assertRaises(ValueError, assign_different_size, arr, val)
+
+       # test assignment of specific items
+       def test_assign_item(self):
+               for arr, rand_func in zip((test.farr, test.iarr, test.barr), (rand_float, rand_int, rand_bool)):
+                       for i in range(len(arr)):
+                               val= rand_func()
+                               arr[i]= val
+                               
+                               self.assertEqual(arr[i], val)
+
+               # float prop should accept also int
+               for i in range(len(test.farr)):
+                       val= rand_int()
+                       test.farr[i]= val
+                       self.assertEqual(test.farr[i], float(val))
+
+               # 
+
+       def test_assign_item_fail(self):
+               def assign_bad_index(arr):
+                       arr[4] = 1.0
+
+               def assign_bad_type(arr):
+                       arr[1]= "123"
+                       
+               for arr in [test.farr, test.iarr, test.barr]:
+                       self.assertRaises(IndexError, assign_bad_index, arr)
+
+               # not testing bool because bool allows not only (True|False)
+               for arr in [test.farr, test.iarr]:      
+                       self.assertRaises(TypeError, assign_bad_type, arr)
+
+       def test_dynamic_assign_array(self):
+               # test various lengths here
+               for arr, rand_func in zip(("fdarr", "idarr", "bdarr"), (rand_float, rand_int, rand_bool)):
+                       for length in range(1, 64):
+                               rval= make_random_array(length, rand_func)
+                               setattr(test, arr, rval)
+                               self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+       def test_dynamic_assign_array_fail(self):
+               # could also test too big length here
+               
+               def assign_empty_list(arr):
+                       setattr(test, arr, ())
+
+               for arr in ("fdarr", "idarr", "bdarr"):
+                       self.assertRaises(ValueError, assign_empty_list, arr)
+
+
+class TestMArray(unittest.TestCase):
+       def setUp(self):
+               # reset dynamic array sizes
+               for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
+                       setattr(test, arr, make_random_3d_array((3, 4, 5), func))
+
+       # test assignment
+       def test_assign_array(self):
+               for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
+                       # assignment of [3][4][5]
+                       rval= make_random_3d_array((3, 4, 5), func)
+                       setattr(test, arr, rval)
+                       self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+               # test assignment of [2][4][5], [1][4][5] should work on dynamic arrays
+
+       def test_assign_array_fail(self):
+               def assign_empty_array():
+                       test.fmarr= ()
+               self.assertRaises(ValueError, assign_empty_array)
+
+               def assign_invalid_size(arr, rval):
+                       setattr(test, arr, rval)
+
+               # assignment of 3,4,4 or 3,3,5 should raise ex
+               for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
+                       rval= make_random_3d_array((3, 4, 4), func)
+                       self.assertRaises(ValueError, assign_invalid_size, arr, rval)
+
+                       rval= make_random_3d_array((3, 3, 5), func)
+                       self.assertRaises(ValueError, assign_invalid_size, arr, rval)
+
+                       rval= make_random_3d_array((3, 3, 3), func)
+                       self.assertRaises(ValueError, assign_invalid_size, arr, rval)
+
+       def test_assign_item(self):
+               # arr[i] = x
+               for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
+                       rval= make_random_2d_array((4, 5), func)
+
+                       for i in range(3):
+                               getattr(test, arr)[i]= rval
+                               self.assertEqual(prop_to_list(getattr(test, arr)[i]), rval)
+
+               # arr[i][j] = x
+               for arr, func in zip(("fmarr", "imarr", "bmarr", "fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool) * 2):
+
+                       arr= getattr(test, arr)
+                       rval= make_random_array(5, func)
+
+                       for i in range(3):
+                               for j in range(4):
+                                       arr[i][j]= rval
+                                       self.assertEqual(prop_to_list(arr[i][j]), rval)
+
+
+       def test_assign_item_fail(self):
+               def assign_wrong_size(arr, i, rval):
+                       getattr(test, arr)[i]= rval
+
+               # assign wrong size at level 2
+               for arr, func in zip(("fmarr", "imarr", "bmarr"), (rand_float, rand_int, rand_bool)):
+                       rval1= make_random_2d_array((3, 5), func)
+                       rval2= make_random_2d_array((4, 3), func)
+
+                       for i in range(3):
+                               self.assertRaises(ValueError, assign_wrong_size, arr, i, rval1)
+                               self.assertRaises(ValueError, assign_wrong_size, arr, i, rval2)
+
+       def test_dynamic_assign_array(self):
+               for arr, func in zip(("fdmarr", "idmarr", "bdmarr"), (rand_float, rand_int, rand_bool)):
+                       # assignment of [3][4][5]
+                       rval= make_random_3d_array((3, 4, 5), func)
+                       setattr(test, arr, rval)
+                       self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+                       # [2][4][5]
+                       rval= make_random_3d_array((2, 4, 5), func)
+                       setattr(test, arr, rval)
+                       self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+                       # [1][4][5]
+                       rval= make_random_3d_array((1, 4, 5), func)
+                       setattr(test, arr, rval)
+                       self.assertEqual(prop_to_list(getattr(test, arr)), rval)
+
+
+       # test access
+       def test_access(self):
+               pass
+
+       # test slice access, negative indices
+       def test_access_fail(self):
+               pass
+
+random.seed()
+
+def rand_int():
+       return random.randint(-1000, 1000)
+
+def rand_float():
+       return float(rand_int())
+
+def rand_bool():
+       return bool(random.randint(0, 1))
+
+def make_random_array(len, rand_func):
+       arr= []
+       for i in range(len):
+               arr.append(rand_func())
+               
+       return arr
+
+def make_random_2d_array(dimsize, rand_func):
+       marr= []
+       for i in range(dimsize[0]):
+               marr.append([])
+
+               for j in range(dimsize[1]):
+                       marr[-1].append(rand_func())
+
+       return marr
+
+def make_random_3d_array(dimsize, rand_func):
+       marr= []
+       for i in range(dimsize[0]):
+               marr.append([])
+
+               for j in range(dimsize[1]):
+                       marr[-1].append([])
+
+                       for k in range(dimsize[2]):
+                               marr[-1][-1].append(rand_func())
+
+       return marr
+
+def prop_to_list(prop):
+       ret= []
+
+       for x in prop:
+               if type(x) not in (bool, int, float):
+                       ret.append(prop_to_list(x))
+               else:
+                       ret.append(x)
+
+       return ret
+
+def suite():
+       return unittest.TestSuite([unittest.TestLoader().loadTestsFromTestCase(TestArray), unittest.TestLoader().loadTestsFromTestCase(TestMArray)])
+
+if __name__ == "__main__":
+       unittest.TextTestRunner(verbosity=2).run(suite())
+
index 1c21c1817e69f86a9468cc6d974e10b61c83a8b6..9cd45a268da3e1624a0bfe6e14ddf2b5cf901355 100644 (file)
 #include <config.h>
 #endif
 
+#include "BLI_storage.h" /* _LARGEFILE_SOURCE */
+
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
 #include <math.h>
 
-
-#include "BLI_storage.h" /* _LARGEFILE_SOURCE */
-
 #include "MEM_guardedalloc.h"
 
 #include "BLI_blenlib.h"
index 98205d17ef38f70d02cc2bf8d4f054bfb921c9b1..4107c1346e5a60ce04d43406e409e94280ec5593 100644 (file)
@@ -586,6 +586,7 @@ PropertyUnit RNA_property_unit(PropertyRNA *prop);
 int RNA_property_flag(PropertyRNA *prop);
 
 int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop);
+int RNA_property_multidimensional_array_length(PointerRNA *ptr, PropertyRNA *prop, int dimension);
 int RNA_property_dynamic_array_set_length(PointerRNA *ptr, PropertyRNA *prop, int length);
 char RNA_property_array_item_char(PropertyRNA *prop, int index);
 unsigned short RNA_property_array_dimension(PropertyRNA *prop, unsigned short dim_size[]);
index c2790927cef38b7babac13ee5b71ee6b37fb4b64..845abf636e23c2d185d9215174a0904286958fa5 100644 (file)
@@ -37,4 +37,7 @@ if env['WITH_BF_LCMS']:
 if env['WITH_BF_GAMEENGINE']:
        defs.append('GAMEBLENDER=1')
 
+if env['BF_UNIT_TEST']:
+       defs.append('UNIT_TEST')
+
 env.BlenderLib ( 'bf_rna', objs, Split(incs), defines=defs, libtype=['core','player'], priority = [165,20] )
index 9234efa2a5d73bf794b5398069afc80771b59afd..569f0547731bb4bf8efb1ed49cd1f0d1ea2fbb1f 100644 (file)
@@ -71,6 +71,9 @@ if env['WITH_BF_OPENAL']:
 if env['WITH_BF_JACK']:
     defs.append('WITH_JACK')
 
+if env['BF_UNIT_TEST']:
+       defs.append('UNIT_TEST')
+
 makesrna_tool.Append(CPPDEFINES=defs)
 
 makesrna_tool.Append (CPPPATH = Split(incs))
index bb7b6cbcd37c94eccdf04205c660e97faed8a949..907eba4018f140b0d37bc8ca9960601ac0428086 100644 (file)
@@ -1991,6 +1991,7 @@ RNAProcessItem PROCESS_ITEMS[]= {
        {"rna_sequence.c", NULL, RNA_def_sequence},
        {"rna_smoke.c", NULL, RNA_def_smoke},
        {"rna_space.c", NULL, RNA_def_space},
+       {"rna_test.c", NULL, RNA_def_test},
        {"rna_text.c", NULL, RNA_def_text},
        {"rna_timeline.c", NULL, RNA_def_timeline_marker},
        {"rna_sound.c", NULL, RNA_def_sound},
index e71dcc2a586148eebf1d1005a16087eb2b36675d..f37fa01480cb230b7ee35fca15899237eec7265c 100644 (file)
@@ -557,14 +557,24 @@ int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
 
 int RNA_property_dynamic_array_set_length(PointerRNA *ptr, PropertyRNA *prop, int length)
 {
-       if (prop->setlength)
-               return prop->setlength(ptr, length);
+       /* length 0 is not allowed */
+       if (!length)
+               return 0;
+
+       if (prop->getlength) {
+               if (prop->setlength)
+                       return prop->setlength(ptr, length);
+               else
+                       /* length cannot be changed */
+                       return 0;
+       }
        else
                prop->arraylength= length; /* function parameters only? */
 
        return 1;
 }
 
+/* used by BPY to make an array from the python object */
 unsigned short RNA_property_array_dimension(PropertyRNA *prop, unsigned short dimsize[])
 {
        if (dimsize && prop->arraydimension > 1) {
@@ -573,6 +583,25 @@ unsigned short RNA_property_array_dimension(PropertyRNA *prop, unsigned short di
        return prop->arraydimension;
 }
 
+/* Return the size of Nth dimension. */
+int RNA_property_multidimensional_array_length(PointerRNA *ptr, PropertyRNA *prop, int dim)
+{
+       unsigned short i;
+       int len;
+
+       if (dim == 0) {
+               len= RNA_property_array_length(ptr, prop);
+
+               for (i= 0; i < prop->arraydimension - 1; i++)
+                       len /= prop->dimsize[i];
+       }
+       else {
+               len= prop->dimsize[dim - 1];
+       }
+
+       return len;
+}
+
 char RNA_property_array_item_char(PropertyRNA *prop, int index)
 {
        const char *vectoritem= "XYZW";
index 69e6698bd3b34ec3c45c35af8dca612f0b5cf421..e415304ab6c84542c8f71fa71a56e0bc7cc04236 100644 (file)
@@ -1046,6 +1046,8 @@ void RNA_def_property_multidimensional_array(PropertyRNA *prop, int arraylength,
 
        prop->arraydimension= dimension;
 
+       /* TODO make sure dimsize values are sane  */
+
        if (dimension > 1)
                memcpy(prop->dimsize, dimsize, sizeof(dimsize[0]) * (dimension - 1));
 }
index 13cc2ae90174cef723fbd00ab063a21bbb7b0dcd..7de80843f27533c3123fdd2dec473663ab93b350 100644 (file)
@@ -157,6 +157,7 @@ void RNA_def_sensor(struct BlenderRNA *brna);
 void RNA_def_sequence(struct BlenderRNA *brna);
 void RNA_def_smoke(struct BlenderRNA *brna);
 void RNA_def_space(struct BlenderRNA *brna);
+void RNA_def_test(struct BlenderRNA *brna);
 void RNA_def_text(struct BlenderRNA *brna);
 void RNA_def_texture(struct BlenderRNA *brna);
 void RNA_def_timeline_marker(struct BlenderRNA *brna);
index d706fd5ac1953aa055408e4113a33622331bc173..2bd89dbd3bf9a607a57df6fa11f4bce1c8292484 100644 (file)
@@ -39,7 +39,12 @@ struct bContext;
 struct IDProperty;
 struct GHash;
 
+#ifdef UNIT_TEST
+#define RNA_MAX_ARRAY 64
+#else
 #define RNA_MAX_ARRAY 32
+#endif
+
 #define RNA_MAX_ARRAY_DIMENSION 3
 
 /* Function Callbacks */
@@ -134,11 +139,10 @@ struct PropertyRNA {
        PropertySubType subtype;
        /* if an array this is > 0, specifying the length */
        unsigned int arraylength;
-       /* these, if non-NULL, override arraylength */
+       /* if non-NULL, overrides arraylength. Must not return 0? */
        PropArrayLengthGetFunc getlength;
        /* if NULL, length cannot be changed by a user */
        PropArrayLengthSetFunc setlength;
-       /* used only for dynamic arrays for now, default 1 */
        unsigned short arraydimension;
        /* dimension sizes for dimensions greater than 1, first dimension size is not specified */
        unsigned short dimsize[RNA_MAX_ARRAY_DIMENSION - 1];
index 82e460ea57d6d53508b02218992ebd6dcd06ca8f..344135acaffdc62e6de6a24cde77df039bc34078 100644 (file)
@@ -219,6 +219,18 @@ static void rna_Main_wm_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
        rna_iterator_listbase_begin(iter, &bmain->wm, NULL);
 }
 
+#ifdef UNIT_TEST
+
+static PointerRNA rna_Test_test_get(PointerRNA *ptr)
+{
+       PointerRNA ret= *ptr;
+       ret.type= &RNA_Test;
+
+       return ret;
+}
+
+#endif
+
 #else
 
 void RNA_def_main(BlenderRNA *brna)
@@ -276,6 +288,18 @@ void RNA_def_main(BlenderRNA *brna)
        }
 
        RNA_api_main(srna);
+
+#ifdef UNIT_TEST
+
+       RNA_define_verify_sdna(0);
+
+       prop= RNA_def_property(srna, "test", PROP_POINTER, PROP_NONE);
+       RNA_def_property_struct_type(prop, "Test");
+       RNA_def_property_pointer_funcs(prop, "rna_Test_test_get", NULL, NULL);
+
+       RNA_define_verify_sdna(1);
+
+#endif
 }
 
 #endif
index f7235db49a55931998b243bd0b07340fe3d4defc..efd0046d827d7978cf1ed5b38026ad381123ce1d 100644 (file)
@@ -1182,7 +1182,7 @@ static void rna_def_mtface(BlenderRNA *brna)
        RNA_def_property_ui_text(prop, "UV 4", "");
        RNA_def_property_update(prop, 0, "rna_Mesh_update_data");
 
-       prop= RNA_def_property(srna, "uv", PROP_FLOAT, PROP_XYZ);
+       prop= RNA_def_property(srna, "uv", PROP_FLOAT, PROP_NONE);
        RNA_def_property_multidimensional_array(prop, 4 * 2, 2, uv_dim);
        RNA_def_property_flag(prop, PROP_DYNAMIC);
        RNA_def_property_dynamic_array_funcs(prop, "rna_MeshTextureFace_uv_get_length", "rna_MeshTextureFace_uv_set_length");
diff --git a/source/blender/makesrna/intern/rna_test.c b/source/blender/makesrna/intern/rna_test.c
new file mode 100644 (file)
index 0000000..bfaf318
--- /dev/null
@@ -0,0 +1,188 @@
+/**
+ * $Id: rna_test.c  $
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * Contributor(s): Arystanbek Dyussenov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* Defines a structure with properties used for array manipulation tests in BPY. */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "RNA_define.h"
+#include "RNA_types.h"
+
+#include "rna_internal.h"
+
+#define ARRAY_SIZE 3
+#define DYNAMIC_ARRAY_SIZE 64
+#define MARRAY_DIM [3][4][5]
+#define MARRAY_TOTDIM 3
+#define MARRAY_DIMSIZE 4, 5
+#define MARRAY_SIZE(type) (sizeof(type MARRAY_DIM) / sizeof(type))
+#define DYNAMIC_MARRAY_DIM [3][4][5]
+#define DYNAMIC_MARRAY_SIZE(type) (sizeof(type DYNAMIC_MARRAY_DIM) / sizeof(type))
+
+#ifdef RNA_RUNTIME
+
+#ifdef UNIT_TEST
+
+#define DEF_VARS(type, prefix)                                                         \
+       static type prefix ## arr[ARRAY_SIZE];                                  \
+       static type prefix ## darr[DYNAMIC_ARRAY_SIZE];                 \
+       static int prefix ## darr_len= ARRAY_SIZE;                              \
+       static type prefix ## marr MARRAY_DIM;                                  \
+       static type prefix ## dmarr DYNAMIC_MARRAY_DIM;                 \
+       static int prefix ## dmarr_len= sizeof(prefix ## dmarr);
+
+#define DEF_GET_SET(type, arr)                                                                                 \
+       void rna_Test_ ## arr ## _get(PointerRNA *ptr, type *values)            \
+       {                                                                                                                                       \
+               memcpy(values, arr, sizeof(arr));                                                               \
+       }                                                                                                                                       \
+                                                                                                                                               \
+       void rna_Test_ ## arr ## _set(PointerRNA *ptr, const type *values)      \
+       {                                                                                                                                       \
+               memcpy(arr, values, sizeof(arr));                                                               \
+       }
+
+#define DEF_GET_SET_LEN(arr, max)                                                                              \
+       static int rna_Test_ ## arr ## _get_length(PointerRNA *ptr)                     \
+       {                                                                                                                                       \
+               return arr ## _len;                                                                                             \
+       }                                                                                                                                       \
+                                                                                                                                               \
+       static int rna_Test_ ## arr ## _set_length(PointerRNA *ptr, int length) \
+       {                                                                                                                                       \
+               if (length > max)                                                                                               \
+                       return 0;                                                                                                       \
+                                                                                                                                               \
+               arr ## _len= length;                                                                                    \
+                                                                                                                                               \
+               return 1;                                                                                                               \
+       }                                                                                                                                       \
+
+DEF_VARS(float, f)
+DEF_VARS(int, i)
+DEF_VARS(int, b)
+
+DEF_GET_SET(float, farr)
+DEF_GET_SET(int, iarr)
+DEF_GET_SET(int, barr)
+
+DEF_GET_SET(float, fmarr)
+DEF_GET_SET(int, imarr)
+DEF_GET_SET(int, bmarr)
+
+DEF_GET_SET(float, fdarr)
+DEF_GET_SET_LEN(fdarr, DYNAMIC_ARRAY_SIZE)
+DEF_GET_SET(int, idarr)
+DEF_GET_SET_LEN(idarr, DYNAMIC_ARRAY_SIZE)
+DEF_GET_SET(int, bdarr)
+DEF_GET_SET_LEN(bdarr, DYNAMIC_ARRAY_SIZE)
+
+DEF_GET_SET(float, fdmarr)
+DEF_GET_SET_LEN(fdmarr, DYNAMIC_MARRAY_SIZE(float))
+DEF_GET_SET(int, idmarr)
+DEF_GET_SET_LEN(idmarr, DYNAMIC_MARRAY_SIZE(int))
+DEF_GET_SET(int, bdmarr)
+DEF_GET_SET_LEN(bdmarr, DYNAMIC_MARRAY_SIZE(int))
+
+#endif
+
+#else
+
+void RNA_def_test(BlenderRNA *brna)
+{
+#ifdef UNIT_TEST
+       StructRNA *srna;
+       PropertyRNA *prop;
+       unsigned short dimsize[]= {MARRAY_DIMSIZE};
+
+       srna= RNA_def_struct(brna, "Test", NULL);
+       RNA_def_struct_sdna(srna, "Test");
+
+       prop= RNA_def_float_array(srna, "farr", ARRAY_SIZE, NULL, 0.0f, 0.0f, "farr", "float array", 0.0f, 0.0f);
+       RNA_def_property_float_funcs(prop, "rna_Test_farr_get", "rna_Test_farr_set", NULL);
+
+       prop= RNA_def_int_array(srna, "iarr", ARRAY_SIZE, NULL, 0, 0, "iarr", "int array", 0, 0);
+       RNA_def_property_int_funcs(prop, "rna_Test_iarr_get", "rna_Test_iarr_set", NULL);
+
+       prop= RNA_def_boolean_array(srna, "barr", ARRAY_SIZE, NULL, "barr", "boolean array");
+       RNA_def_property_boolean_funcs(prop, "rna_Test_barr_get", "rna_Test_barr_set");
+
+       /* dynamic arrays */
+
+       prop= RNA_def_float_array(srna, "fdarr", DYNAMIC_ARRAY_SIZE, NULL, 0.0f, 0.0f, "fdarr", "dynamic float array", 0.0f, 0.0f);
+       RNA_def_property_flag(prop, PROP_DYNAMIC);
+       RNA_def_property_dynamic_array_funcs(prop, "rna_Test_fdarr_get_length", "rna_Test_fdarr_set_length");
+       RNA_def_property_float_funcs(prop, "rna_Test_fdarr_get", "rna_Test_fdarr_set", NULL);
+
+       prop= RNA_def_int_array(srna, "idarr", DYNAMIC_ARRAY_SIZE, NULL, 0, 0, "idarr", "int array", 0, 0);
+       RNA_def_property_flag(prop, PROP_DYNAMIC);
+       RNA_def_property_dynamic_array_funcs(prop, "rna_Test_idarr_get_length", "rna_Test_idarr_set_length");
+       RNA_def_property_int_funcs(prop, "rna_Test_idarr_get", "rna_Test_idarr_set", NULL);
+       
+       prop= RNA_def_boolean_array(srna, "bdarr", DYNAMIC_ARRAY_SIZE, NULL, "bdarr", "boolean array");
+       RNA_def_property_flag(prop, PROP_DYNAMIC);
+       RNA_def_property_dynamic_array_funcs(prop, "rna_Test_bdarr_get_length", "rna_Test_bdarr_set_length");
+       RNA_def_property_boolean_funcs(prop, "rna_Test_bdarr_get", "rna_Test_bdarr_set");
+
+       /* multidimensional arrays */
+
+       prop= RNA_def_property(srna, "fmarr", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_multidimensional_array(prop, MARRAY_SIZE(float), MARRAY_TOTDIM, dimsize);
+       RNA_def_property_float_funcs(prop, "rna_Test_fmarr_get", "rna_Test_fmarr_set", NULL);
+
+       prop= RNA_def_property(srna, "imarr", PROP_INT, PROP_NONE);
+       RNA_def_property_multidimensional_array(prop, MARRAY_SIZE(int), MARRAY_TOTDIM, dimsize);
+       RNA_def_property_int_funcs(prop, "rna_Test_imarr_get", "rna_Test_imarr_set", NULL);
+
+       prop= RNA_def_property(srna, "bmarr", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_multidimensional_array(prop, MARRAY_SIZE(int), MARRAY_TOTDIM, dimsize);
+       RNA_def_property_boolean_funcs(prop, "rna_Test_bmarr_get", "rna_Test_bmarr_set");
+
+       /* dynamic multidimensional arrays */
+
+       prop= RNA_def_property(srna, "fdmarr", PROP_FLOAT, PROP_NONE);
+       RNA_def_property_multidimensional_array(prop, DYNAMIC_MARRAY_SIZE(float), MARRAY_TOTDIM, dimsize);
+       RNA_def_property_flag(prop, PROP_DYNAMIC);
+       RNA_def_property_dynamic_array_funcs(prop, "rna_Test_fdmarr_get_length", "rna_Test_fdmarr_set_length");
+       RNA_def_property_float_funcs(prop, "rna_Test_fdmarr_get", "rna_Test_fdmarr_set", NULL);
+
+       prop= RNA_def_property(srna, "idmarr", PROP_INT, PROP_NONE);
+       RNA_def_property_multidimensional_array(prop, DYNAMIC_MARRAY_SIZE(int), MARRAY_TOTDIM, dimsize);
+       RNA_def_property_flag(prop, PROP_DYNAMIC);
+       RNA_def_property_dynamic_array_funcs(prop, "rna_Test_idmarr_get_length", "rna_Test_idmarr_set_length");
+       RNA_def_property_int_funcs(prop, "rna_Test_idmarr_get", "rna_Test_idmarr_set", NULL);
+
+       prop= RNA_def_property(srna, "bdmarr", PROP_BOOLEAN, PROP_NONE);
+       RNA_def_property_multidimensional_array(prop, DYNAMIC_MARRAY_SIZE(int), MARRAY_TOTDIM, dimsize);
+       RNA_def_property_flag(prop, PROP_DYNAMIC);
+       RNA_def_property_dynamic_array_funcs(prop, "rna_Test_bdmarr_get_length", "rna_Test_bdmarr_set_length");
+       RNA_def_property_boolean_funcs(prop, "rna_Test_bdmarr_get", "rna_Test_bdmarr_set");
+
+#endif
+}
+
+#endif /* RNA_RUNTIME */
+
+
index 669cccb70111a8554f0bb3dec5efdfbc66627aab..9db4b20d011f5e758c6c2e7a9a5e8f1126841455 100644 (file)
 
 #include "BLI_string.h"
 
+#include "BKE_global.h"
+
 #include "MEM_guardedalloc.h"
 
+#define MAX_ARRAY_DIMENSION 10
+
+/* convenient way to access array dimension size */
+#define DIMSIZE(a) (dimsize[a - 1])
+
 typedef void (*ItemConvertFunc)(PyObject *, char *);
-typedef int (*ItemTypeCheckFunc)(PyObject *);
+typedef int  (*ItemTypeCheckFunc)(PyObject *);
 typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
+typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
+
+/*
+  arr[3][4][5]
+      0  1  2  <- dimension index
+*/
 
-/* Ensures that a python sequence has an expected number of items/sub-items and items are of expected type. */
-static int pyrna_validate_array(PyObject *seq, unsigned short dim, unsigned short totdim, unsigned short dim_size[],
-                                                               ItemTypeCheckFunc check_item_type, const char *item_type_str, char *error_str, int error_str_size)
+/*
+  arr[2] = x
+
+  py_to_array_index(arraydim=0, arrayoffset=0, index=2)
+    validate_array(lvalue_dim=0)
+    ... make real index ...
+*/
+
+/* arr[3]=x, self->arraydim is 0, lvalue_dim is 1 */
+/* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
+static int validate_array_type(PyObject *seq, unsigned short dim, unsigned short totdim, unsigned short dimsize[],
+                                                          ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
 {
        int i;
-       if (dim < totdim) {
+
+       /* not the last dimension */
+       if (dim + 1 < totdim) {
+               /* check that a sequence contains dimsize[dim] items */
+
                for (i= 0; i < PySequence_Length(seq); i++) {
                        PyObject *item;
                        int ok= 1;
                        item= PySequence_GetItem(seq, i);
 
                        if (!PySequence_Check(item)) {
-                               BLI_snprintf(error_str, error_str_size, "expected a %d-dimensional sequence of %s", (int)totdim, item_type_str);
+                               /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
+                               PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s", error_prefix, item_type_str);
                                ok= 0;
                        }
-                       else if (PySequence_Length(item) != dim_size[dim - 1]) {
-                               BLI_snprintf(error_str, error_str_size, "dimension %d should contain %d items", (int)dim, (int)dim_size[dim - 1]);
+                       /* arr[3][4][5]
+                          DIMSIZE(1)=4
+                          DIMSIZE(2)=5
+                  
+                          dim=0 */
+                       else if (PySequence_Length(item) != DIMSIZE(dim + 1)) {
+                               /* BLI_snprintf(error_str, error_str_size, "sequences of dimension %d should contain %d items", (int)dim + 1, (int)DIMSIZE(dim + 1)); */
+                               PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items", error_prefix, (int)dim + 1, (int)DIMSIZE(dim + 1));
                                ok= 0;
                        }
-
-                       if (!pyrna_validate_array(item, dim + 1, totdim, dim_size, check_item_type, item_type_str, error_str, error_str_size)) {
+                       else if (!validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix)) {
                                ok= 0;
                        }
 
@@ -67,13 +99,15 @@ static int pyrna_validate_array(PyObject *seq, unsigned short dim, unsigned shor
                }
        }
        else {
+               /* check that items are of correct type */
                for (i= 0; i < PySequence_Length(seq); i++) {
                        PyObject *item= PySequence_GetItem(seq, i);
 
                        if (!check_item_type(item)) {
                                Py_DECREF(item);
-                                                       
-                               BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str);
+
+                               /* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
+                               PyErr_Format(PyExc_TypeError, "sequence items should be of type %s", item_type_str);
                                return 0;
                        }
 
@@ -85,7 +119,7 @@ static int pyrna_validate_array(PyObject *seq, unsigned short dim, unsigned shor
 }
 
 /* Returns the number of items in a single- or multi-dimensional sequence. */
-static int pyrna_count_items(PyObject *seq)
+static int count_items(PyObject *seq)
 {
        int totitem= 0;
 
@@ -93,7 +127,7 @@ static int pyrna_count_items(PyObject *seq)
                int i;
                for (i= 0; i < PySequence_Length(seq); i++) {
                        PyObject *item= PySequence_GetItem(seq, i);
-                       totitem += pyrna_count_items(item);
+                       totitem += count_items(item);
                        Py_DECREF(item);
                }
        }
@@ -103,40 +137,103 @@ static int pyrna_count_items(PyObject *seq)
        return totitem;
 }
 
-static int pyrna_apply_array_length(PointerRNA *ptr, PropertyRNA *prop, int totitem, char *error_str, int error_str_size)
+/* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
+static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int *totitem, const char *error_prefix)
 {
-       if (RNA_property_flag(prop) & PROP_DYNAMIC) {
-               /* length can be flexible */
-               if (RNA_property_array_length(ptr, prop) != totitem) {
-                       if (!RNA_property_dynamic_array_set_length(ptr, prop, totitem)) {
-                               BLI_snprintf(error_str, error_str_size, "%s.%s: array length cannot be changed to %d", RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), totitem);
+       unsigned short dimsize[MAX_ARRAY_DIMENSION];
+       int tot, totdim, len;
+
+       tot= count_items(rvalue);
+       totdim= RNA_property_array_dimension(prop, dimsize);
+
+       if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
+               /* length is flexible */
+               if (RNA_property_array_length(ptr, prop) != tot) {
+                       if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
+                               /* BLI_snprintf(error_str, error_str_size, "%s.%s: array length cannot be changed to %d", RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot); */
+                               PyErr_Format(PyExc_ValueError, "%s %s.%s: array length cannot be changed to %d", error_prefix, RNA_struct_identifier(ptr->type), RNA_property_identifier(prop), tot);
                                return 0;
                        }
+
+                       len= tot;
                }
        }
        else {
                /* length is a constraint */
-               int len= RNA_property_array_length(ptr, prop);
-               if (totitem != len) {
-                       BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len);
+               if (!lvalue_dim) {
+                       len= RNA_property_array_length(ptr, prop);
+               }
+               /* array item assignment */
+               else {
+                       int i;
+
+                       len= 1;
+
+                       /* arr[3][4][5]
+
+                          arr[2] = x
+                          dimsize={4, 5}
+                          DIMSIZE(1) = 4
+                          DIMSIZE(2) = 5
+                          lvalue_dim=0, totdim=3
+
+                          arr[2][3] = x
+                          lvalue_dim=1
+
+                          arr[2][3][4] = x
+                          lvalue_dim=2 */
+                       for (i= lvalue_dim; i < totdim; i++)
+                               len *= DIMSIZE(i);
+               }
+
+               if (tot != len) {
+                       /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
+                       PyErr_Format(PyExc_ValueError, "%s sequence must have %d items total", error_prefix, len);
                        return 0;
                }
        }
+
+       *totitem= len;
+
        return 1;
 }
 
-static char *pyrna_py_to_array(PyObject *seq, unsigned short dim, unsigned short totdim, char *data, unsigned int item_size, ItemConvertFunc convert_item)
+static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *totitem, const char *error_prefix)
+{
+       unsigned short dimsize[MAX_ARRAY_DIMENSION];
+       int totdim= RNA_property_array_dimension(prop, dimsize);
+
+       /* validate type first because length validation may modify property array length */
+
+       if (!validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix))
+               return 0;
+
+       return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
+}
+
+static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, unsigned short dim, char *data, unsigned int item_size, int *index, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
 {
        unsigned int i;
+       int totdim= RNA_property_array_dimension(prop, NULL);
+
        for (i= 0; i < PySequence_Length(seq); i++) {
                PyObject *item= PySequence_GetItem(seq, i);
 
-               if (dim < totdim) {
-                       data= pyrna_py_to_array(item, dim + 1, totdim, data, item_size, convert_item);
+               if (dim + 1 < totdim) {
+                       data= copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
                }
                else {
-                       convert_item(item, data);
-                       data += item_size;
+                       if (!data) {
+                               char value[sizeof(int)];
+
+                               convert_item(item, value);
+                               rna_set_index(ptr, prop, *index, value);
+                               *index = *index + 1;
+                       }
+                       else {
+                               convert_item(item, data);
+                               data += item_size;
+                       }
                }
                        
                Py_DECREF(item);
@@ -145,21 +242,15 @@ static char *pyrna_py_to_array(PyObject *seq, unsigned short dim, unsigned short
        return data;
 }
 
-static int pyrna_py_to_array_generic(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size,
-                                                                        ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array)
+static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, ItemConvertFunc convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
 {
-       unsigned short totdim, dim_size[100];
+       unsigned short totdim, dim_size[MAX_ARRAY_DIMENSION];
        int totitem;
        char *data= NULL;
 
        totdim= RNA_property_array_dimension(prop, dim_size);
 
-       if (!pyrna_validate_array(py, 1, totdim, dim_size, check_item_type, item_type_str, error_str, error_str_size))
-               return 0;
-
-       totitem= pyrna_count_items(py);
-
-       if (!pyrna_apply_array_length(ptr, prop, totitem, error_str, error_str_size))
+       if (!validate_array(py, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix))
                return 0;
 
        if (totitem) {
@@ -168,7 +259,7 @@ static int pyrna_py_to_array_generic(PyObject *py, PointerRNA *ptr, PropertyRNA
                else
                        data= param_data;
 
-               pyrna_py_to_array(py, 1, totdim, data, item_size, convert_item);
+               copy_values(py, ptr, prop, 0, data, item_size, NULL, convert_item, NULL);
 
                if (param_data) {
                        if (RNA_property_flag(prop) & PROP_DYNAMIC) {
@@ -186,50 +277,236 @@ static int pyrna_py_to_array_generic(PyObject *py, PointerRNA *ptr, PropertyRNA
        return 1;
 }
 
-static void pyrna_py_to_float(PyObject *py, char *data)
+static int py_to_array_index(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int arrayoffset, int index, ItemTypeCheckFunc check_item_type, const char *item_type_str, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
+{
+       unsigned short totdim, dimsize[MAX_ARRAY_DIMENSION];
+       int totitem, i;
+
+       totdim= RNA_property_array_dimension(prop, dimsize);
+
+       /* convert index */
+
+       /* arr[3][4][5]
+
+          arr[2] = x
+          lvalue_dim=0, index = 0 + 2 * 4 * 5
+
+          arr[2][3] = x
+          lvalue_dim=1, index = 40 + 3 * 5 */
+
+       lvalue_dim++;
+
+       for (i= lvalue_dim; i < totdim; i++)
+               index *= DIMSIZE(i);
+
+       index += arrayoffset;
+
+       if (!validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix))
+               return 0;
+
+       if (totitem)
+               copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
+
+       return 1;
+}
+
+static void py_to_float(PyObject *py, char *data)
 {
        *(float*)data= (float)PyFloat_AsDouble(py);
 }
 
-static void pyrna_py_to_int(PyObject *py, char *data)
+static void py_to_int(PyObject *py, char *data)
 {
        *(int*)data= (int)PyLong_AsSsize_t(py);
 }
 
-static void pyrna_py_to_boolean(PyObject *py, char *data)
+static void py_to_bool(PyObject *py, char *data)
 {
        *(int*)data= (int)PyObject_IsTrue(py);
 }
 
 static int py_float_check(PyObject *py)
 {
-       return PyFloat_Check(py) || (PyIndex_Check(py));
+       /* accept both floats and integers */
+       return PyFloat_Check(py) || PyLong_Check(py);
 }
 
 static int py_int_check(PyObject *py)
 {
-       return PyLong_Check(py) || (PyIndex_Check(py));
+       /* accept only integers */
+       return PyLong_Check(py);
 }
 
 static int py_bool_check(PyObject *py)
 {
-       return PyBool_Check(py) || (PyIndex_Check(py));
+       return PyBool_Check(py);
+}
+
+static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
+{
+       RNA_property_float_set_index(ptr, prop, index, *(float*)value);
+}
+
+static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
+{
+       RNA_property_int_set_index(ptr, prop, index, *(int*)value);
+}
+
+static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
+{
+       RNA_property_boolean_set_index(ptr, prop, index, *(int*)value);
+}
+
+int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix)
+{
+       int ret;
+       switch (RNA_property_type(prop)) {
+       case PROP_FLOAT:
+               ret= py_to_array(py, ptr, prop, param_data, py_float_check, "float", sizeof(float), py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
+               break;
+       case PROP_INT:
+               ret= py_to_array(py, ptr, prop, param_data, py_int_check, "int", sizeof(int), py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
+               break;
+       case PROP_BOOLEAN:
+               ret= py_to_array(py, ptr, prop, param_data, py_bool_check, "boolean", sizeof(int), py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
+               break;
+       default:
+               PyErr_SetString(PyExc_TypeError, "not an array type");
+               ret= 0;
+       }
+
+       return ret;
 }
 
-int pyrna_py_to_float_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size)
+int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix)
 {
-       return pyrna_py_to_array_generic(py, ptr, prop, param_data, error_str, error_str_size,
-                                                                        py_float_check, "float", sizeof(float), pyrna_py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array);
+       int ret;
+       switch (RNA_property_type(prop)) {
+       case PROP_FLOAT:
+               ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_float_check, "float", py_to_float, float_set_index, error_prefix);
+               break;
+       case PROP_INT:
+               ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_int_check, "int", py_to_int, int_set_index, error_prefix);
+               break;
+       case PROP_BOOLEAN:
+               ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
+               break;
+       default:
+               PyErr_SetString(PyExc_TypeError, "not an array type");
+               ret= 0;
+       }
+
+       return ret;
 }
 
-int pyrna_py_to_int_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size)
+static PyObject *pyrna_array_item(PointerRNA *ptr, PropertyRNA *prop, int index)
 {
-       return pyrna_py_to_array_generic(py, ptr, prop, param_data, error_str, error_str_size,
-                                                                        py_int_check, "int", sizeof(int), pyrna_py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array);
+       PyObject *item;
+
+       switch (RNA_property_type(prop)) {
+       case PROP_FLOAT:
+               item= PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
+               break;
+       case PROP_BOOLEAN:
+               item= PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
+               break;
+       case PROP_INT:
+               item= PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index));
+               break;
+       default:
+               PyErr_SetString(PyExc_TypeError, "not an array type");
+               item= NULL;
+       }
+
+       return item;
 }
 
-int pyrna_py_to_boolean_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size)
+#if 0
+/* XXX this is not used (and never will?) */
+/* Given an array property, creates an N-dimensional tuple of values. */
+static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
 {
-       return pyrna_py_to_array_generic(py, ptr, prop, param_data, error_str, error_str_size,
-                                                                        py_bool_check, "boolean", sizeof(int), pyrna_py_to_boolean, (RNA_SetArrayFunc)RNA_property_boolean_set_array);
+       PyObject *tuple;
+       int i, len;
+       int totdim= RNA_property_array_dimension(prop, NULL);
+
+       len= RNA_property_multidimensional_array_length(ptr, prop, dim);
+
+       tuple= PyTuple_New(len);
+
+       for (i= 0; i < len; i++) {
+               PyObject *item;
+
+               if (dim + 1 < totdim)
+                       item= pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
+               else {
+                       item= pyrna_array_item(ptr, prop, *index);
+                       *index= *index + 1;
+               }
+
+               if (!item) {
+                       Py_DECREF(tuple);
+                       return NULL;
+               }
+
+               PyTuple_SetItem(tuple, i, item);
+       }
+
+       return tuple;
+}
+#endif
+
+PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index)
+{
+       int totdim, i, len;
+       unsigned short dimsize[MAX_ARRAY_DIMENSION];
+       BPy_PropertyRNA *ret= NULL;
+
+       /* just in case check */
+       len= RNA_property_multidimensional_array_length(&self->ptr, self->prop, self->arraydim);
+       if (index >= len || index < 0) {
+               /* this shouldn't happen because higher level funcs must check for invalid index */
+               if (G.f & G_DEBUG) printf("pyrna_py_from_array_index: invalid index %d for array with length=%d\n", index, len);
+
+               PyErr_SetString(PyExc_IndexError, "out of range");
+               return NULL;
+       }
+
+       totdim= RNA_property_array_dimension(self->prop, dimsize);
+
+       if (self->arraydim + 1 < totdim) {
+               ret= (BPy_PropertyRNA*)pyrna_prop_CreatePyObject(&self->ptr, self->prop);
+               ret->arraydim= self->arraydim + 1;
+
+               /* arr[3][4][5]
+
+                  x = arr[2]
+                  index = 0 + 2 * 4 * 5
+
+                  x = arr[2][3]
+                  index = offset + 3 * 5 */
+
+               for (i= self->arraydim + 1; i < totdim; i++)
+                       index *= DIMSIZE(i);
+
+               ret->arrayoffset= self->arrayoffset + index;
+       }
+       else {
+               index = self->arrayoffset + index;
+               ret= (BPy_PropertyRNA*)pyrna_array_item(&self->ptr, self->prop, index);
+       }
+
+       return (PyObject*)ret;
+}
+
+PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
+{
+       PyObject *ret;
+
+       ret= pyrna_math_object_from_array(ptr, prop);
+
+       /* is this a maths object? */
+       if (ret) return ret;
+
+       return pyrna_prop_CreatePyObject(ptr, prop);
 }
index 8ba3b5f8732e886ff3eee2505e0d0ac03ea24b4b..f2ffd5e0358eb85103efe6f3e777e6be7b438f82 100644 (file)
@@ -130,6 +130,70 @@ Mathutils_Callback mathutils_rna_matrix_cb = {
        (BaseMathSetIndexFunc)  NULL
 };
 
+PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
+{
+       PyObject *ret= NULL;
+
+#ifdef USE_MATHUTILS
+       int type, subtype, totdim;
+       int len;
+
+       len= RNA_property_array_length(ptr, prop);
+       type= RNA_property_type(prop);
+       subtype= RNA_property_subtype(prop);
+       totdim= RNA_property_array_dimension(prop, NULL);
+
+       if (type != PROP_FLOAT) return NULL;
+
+       if (totdim == 1 || (totdim == 2 && subtype == PROP_MATRIX)) {
+               ret = pyrna_prop_CreatePyObject(ptr, prop);
+
+               switch(RNA_property_subtype(prop)) {
+               case PROP_TRANSLATION:
+               case PROP_DIRECTION:
+               case PROP_VELOCITY:
+               case PROP_ACCELERATION:
+               case PROP_XYZ:
+                       if(len>=2 && len <= 4) {
+                               PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, FALSE);
+                               Py_DECREF(ret); /* the vector owns now */
+                               ret= vec_cb; /* return the vector instead */
+                       }
+                       break;
+               case PROP_MATRIX:
+                       if(len==16) {
+                               PyObject *mat_cb= newMatrixObject_cb(ret, 4,4, mathutils_rna_matrix_cb_index, FALSE);
+                               Py_DECREF(ret); /* the matrix owns now */
+                               ret= mat_cb; /* return the matrix instead */
+                       }
+                       else if (len==9) {
+                               PyObject *mat_cb= newMatrixObject_cb(ret, 3,3, mathutils_rna_matrix_cb_index, FALSE);
+                               Py_DECREF(ret); /* the matrix owns now */
+                               ret= mat_cb; /* return the matrix instead */
+                       }
+                       break;
+               case PROP_EULER:
+               case PROP_QUATERNION:
+                       if(len==3) { /* euler */
+                               PyObject *eul_cb= newEulerObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
+                               Py_DECREF(ret); /* the matrix owns now */
+                               ret= eul_cb; /* return the matrix instead */
+                       }
+                       else if (len==4) {
+                               PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
+                               Py_DECREF(ret); /* the matrix owns now */
+                               ret= quat_cb; /* return the matrix instead */
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+#endif
+
+       return ret;
+}
+
 #endif
 
 static StructRNA *pyrna_struct_as_srna(PyObject *self);
@@ -288,58 +352,7 @@ PyObject * pyrna_prop_to_py(PointerRNA *ptr, PropertyRNA *prop)
        int len = RNA_property_array_length(ptr, prop);
 
        if (len > 0) {
-               /* resolve the array from a new pytype */
-               PyObject *ret = pyrna_prop_CreatePyObject(ptr, prop);
-               
-#ifdef USE_MATHUTILS
-
-               /* return a mathutils vector where possible */
-               if(RNA_property_type(prop)==PROP_FLOAT) {
-                       switch(RNA_property_subtype(prop)) {
-                       case PROP_TRANSLATION:
-                       case PROP_DIRECTION:
-                       case PROP_VELOCITY:
-                       case PROP_ACCELERATION:
-                       case PROP_XYZ:
-                               if(len>=2 && len <= 4) {
-                                       PyObject *vec_cb= newVectorObject_cb(ret, len, mathutils_rna_array_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the vector owns now */
-                                       ret= vec_cb; /* return the vector instead */
-                               }
-                               break;
-                       case PROP_MATRIX:
-                               if(len==16) {
-                                       PyObject *mat_cb= newMatrixObject_cb(ret, 4,4, mathutils_rna_matrix_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the matrix owns now */
-                                       ret= mat_cb; /* return the matrix instead */
-                               }
-                               else if (len==9) {
-                                       PyObject *mat_cb= newMatrixObject_cb(ret, 3,3, mathutils_rna_matrix_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the matrix owns now */
-                                       ret= mat_cb; /* return the matrix instead */
-                               }
-                               break;
-                       case PROP_EULER:
-                       case PROP_QUATERNION:
-                               if(len==3) { /* euler */
-                                       PyObject *eul_cb= newEulerObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the matrix owns now */
-                                       ret= eul_cb; /* return the matrix instead */
-                               }
-                               else if (len==4) {
-                                       PyObject *quat_cb= newQuaternionObject_cb(ret, mathutils_rna_array_cb_index, FALSE);
-                                       Py_DECREF(ret); /* the matrix owns now */
-                                       ret= quat_cb; /* return the matrix instead */
-                               }
-                               break;
-                       default:
-                               break;
-                       }
-               }
-
-#endif
-               
-               return ret;
+               return pyrna_py_from_array(ptr, prop);
        }
        
        /* see if we can coorce into a python type - PropertyType */
@@ -511,7 +524,7 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
        int len = RNA_property_array_length(ptr, prop);
        
        if (len > 0) {
-               char error_str[512];
+               /* char error_str[512]; */
                int ok= 1;
 
 #ifdef USE_MATHUTILS
@@ -526,21 +539,10 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
                        return -1;
                }
                /* done getting the length */
-               
-               /* for arrays we have a limited number of types */
-               switch (type) {
-               case PROP_BOOLEAN:
-                       ok= pyrna_py_to_boolean_array(value, ptr, prop, data, error_str, sizeof(error_str));
-                       break;
-               case PROP_INT:
-                       ok= pyrna_py_to_int_array(value, ptr, prop, data, error_str, sizeof(error_str));
-                       break;
-               case PROP_FLOAT:
-                       ok= pyrna_py_to_float_array(value, ptr, prop, data, error_str, sizeof(error_str));
-                       break;
-               }
+               ok= pyrna_py_to_array(ptr, prop, data, value, error_prefix);
+
                if (!ok) {
-                       PyErr_Format(PyExc_AttributeError, "%.200s %s", error_prefix, error_str);
+                       /* PyErr_Format(PyExc_AttributeError, "%.200s %s", error_prefix, error_str); */
                        return -1;
                }
        }
@@ -733,82 +735,84 @@ int pyrna_py_to_prop(PointerRNA *ptr, PropertyRNA *prop, void *data, PyObject *v
        return 0;
 }
 
-static PyObject * pyrna_prop_to_py_index(PointerRNA *ptr, PropertyRNA *prop, int index)
+static PyObject * pyrna_prop_to_py_index(BPy_PropertyRNA *self, int index)
 {
-       PyObject *ret;
-       int type = RNA_property_type(prop);
-       
-       /* see if we can coorce into a python type - PropertyType */
-       switch (type) {
-       case PROP_BOOLEAN:
-               ret = PyBool_FromLong( RNA_property_boolean_get_index(ptr, prop, index) );
-               break;
-       case PROP_INT:
-               ret = PyLong_FromSsize_t( (Py_ssize_t)RNA_property_int_get_index(ptr, prop, index) );
-               break;
-       case PROP_FLOAT:
-               ret = PyFloat_FromDouble( RNA_property_float_get_index(ptr, prop, index) );
-               break;
-       default:
-               PyErr_SetString(PyExc_AttributeError, "not an array type");
-               ret = NULL;
-               break;
-       }
-       
-       return ret;
+       return pyrna_py_from_array_index(self, index);
 }
 
-static int pyrna_py_to_prop_index(PointerRNA *ptr, PropertyRNA *prop, int index, PyObject *value)
+static int pyrna_py_to_prop_index(BPy_PropertyRNA *self, int index, PyObject *value)
 {
        int ret = 0;
+       int totdim;
+       PointerRNA *ptr= &self->ptr;
+       PropertyRNA *prop= self->prop;
        int type = RNA_property_type(prop);
-       
-       /* see if we can coorce into a python type - PropertyType */
-       switch (type) {
-       case PROP_BOOLEAN:
-       {
-               int param = PyObject_IsTrue( value );
-               
-               if( param < 0 ) {
-                       PyErr_SetString(PyExc_TypeError, "expected True/False or 0/1");
-                       ret = -1;
-               } else {
-                       RNA_property_boolean_set_index(ptr, prop, index, param);
-               }
-               break;
-       }
-       case PROP_INT:
-       {
-               int param = PyLong_AsSsize_t(value);
-               if (PyErr_Occurred()) {
-                       PyErr_SetString(PyExc_TypeError, "expected an int type");
-                       ret = -1;
-               } else {
-                       RNA_property_int_set_index(ptr, prop, index, param);
+
+       totdim= RNA_property_array_dimension(prop, NULL);
+
+       if (totdim > 1) {
+               /* char error_str[512]; */
+               if (!pyrna_py_to_array_index(&self->ptr, self->prop, self->arraydim, self->arrayoffset, index, value, "")) {
+                       /* PyErr_SetString(PyExc_AttributeError, error_str); */
+                       ret= -1;
                }
-               break;
        }
-       case PROP_FLOAT:
-       {
-               float param = PyFloat_AsDouble(value);
-               if (PyErr_Occurred()) {
-                       PyErr_SetString(PyExc_TypeError, "expected a float type");
+       else {
+               /* see if we can coorce into a python type - PropertyType */
+               switch (type) {
+               case PROP_BOOLEAN:
+                       {
+                               int param = PyObject_IsTrue( value );
+               
+                               if( param < 0 ) {
+                                       PyErr_SetString(PyExc_TypeError, "expected True/False or 0/1");
+                                       ret = -1;
+                               } else {
+                                       RNA_property_boolean_set_index(ptr, prop, index, param);
+                               }
+                               break;
+                       }
+               case PROP_INT:
+                       {
+                               int param = PyLong_AsSsize_t(value);
+                               if (PyErr_Occurred()) {
+                                       PyErr_SetString(PyExc_TypeError, "expected an int type");
+                                       ret = -1;
+                               } else {
+                                       RNA_property_int_set_index(ptr, prop, index, param);
+                               }
+                               break;
+                       }
+               case PROP_FLOAT:
+                       {
+                               float param = PyFloat_AsDouble(value);
+                               if (PyErr_Occurred()) {
+                                       PyErr_SetString(PyExc_TypeError, "expected a float type");
+                                       ret = -1;
+                               } else {
+                                       RNA_property_float_set_index(ptr, prop, index, param);
+                               }
+                               break;
+                       }
+               default:
+                       PyErr_SetString(PyExc_AttributeError, "not an array type");
                        ret = -1;
-               } else {
-                       RNA_property_float_set_index(ptr, prop, index, param);
+                       break;
                }
-               break;
-       }
-       default:
-               PyErr_SetString(PyExc_AttributeError, "not an array type");
-               ret = -1;
-               break;
        }
        
        return ret;
 }
 
 //---------------sequence-------------------------------------------
+static int pyrna_prop_array_length(BPy_PropertyRNA *self)
+{
+       if (RNA_property_array_dimension(self->prop, NULL) > 1)
+               return RNA_property_multidimensional_array_length(&self->ptr, self->prop, self->arraydim);
+       else
+               return RNA_property_array_length(&self->ptr, self->prop);
+}
+
 static Py_ssize_t pyrna_prop_len( BPy_PropertyRNA * self )
 {
        Py_ssize_t len;
@@ -816,10 +820,10 @@ static Py_ssize_t pyrna_prop_len( BPy_PropertyRNA * self )
        if (RNA_property_type(self->prop) == PROP_COLLECTION) {
                len = RNA_property_collection_length(&self->ptr, self->prop);
        } else {
-               len = RNA_property_array_length(&self->ptr, self->prop);
+               len = pyrna_prop_array_length(self);
                
                if (len==0) { /* not an array*/
-                       PyErr_SetString(PyExc_AttributeError, "len() only available for collection RNA types");
+                       PyErr_SetString(PyExc_AttributeError, "len() only available for collection and array RNA types");
                        return -1;
                }
        }
@@ -840,14 +844,15 @@ static PyObject *prop_subscript_collection_int(BPy_PropertyRNA * self, int keynu
        PyErr_Format(PyExc_IndexError, "index %d out of range", keynum);
        return NULL;
 }
+
 static PyObject *prop_subscript_array_int(BPy_PropertyRNA * self, int keynum)
 {
-       int len= RNA_property_array_length(&self->ptr, self->prop);
+       int len= pyrna_prop_array_length(self);
 
        if(keynum < 0) keynum += len;
 
        if(keynum >= 0 && keynum < len)
-               return pyrna_prop_to_py_index(&self->ptr, self->prop, keynum);
+               return pyrna_prop_to_py_index(self, keynum);
 
        PyErr_Format(PyExc_IndexError, "index %d out of range", keynum);
        return NULL;
@@ -894,7 +899,7 @@ static PyObject *prop_subscript_array_slice(BPy_PropertyRNA * self, int start, i
        start = MIN2(start,stop); /* values are clamped from PySlice_GetIndicesEx */
 
        for(count = start; count < stop; count++)
-               PyList_SetItem(list, count - start, pyrna_prop_to_py_index(&self->ptr, self->prop, count));
+               PyList_SetItem(list, count - start, pyrna_prop_to_py_index(self, count));
 
        return list;
 }
@@ -947,8 +952,8 @@ static PyObject *prop_subscript_array(BPy_PropertyRNA * self, PyObject *key)
                return prop_subscript_array_int(self, PyLong_AsSsize_t(key));
        }
        else if (PySlice_Check(key)) {
-               int len= RNA_property_array_length(&self->ptr, self->prop);
                Py_ssize_t start, stop, step, slicelength;
+               int len = pyrna_prop_array_length(self);
 
                if (PySlice_GetIndicesEx((PySliceObject*)key, len, &start, &stop, &step, &slicelength) < 0)
                        return NULL;
@@ -974,13 +979,12 @@ static PyObject *pyrna_prop_subscript( BPy_PropertyRNA * self, PyObject *key )
 {
        if (RNA_property_type(self->prop) == PROP_COLLECTION) {
                return prop_subscript_collection(self, key);
-       } else if (RNA_property_array_length(&self->ptr, self->prop)) { /* arrays are currently fixed length, zero length means its not an array */
+       } else if (RNA_property_array_length(&self->ptr, self->prop)) { /* zero length means its not an array */
                return prop_subscript_array(self, key);
-       } else {
-               PyErr_SetString(PyExc_TypeError, "rna type is not an array or a collection");
-               return NULL;
-       }
+       } 
 
+       PyErr_SetString(PyExc_TypeError, "rna type is not an array or a collection");
+       return NULL;
 }
 
 static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int end, PyObject *value)
@@ -991,7 +995,7 @@ static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int
        begin = MIN2(begin,end);
 
        for(count = begin; count < end; count++) {
-               if(pyrna_py_to_prop_index(&self->ptr, self->prop, count - begin, value) == -1) {
+               if(pyrna_py_to_prop_index(self, count - begin, value) == -1) {
                        /* TODO - this is wrong since some values have been assigned... will need to fix that */
                        return -1; /* pyrna_struct_CreatePyObject should set the error */
                }
@@ -1002,13 +1006,12 @@ static int prop_subscript_ass_array_slice(BPy_PropertyRNA * self, int begin, int
 
 static int prop_subscript_ass_array_int(BPy_PropertyRNA * self, int keynum, PyObject *value)
 {
-
-       int len= RNA_property_array_length(&self->ptr, self->prop);
+       int len= pyrna_prop_array_length(self);
 
        if(keynum < 0) keynum += len;
 
        if(keynum >= 0 && keynum < len)
-               return pyrna_py_to_prop_index(&self->ptr, self->prop, keynum, value);
+               return pyrna_py_to_prop_index(self, keynum, value);
 
        PyErr_SetString(PyExc_IndexError, "out of range");
        return -1;
@@ -1682,7 +1685,7 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self)
        
        if (ret==NULL) {
                /* collection did not work, try array */
-               int len = RNA_property_array_length(&self->ptr, self->prop);
+               int len = pyrna_prop_array_length(self);
                
                if (len) {
                        int i;
@@ -1690,7 +1693,7 @@ PyObject *pyrna_prop_iter(BPy_PropertyRNA *self)
                        ret = PyList_New(len);
                        
                        for (i=0; i < len; i++) {
-                               PyList_SET_ITEM(ret, i, pyrna_prop_to_py_index(&self->ptr, self->prop, i));
+                               PyList_SET_ITEM(ret, i, pyrna_prop_to_py_index(self, i));
                        }
                }
        }
@@ -1781,6 +1784,8 @@ PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *data)
                /* resolve the array from a new pytype */
                ret = PyTuple_New(len);
 
+               /* kazanbas: TODO make multidim sequences here */
+
                switch (type) {
                case PROP_BOOLEAN:
                        for(a=0; a<len; a++)
@@ -2445,6 +2450,9 @@ PyObject *pyrna_prop_CreatePyObject( PointerRNA *ptr, PropertyRNA *prop )
        
        pyrna->ptr = *ptr;
        pyrna->prop = prop;
+
+       pyrna->arraydim= 0;
+       pyrna->arrayoffset= 0;
                
        return ( PyObject * ) pyrna;
 }
index d65849ad8a4f78ecdfc3e6d742291b72d499da4e..d006b168f458c12bb26fb73bdd922289416f8cf7 100644 (file)
@@ -55,6 +55,10 @@ typedef struct {
        PyObject_HEAD /* required python macro   */
        PointerRNA ptr;
        PropertyRNA *prop;
+
+       /* Arystan: this is a hack to allow sub-item r/w access like: face.uv[n][m] */
+       int arraydim; /* array dimension, e.g: 0 for face.uv, 2 for face.uv[n][m], etc. */
+       int arrayoffset; /* array first item offset, e.g. if face.uv is [4][2], arrayoffset for face.uv[n] is 2n */
 } BPy_PropertyRNA;
 
 /* cheap trick */
@@ -92,8 +96,11 @@ void pyrna_alloc_types(void);
 void pyrna_free_types(void);
 
 /* primitive type conversion */
-int pyrna_py_to_boolean_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size);
-int pyrna_py_to_int_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size);
-int pyrna_py_to_float_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size);
+int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix);
+int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix);
+
+PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop);
+PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index);
+PyObject *pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop);
 
 #endif
index 580a457e3a09cd7cdedbaf9b40722aac57331d39..7cadab992b860e01ca6fdda5df5965fef9405e40 100755 (executable)
@@ -91,7 +91,7 @@ def validate_arguments(args, bc):
                        'BF_BSC', 'BF_CONFIG',
                        'BF_PRIORITYLIST', 'BF_BUILDINFO','CC', 'CXX', 'BF_QUICKDEBUG',
                        'BF_LISTDEBUG', 'LCGDIR', 'BF_X264_CONFIG', 'BF_XVIDCORE_CONFIG',
-                       'BF_DOCDIR']
+                       'BF_DOCDIR', 'BF_UNIT_TEST']
 
        okdict = {}
 
@@ -386,7 +386,9 @@ def read_opts(cfg, args):
                
                ('BF_CONFIG', 'SCons python config file used to set default options', 'user_config.py'),
                ('BF_NUMJOBS', 'Number of build processes to spawn', '1'),
-               ('BF_MSVS', 'Generate MSVS project files and solution', False)
+               ('BF_MSVS', 'Generate MSVS project files and solution', False),
+
+               (BoolVariable('BF_UNIT_TEST', 'Build with unit test support.', False))
 
        ) # end of opts.AddOptions()