rna support for passing dynamic sized arrays to rna functions
[blender.git] / source / blender / python / intern / bpy_array.c
1 /**
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * Contributor(s): Arystanbek Dyussenov
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include "bpy_rna.h"
26 #include "BKE_global.h"
27 #include "MEM_guardedalloc.h"
28
29 #define MAX_ARRAY_DIMENSION 10
30
31 typedef void (*ItemConvertFunc)(PyObject *, char *);
32 typedef int  (*ItemTypeCheckFunc)(PyObject *);
33 typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
34 typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
35
36 /*
37   arr[3][4][5]
38           0  1  2  <- dimension index
39 */
40
41 /*
42   arr[2] = x
43
44   py_to_array_index(arraydim=0, arrayoffset=0, index=2)
45         validate_array(lvalue_dim=0)
46         ... make real index ...
47 */
48
49 /* arr[3]=x, self->arraydim is 0, lvalue_dim is 1 */
50 /* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
51 static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[],
52                                                            ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
53 {
54         int i;
55
56         /* not the last dimension */
57         if (dim + 1 < totdim) {
58                 /* check that a sequence contains dimsize[dim] items */
59
60                 for (i= 0; i < PySequence_Length(seq); i++) {
61                         PyObject *item;
62                         int ok= 1;
63                         item= PySequence_GetItem(seq, i);
64
65                         if (!PySequence_Check(item)) {
66                                 /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
67                                 PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s", error_prefix, item_type_str);
68                                 ok= 0;
69                         }
70                         /* arr[3][4][5]
71                            dimsize[1]=4
72                            dimsize[2]=5
73                    
74                            dim=0 */
75                         else if (PySequence_Length(item) != dimsize[dim + 1]) {
76                                 /* BLI_snprintf(error_str, error_str_size, "sequences of dimension %d should contain %d items", (int)dim + 1, (int)dimsize[dim + 1]); */
77                                 PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items", error_prefix, (int)dim + 1, (int)dimsize[dim + 1]);
78                                 ok= 0;
79                         }
80                         else if (!validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix)) {
81                                 ok= 0;
82                         }
83
84                         Py_DECREF(item);
85
86                         if (!ok)
87                                 return 0;
88                 }
89         }
90         else {
91                 /* check that items are of correct type */
92                 for (i= 0; i < PySequence_Length(seq); i++) {
93                         PyObject *item= PySequence_GetItem(seq, i);
94
95                         if (!check_item_type(item)) {
96                                 Py_DECREF(item);
97
98                                 /* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
99                                 PyErr_Format(PyExc_TypeError, "sequence items should be of type %s", item_type_str);
100                                 return 0;
101                         }
102
103                         Py_DECREF(item);
104                 }
105         }
106
107         return 1;
108 }
109
110 /* Returns the number of items in a single- or multi-dimensional sequence. */
111 static int count_items(PyObject *seq)
112 {
113         int totitem= 0;
114
115         if (PySequence_Check(seq)) {
116                 int i;
117                 for (i= 0; i < PySequence_Length(seq); i++) {
118                         PyObject *item= PySequence_GetItem(seq, i);
119                         totitem += count_items(item);
120                         Py_DECREF(item);
121                 }
122         }
123         else
124                 totitem= 1;
125
126         return totitem;
127 }
128
129 /* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
130 static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int *totitem, const char *error_prefix)
131 {
132         int dimsize[MAX_ARRAY_DIMENSION];
133         int tot, totdim, len;
134
135         tot= count_items(rvalue);
136         totdim= RNA_property_array_dimension(ptr, prop, dimsize);
137
138         if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
139                 if (RNA_property_array_length(ptr, prop) != tot) {
140 #if 0
141                         /* length is flexible */
142                         if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
143                                 /* 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); */
144                                 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);
145                                 return 0;
146                         }
147 #else
148                         *totitem= tot;
149                         return 1;
150
151 #endif
152                 }
153
154                 len= tot;
155         }
156         else {
157                 /* length is a constraint */
158                 if (!lvalue_dim) {
159                         len= RNA_property_array_length(ptr, prop);
160                 }
161                 /* array item assignment */
162                 else {
163                         int i;
164
165                         len= 1;
166
167                         /* arr[3][4][5]
168
169                            arr[2] = x
170                            dimsize={4, 5}
171                            dimsize[1] = 4
172                            dimsize[2] = 5
173                            lvalue_dim=0, totdim=3
174
175                            arr[2][3] = x
176                            lvalue_dim=1
177
178                            arr[2][3][4] = x
179                            lvalue_dim=2 */
180                         for (i= lvalue_dim; i < totdim; i++)
181                                 len *= dimsize[i];
182                 }
183
184                 if (tot != len) {
185                         /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
186                         PyErr_Format(PyExc_ValueError, "%s sequence must have %d items total", error_prefix, len);
187                         return 0;
188                 }
189         }
190
191         *totitem= len;
192
193         return 1;
194 }
195
196 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)
197 {
198         int dimsize[MAX_ARRAY_DIMENSION];
199         int totdim= RNA_property_array_dimension(ptr, prop, dimsize);
200
201         /* validate type first because length validation may modify property array length */
202
203         if (!validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix))
204                 return 0;
205
206         return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
207 }
208
209 static char *copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, int dim, char *data, unsigned int item_size, int *index, ItemConvertFunc convert_item, RNA_SetIndexFunc rna_set_index)
210 {
211         unsigned int i;
212         int totdim= RNA_property_array_dimension(ptr, prop, NULL);
213
214         for (i= 0; i < PySequence_Length(seq); i++) {
215                 PyObject *item= PySequence_GetItem(seq, i);
216
217                 if (dim + 1 < totdim) {
218                         data= copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
219                 }
220                 else {
221                         if (!data) {
222                                 char value[sizeof(int)];
223
224                                 convert_item(item, value);
225                                 rna_set_index(ptr, prop, *index, value);
226                                 *index = *index + 1;
227                         }
228                         else {
229                                 convert_item(item, data);
230                                 data += item_size;
231                         }
232                 }
233                         
234                 Py_DECREF(item);
235         }
236
237         return data;
238 }
239
240 static int py_to_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, 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)
241 {
242         int totdim, dim_size[MAX_ARRAY_DIMENSION];
243         int totitem;
244         char *data= NULL;
245
246         totdim= RNA_property_array_dimension(ptr, prop, dim_size);
247
248         if (!validate_array(py, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix)) {
249                 return 0;
250         }
251
252         if (totitem) {
253                 /* note: this code is confusing */
254                 if(param_data && RNA_property_flag(prop) & PROP_DYNAMIC) {
255                         /* not freeing allocated mem, RNA_parameter_list_free() will do this */
256                         ParameterDynAlloc *param_alloc= (ParameterDynAlloc *)param_data;
257                         param_alloc->array_tot= (int)totitem;
258                         param_alloc->array= MEM_callocN(item_size * totitem, "py_to_array dyn"); /* freeing param list will free */
259
260                         data= param_alloc->array;
261                 }
262                 else if (param_data) {
263                         data= param_data;
264                 }
265                 else {
266                         data= PyMem_MALLOC(item_size * totitem);
267                 }
268
269                 copy_values(py, ptr, prop, 0, data, item_size, NULL, convert_item, NULL);
270
271                 if (param_data==NULL) {
272                         /* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
273                         rna_set_array(ptr, prop, data);
274                         PyMem_FREE(data);
275                 }
276         }
277
278         return 1;
279 }
280
281 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)
282 {
283         int totdim, dimsize[MAX_ARRAY_DIMENSION];
284         int totitem, i;
285
286         totdim= RNA_property_array_dimension(ptr, prop, dimsize);
287
288         /* convert index */
289
290         /* arr[3][4][5]
291
292            arr[2] = x
293            lvalue_dim=0, index = 0 + 2 * 4 * 5
294
295            arr[2][3] = x
296            lvalue_dim=1, index = 40 + 3 * 5 */
297
298         lvalue_dim++;
299
300         for (i= lvalue_dim; i < totdim; i++)
301                 index *= dimsize[i];
302
303         index += arrayoffset;
304
305         if (!validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix))
306                 return 0;
307
308         if (totitem)
309                 copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
310
311         return 1;
312 }
313
314 static void py_to_float(PyObject *py, char *data)
315 {
316         *(float*)data= (float)PyFloat_AsDouble(py);
317 }
318
319 static void py_to_int(PyObject *py, char *data)
320 {
321         *(int*)data= (int)PyLong_AsSsize_t(py);
322 }
323
324 static void py_to_bool(PyObject *py, char *data)
325 {
326         *(int*)data= (int)PyObject_IsTrue(py);
327 }
328
329 static int py_float_check(PyObject *py)
330 {
331         /* accept both floats and integers */
332         return PyFloat_Check(py) || PyLong_Check(py);
333 }
334
335 static int py_int_check(PyObject *py)
336 {
337         /* accept only integers */
338         return PyLong_Check(py);
339 }
340
341 static int py_bool_check(PyObject *py)
342 {
343         return PyBool_Check(py);
344 }
345
346 static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
347 {
348         RNA_property_float_set_index(ptr, prop, index, *(float*)value);
349 }
350
351 static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
352 {
353         RNA_property_int_set_index(ptr, prop, index, *(int*)value);
354 }
355
356 static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
357 {
358         RNA_property_boolean_set_index(ptr, prop, index, *(int*)value);
359 }
360
361 int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, ParameterList *parms, char *param_data, PyObject *py, const char *error_prefix)
362 {
363         int ret;
364         switch (RNA_property_type(prop)) {
365         case PROP_FLOAT:
366                 ret= py_to_array(py, ptr, prop, parms, param_data, py_float_check, "float", sizeof(float), py_to_float, (RNA_SetArrayFunc)RNA_property_float_set_array, error_prefix);
367                 break;
368         case PROP_INT:
369                 ret= py_to_array(py, ptr, prop, parms, param_data, py_int_check, "int", sizeof(int), py_to_int, (RNA_SetArrayFunc)RNA_property_int_set_array, error_prefix);
370                 break;
371         case PROP_BOOLEAN:
372                 ret= py_to_array(py, ptr, prop, parms, param_data, py_bool_check, "boolean", sizeof(int), py_to_bool, (RNA_SetArrayFunc)RNA_property_boolean_set_array, error_prefix);
373                 break;
374         default:
375                 PyErr_SetString(PyExc_TypeError, "not an array type");
376                 ret= 0;
377         }
378
379         return ret;
380 }
381
382 int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix)
383 {
384         int ret;
385         switch (RNA_property_type(prop)) {
386         case PROP_FLOAT:
387                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_float_check, "float", py_to_float, float_set_index, error_prefix);
388                 break;
389         case PROP_INT:
390                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_int_check, "int", py_to_int, int_set_index, error_prefix);
391                 break;
392         case PROP_BOOLEAN:
393                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
394                 break;
395         default:
396                 PyErr_SetString(PyExc_TypeError, "not an array type");
397                 ret= 0;
398         }
399
400         return ret;
401 }
402
403 static PyObject *pyrna_array_item(PointerRNA *ptr, PropertyRNA *prop, int index)
404 {
405         PyObject *item;
406
407         switch (RNA_property_type(prop)) {
408         case PROP_FLOAT:
409                 item= PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
410                 break;
411         case PROP_BOOLEAN:
412                 item= PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
413                 break;
414         case PROP_INT:
415                 item= PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index));
416                 break;
417         default:
418                 PyErr_SetString(PyExc_TypeError, "not an array type");
419                 item= NULL;
420         }
421
422         return item;
423 }
424
425 #if 0
426 /* XXX this is not used (and never will?) */
427 /* Given an array property, creates an N-dimensional tuple of values. */
428 static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
429 {
430         PyObject *tuple;
431         int i, len;
432         int totdim= RNA_property_array_dimension(ptr, prop, NULL);
433
434         len= RNA_property_multi_array_length(ptr, prop, dim);
435
436         tuple= PyTuple_New(len);
437
438         for (i= 0; i < len; i++) {
439                 PyObject *item;
440
441                 if (dim + 1 < totdim)
442                         item= pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
443                 else {
444                         item= pyrna_array_item(ptr, prop, *index);
445                         *index= *index + 1;
446                 }
447
448                 if (!item) {
449                         Py_DECREF(tuple);
450                         return NULL;
451                 }
452
453                 PyTuple_SetItem(tuple, i, item);
454         }
455
456         return tuple;
457 }
458 #endif
459
460 PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
461 {
462         int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
463         BPy_PropertyRNA *ret= NULL;
464
465         arraydim= self ? self->arraydim : 0;
466         arrayoffset = self ? self->arrayoffset : 0;
467
468         /* just in case check */
469         len= RNA_property_multi_array_length(ptr, prop, arraydim);
470         if (index >= len || index < 0) {
471                 /* this shouldn't happen because higher level funcs must check for invalid index */
472                 if (G.f & G_DEBUG) printf("pyrna_py_from_array_index: invalid index %d for array with length=%d\n", index, len);
473
474                 PyErr_SetString(PyExc_IndexError, "out of range");
475                 return NULL;
476         }
477
478         totdim= RNA_property_array_dimension(ptr, prop, dimsize);
479
480         if (arraydim + 1 < totdim) {
481                 ret= (BPy_PropertyRNA*)pyrna_prop_CreatePyObject(ptr, prop);
482                 ret->arraydim= arraydim + 1;
483
484                 /* arr[3][4][5]
485
486                    x = arr[2]
487                    index = 0 + 2 * 4 * 5
488
489                    x = arr[2][3]
490                    index = offset + 3 * 5 */
491
492                 for (i= arraydim + 1; i < totdim; i++)
493                         index *= dimsize[i];
494
495                 ret->arrayoffset= arrayoffset + index;
496         }
497         else {
498                 index = arrayoffset + index;
499                 ret= (BPy_PropertyRNA*)pyrna_array_item(ptr, prop, index);
500         }
501
502         return (PyObject*)ret;
503 }
504
505 PyObject *pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
506 {
507         PyObject *ret;
508
509         ret= pyrna_math_object_from_array(ptr, prop);
510
511         /* is this a maths object? */
512         if (ret) return ret;
513
514         return pyrna_prop_CreatePyObject(ptr, prop);
515 }
516
517 /* TODO, multi-dimensional arrays */
518 int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
519 {
520         int len= RNA_property_array_length(ptr, prop);
521         int type;
522         int i;
523
524         if(len==0) /* possible with dynamic arrays */
525                 return 0;
526
527         if (RNA_property_array_dimension(ptr, prop, NULL) > 1) {
528                 PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
529                 return -1;
530         }
531
532         type= RNA_property_type(prop);
533
534         switch (type) {
535                 case PROP_FLOAT:
536                 {
537                         float value_f= PyFloat_AsDouble(value);
538                         if(value_f==-1 && PyErr_Occurred()) {
539                                 PyErr_Clear();
540                                 return 0;
541                         }
542                         else {
543                                 float tmp[32];
544                                 float *tmp_arr;
545
546                                 if(len * sizeof(float) > sizeof(tmp)) {
547                                         tmp_arr= PyMem_MALLOC(len * sizeof(float));
548                                 }
549                                 else {
550                                         tmp_arr= tmp;
551                                 }
552
553                                 RNA_property_float_get_array(ptr, prop, tmp_arr);
554
555                                 for(i=0; i<len; i++)
556                                         if(tmp_arr[i] == value_f)
557                                                 break;
558
559                                 if(tmp_arr != tmp)
560                                         PyMem_FREE(tmp_arr);
561
562                                 return i<len ? 1 : 0;
563                         }
564                         break;
565                 }
566                 case PROP_BOOLEAN:
567                 case PROP_INT:
568                 {
569                         int value_i= PyLong_AsSsize_t(value);
570                         if(value_i==-1 && PyErr_Occurred()) {
571                                 PyErr_Clear();
572                                 return 0;
573                         }
574                         else {
575                                 int tmp[32];
576                                 int *tmp_arr;
577
578                                 if(len * sizeof(int) > sizeof(tmp)) {
579                                         tmp_arr= PyMem_MALLOC(len * sizeof(int));
580                                 }
581                                 else {
582                                         tmp_arr= tmp;
583                                 }
584
585                                 if(type==PROP_BOOLEAN)
586                                         RNA_property_boolean_get_array(ptr, prop, tmp_arr);
587                                 else
588                                         RNA_property_int_get_array(ptr, prop, tmp_arr);
589
590                                 for(i=0; i<len; i++)
591                                         if(tmp_arr[i] == value_i)
592                                                 break;
593
594                                 if(tmp_arr != tmp)
595                                         PyMem_FREE(tmp_arr);
596
597                                 return i<len ? 1 : 0;
598                         }
599                         break;
600                 }
601         }
602
603         /* should never reach this */
604         PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
605         return -1;
606 }