Manual merge of soc-2009-kazanbas branch:
[blender.git] / source / blender / python / intern / bpy_array.c
1 /**
2  * 
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
19  *
20  * Contributor(s): Arystanbek Dyussenov
21  *
22  * ***** END GPL LICENSE BLOCK *****
23  */
24
25 #include "Python.h"
26
27 #include "bpy_rna.h"
28
29 #include "RNA_access.h"
30
31 #include "BLI_string.h"
32
33 #include "BKE_global.h"
34
35 #include "MEM_guardedalloc.h"
36
37 #define MAX_ARRAY_DIMENSION 10
38
39 typedef void (*ItemConvertFunc)(PyObject *, char *);
40 typedef int  (*ItemTypeCheckFunc)(PyObject *);
41 typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
42 typedef void (*RNA_SetIndexFunc)(PointerRNA *, PropertyRNA *, int index, void *);
43
44 /*
45   arr[3][4][5]
46       0  1  2  <- dimension index
47 */
48
49 /*
50   arr[2] = x
51
52   py_to_array_index(arraydim=0, arrayoffset=0, index=2)
53     validate_array(lvalue_dim=0)
54     ... make real index ...
55 */
56
57 /* arr[3]=x, self->arraydim is 0, lvalue_dim is 1 */
58 /* Ensures that a python sequence has expected number of items/sub-items and items are of desired type. */
59 static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[],
60                                                            ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
61 {
62         int i;
63
64         /* not the last dimension */
65         if (dim + 1 < totdim) {
66                 /* check that a sequence contains dimsize[dim] items */
67
68                 for (i= 0; i < PySequence_Length(seq); i++) {
69                         PyObject *item;
70                         int ok= 1;
71                         item= PySequence_GetItem(seq, i);
72
73                         if (!PySequence_Check(item)) {
74                                 /* BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str); */
75                                 PyErr_Format(PyExc_TypeError, "%s expected a sequence of %s", error_prefix, item_type_str);
76                                 ok= 0;
77                         }
78                         /* arr[3][4][5]
79                            dimsize[1]=4
80                            dimsize[2]=5
81                    
82                            dim=0 */
83                         else if (PySequence_Length(item) != dimsize[dim + 1]) {
84                                 /* BLI_snprintf(error_str, error_str_size, "sequences of dimension %d should contain %d items", (int)dim + 1, (int)dimsize[dim + 1]); */
85                                 PyErr_Format(PyExc_ValueError, "%s sequences of dimension %d should contain %d items", error_prefix, (int)dim + 1, (int)dimsize[dim + 1]);
86                                 ok= 0;
87                         }
88                         else if (!validate_array_type(item, dim + 1, totdim, dimsize, check_item_type, item_type_str, error_prefix)) {
89                                 ok= 0;
90                         }
91
92                         Py_DECREF(item);
93
94                         if (!ok)
95                                 return 0;
96                 }
97         }
98         else {
99                 /* check that items are of correct type */
100                 for (i= 0; i < PySequence_Length(seq); i++) {
101                         PyObject *item= PySequence_GetItem(seq, i);
102
103                         if (!check_item_type(item)) {
104                                 Py_DECREF(item);
105
106                                 /* BLI_snprintf(error_str, error_str_size, "sequence items should be of type %s", item_type_str); */
107                                 PyErr_Format(PyExc_TypeError, "sequence items should be of type %s", item_type_str);
108                                 return 0;
109                         }
110
111                         Py_DECREF(item);
112                 }
113         }
114
115         return 1;
116 }
117
118 /* Returns the number of items in a single- or multi-dimensional sequence. */
119 static int count_items(PyObject *seq)
120 {
121         int totitem= 0;
122
123         if (PySequence_Check(seq)) {
124                 int i;
125                 for (i= 0; i < PySequence_Length(seq); i++) {
126                         PyObject *item= PySequence_GetItem(seq, i);
127                         totitem += count_items(item);
128                         Py_DECREF(item);
129                 }
130         }
131         else
132                 totitem= 1;
133
134         return totitem;
135 }
136
137 /* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
138 static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, int lvalue_dim, int *totitem, const char *error_prefix)
139 {
140         int dimsize[MAX_ARRAY_DIMENSION];
141         int tot, totdim, len;
142
143         tot= count_items(rvalue);
144         totdim= RNA_property_array_dimension(ptr, prop, dimsize);
145
146         if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
147                 if (RNA_property_array_length(ptr, prop) != tot) {
148 #if 0
149                         /* length is flexible */
150                         if (!RNA_property_dynamic_array_set_length(ptr, prop, tot)) {
151                                 /* 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); */
152                                 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);
153                                 return 0;
154                         }
155 #else
156                         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);
157                         return 0;
158 #endif
159                 }
160
161                 len= tot;
162         }
163         else {
164                 /* length is a constraint */
165                 if (!lvalue_dim) {
166                         len= RNA_property_array_length(ptr, prop);
167                 }
168                 /* array item assignment */
169                 else {
170                         int i;
171
172                         len= 1;
173
174                         /* arr[3][4][5]
175
176                            arr[2] = x
177                            dimsize={4, 5}
178                            dimsize[1] = 4
179                            dimsize[2] = 5
180                            lvalue_dim=0, totdim=3
181
182                            arr[2][3] = x
183                            lvalue_dim=1
184
185                            arr[2][3][4] = x
186                            lvalue_dim=2 */
187                         for (i= lvalue_dim; i < totdim; i++)
188                                 len *= dimsize[i];
189                 }
190
191                 if (tot != len) {
192                         /* BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len); */
193                         PyErr_Format(PyExc_ValueError, "%s sequence must have %d items total", error_prefix, len);
194                         return 0;
195                 }
196         }
197
198         *totitem= len;
199
200         return 1;
201 }
202
203 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)
204 {
205         int dimsize[MAX_ARRAY_DIMENSION];
206         int totdim= RNA_property_array_dimension(ptr, prop, dimsize);
207
208         /* validate type first because length validation may modify property array length */
209
210         if (!validate_array_type(rvalue, lvalue_dim, totdim, dimsize, check_item_type, item_type_str, error_prefix))
211                 return 0;
212
213         return validate_array_length(rvalue, ptr, prop, lvalue_dim, totitem, error_prefix);
214 }
215
216 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)
217 {
218         unsigned int i;
219         int totdim= RNA_property_array_dimension(ptr, prop, NULL);
220
221         for (i= 0; i < PySequence_Length(seq); i++) {
222                 PyObject *item= PySequence_GetItem(seq, i);
223
224                 if (dim + 1 < totdim) {
225                         data= copy_values(item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
226                 }
227                 else {
228                         if (!data) {
229                                 char value[sizeof(int)];
230
231                                 convert_item(item, value);
232                                 rna_set_index(ptr, prop, *index, value);
233                                 *index = *index + 1;
234                         }
235                         else {
236                                 convert_item(item, data);
237                                 data += item_size;
238                         }
239                 }
240                         
241                 Py_DECREF(item);
242         }
243
244         return data;
245 }
246
247 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)
248 {
249         int totdim, dim_size[MAX_ARRAY_DIMENSION];
250         int totitem;
251         char *data= NULL;
252
253         totdim= RNA_property_array_dimension(ptr, prop, dim_size);
254
255         if (!validate_array(py, ptr, prop, 0, check_item_type, item_type_str, &totitem, error_prefix)) {
256                 return 0;
257         }
258
259         if (totitem) {
260                 if (!param_data || RNA_property_flag(prop) & PROP_DYNAMIC)
261                         data= MEM_callocN(item_size * totitem, "pyrna primitive type array");
262                 else
263                         data= param_data;
264
265                 copy_values(py, ptr, prop, 0, data, item_size, NULL, convert_item, NULL);
266
267                 if (param_data) {
268                         if (RNA_property_flag(prop) & PROP_DYNAMIC) {
269                                 /* not freeing allocated mem, RNA_parameter_list_free will do this */
270                                 *(char**)param_data= data;
271                         }
272                 }
273                 else {
274                         /* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
275                         rna_set_array(ptr, prop, data);
276                         MEM_freeN(data);
277                 }
278         }
279
280         return 1;
281 }
282
283 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)
284 {
285         int totdim, dimsize[MAX_ARRAY_DIMENSION];
286         int totitem, i;
287
288         totdim= RNA_property_array_dimension(ptr, prop, dimsize);
289
290         /* convert index */
291
292         /* arr[3][4][5]
293
294            arr[2] = x
295            lvalue_dim=0, index = 0 + 2 * 4 * 5
296
297            arr[2][3] = x
298            lvalue_dim=1, index = 40 + 3 * 5 */
299
300         lvalue_dim++;
301
302         for (i= lvalue_dim; i < totdim; i++)
303                 index *= dimsize[i];
304
305         index += arrayoffset;
306
307         if (!validate_array(py, ptr, prop, lvalue_dim, check_item_type, item_type_str, &totitem, error_prefix))
308                 return 0;
309
310         if (totitem)
311                 copy_values(py, ptr, prop, lvalue_dim, NULL, 0, &index, convert_item, rna_set_index);
312
313         return 1;
314 }
315
316 static void py_to_float(PyObject *py, char *data)
317 {
318         *(float*)data= (float)PyFloat_AsDouble(py);
319 }
320
321 static void py_to_int(PyObject *py, char *data)
322 {
323         *(int*)data= (int)PyLong_AsSsize_t(py);
324 }
325
326 static void py_to_bool(PyObject *py, char *data)
327 {
328         *(int*)data= (int)PyObject_IsTrue(py);
329 }
330
331 static int py_float_check(PyObject *py)
332 {
333         /* accept both floats and integers */
334         return PyFloat_Check(py) || PyLong_Check(py);
335 }
336
337 static int py_int_check(PyObject *py)
338 {
339         /* accept only integers */
340         return PyLong_Check(py);
341 }
342
343 static int py_bool_check(PyObject *py)
344 {
345         return PyBool_Check(py);
346 }
347
348 static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
349 {
350         RNA_property_float_set_index(ptr, prop, index, *(float*)value);
351 }
352
353 static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
354 {
355         RNA_property_int_set_index(ptr, prop, index, *(int*)value);
356 }
357
358 static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
359 {
360         RNA_property_boolean_set_index(ptr, prop, index, *(int*)value);
361 }
362
363 int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix)
364 {
365         int ret;
366         switch (RNA_property_type(prop)) {
367         case PROP_FLOAT:
368                 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);
369                 break;
370         case PROP_INT:
371                 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);
372                 break;
373         case PROP_BOOLEAN:
374                 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);
375                 break;
376         default:
377                 PyErr_SetString(PyExc_TypeError, "not an array type");
378                 ret= 0;
379         }
380
381         return ret;
382 }
383
384 int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix)
385 {
386         int ret;
387         switch (RNA_property_type(prop)) {
388         case PROP_FLOAT:
389                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_float_check, "float", py_to_float, float_set_index, error_prefix);
390                 break;
391         case PROP_INT:
392                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_int_check, "int", py_to_int, int_set_index, error_prefix);
393                 break;
394         case PROP_BOOLEAN:
395                 ret= py_to_array_index(py, ptr, prop, arraydim, arrayoffset, index, py_bool_check, "boolean", py_to_bool, bool_set_index, error_prefix);
396                 break;
397         default:
398                 PyErr_SetString(PyExc_TypeError, "not an array type");
399                 ret= 0;
400         }
401
402         return ret;
403 }
404
405 static PyObject *pyrna_array_item(PointerRNA *ptr, PropertyRNA *prop, int index)
406 {
407         PyObject *item;
408
409         switch (RNA_property_type(prop)) {
410         case PROP_FLOAT:
411                 item= PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
412                 break;
413         case PROP_BOOLEAN:
414                 item= PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
415                 break;
416         case PROP_INT:
417                 item= PyLong_FromSsize_t(RNA_property_int_get_index(ptr, prop, index));
418                 break;
419         default:
420                 PyErr_SetString(PyExc_TypeError, "not an array type");
421                 item= NULL;
422         }
423
424         return item;
425 }
426
427 #if 0
428 /* XXX this is not used (and never will?) */
429 /* Given an array property, creates an N-dimensional tuple of values. */
430 static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr, PropertyRNA *prop, int dim, int *index)
431 {
432         PyObject *tuple;
433         int i, len;
434         int totdim= RNA_property_array_dimension(ptr, prop, NULL);
435
436         len= RNA_property_multi_array_length(ptr, prop, dim);
437
438         tuple= PyTuple_New(len);
439
440         for (i= 0; i < len; i++) {
441                 PyObject *item;
442
443                 if (dim + 1 < totdim)
444                         item= pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
445                 else {
446                         item= pyrna_array_item(ptr, prop, *index);
447                         *index= *index + 1;
448                 }
449
450                 if (!item) {
451                         Py_DECREF(tuple);
452                         return NULL;
453                 }
454
455                 PyTuple_SetItem(tuple, i, item);
456         }
457
458         return tuple;
459 }
460 #endif
461
462 PyObject *pyrna_py_from_array_index(BPy_PropertyRNA *self, int index)
463 {
464         int totdim, i, len;
465         int dimsize[MAX_ARRAY_DIMENSION];
466         BPy_PropertyRNA *ret= NULL;
467
468         /* just in case check */
469         len= RNA_property_multi_array_length(&self->ptr, self->prop, self->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(&self->ptr, self->prop, dimsize);
479
480         if (self->arraydim + 1 < totdim) {
481                 ret= (BPy_PropertyRNA*)pyrna_prop_CreatePyObject(&self->ptr, self->prop);
482                 ret->arraydim= self->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= self->arraydim + 1; i < totdim; i++)
493                         index *= dimsize[i];
494
495                 ret->arrayoffset= self->arrayoffset + index;
496         }
497         else {
498                 index = self->arrayoffset + index;
499                 ret= (BPy_PropertyRNA*)pyrna_array_item(&self->ptr, self->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 }