Blender V4.3
bpy_rna_array.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
11#include <Python.h>
12
13#include "CLG_log.h"
14
15#include "BLI_utildefines.h"
16
17#include "RNA_types.hh"
18
19#include "bpy_rna.hh"
20
21#include "MEM_guardedalloc.h"
22
23#include "RNA_access.hh"
24
25#include "BPY_extern_clog.hh"
26
28
29#define USE_MATHUTILS
30
31#ifdef USE_MATHUTILS
32# include "../mathutils/mathutils.hh" /* so we can have mathutils callbacks */
33#endif
34
35#define MAX_ARRAY_DIMENSION 10
36
38
39using ItemConvertFunc = void (*)(const ItemConvertArgData *arg, PyObject *py_data, char *data);
40using ItemTypeCheckFunc = int (*)(PyObject *py_data);
41using RNA_SetArrayFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, const char *data);
42using RNA_SetIndexFunc = void (*)(PointerRNA *ptr, PropertyRNA *prop, int index, void *data_item);
43
45 union {
46 struct {
47 int range[2];
49 struct {
50 float range[2];
52 };
53};
54
62
63/*
64 * arr[3][4][5]
65 * 0 1 2 <- dimension index
66 */
67
68/*
69 * arr[2] = x
70 *
71 * py_to_array_index(arraydim=0, arrayoffset=0, index=2)
72 * validate_array(lvalue_dim=0)
73 * ... make real index ...
74 */
75
76/* arr[3] = x, self->arraydim is 0, lvalue_dim is 1 */
77/* Ensures that a python sequence has expected number of
78 * items/sub-items and items are of desired type. */
79static int validate_array_type(PyObject *seq,
80 int dim,
81 int totdim,
82 int dimsize[],
83 const bool is_dynamic,
84 ItemTypeCheckFunc check_item_type,
85 const char *item_type_str,
86 const char *error_prefix)
87{
88 Py_ssize_t i;
89
90 /* not the last dimension */
91 if (dim + 1 < totdim) {
92 /* check that a sequence contains dimsize[dim] items */
93 const int seq_size = PySequence_Size(seq);
94 if (seq_size == -1) {
95 PyErr_Format(PyExc_ValueError,
96 "%s sequence expected at dimension %d, not '%s'",
97 error_prefix,
98 dim + 1,
99 Py_TYPE(seq)->tp_name);
100 return -1;
101 }
102 for (i = 0; i < seq_size; i++) {
103 Py_ssize_t item_seq_size;
104 PyObject *item;
105 bool ok = true;
106 item = PySequence_GetItem(seq, i);
107
108 if (item == nullptr) {
109 PyErr_Format(PyExc_TypeError,
110 "%s sequence type '%s' failed to retrieve index %d",
111 error_prefix,
112 Py_TYPE(seq)->tp_name,
113 i);
114 ok = false;
115 }
116 else if ((item_seq_size = PySequence_Size(item)) == -1) {
117 // BLI_snprintf(error_str, error_str_size, "expected a sequence of %s", item_type_str);
118 PyErr_Format(PyExc_TypeError,
119 "%s expected a sequence of %s, not %s",
120 error_prefix,
121 item_type_str,
122 Py_TYPE(item)->tp_name);
123 ok = false;
124 }
125 /* arr[3][4][5]
126 * dimsize[1] = 4
127 * dimsize[2] = 5
128 *
129 * dim = 0 */
130 else if (item_seq_size != dimsize[dim + 1]) {
131 /* BLI_snprintf(error_str, error_str_size,
132 * "sequences of dimension %d should contain %d items",
133 * dim + 1, dimsize[dim + 1]); */
134 PyErr_Format(PyExc_ValueError,
135 "%s sequences of dimension %d should contain %d items, not %d",
136 error_prefix,
137 dim + 1,
138 dimsize[dim + 1],
139 item_seq_size);
140 ok = false;
141 }
142 else if (validate_array_type(item,
143 dim + 1,
144 totdim,
145 dimsize,
146 is_dynamic,
147 check_item_type,
148 item_type_str,
149 error_prefix) == -1)
150 {
151 ok = false;
152 }
153
154 Py_XDECREF(item);
155
156 if (!ok) {
157 return -1;
158 }
159 }
160 }
161 else {
162 /* check that items are of correct type */
163 const int seq_size = PySequence_Size(seq);
164 if (seq_size == -1) {
165 PyErr_Format(PyExc_ValueError,
166 "%s sequence expected at dimension %d, not '%s'",
167 error_prefix,
168 dim + 1,
169 Py_TYPE(seq)->tp_name);
170 return -1;
171 }
172 if ((seq_size != dimsize[dim]) && (is_dynamic == false)) {
173 PyErr_Format(PyExc_ValueError,
174 "%s sequences of dimension %d should contain %d items, not %d",
175 error_prefix,
176 dim,
177 dimsize[dim],
178 seq_size);
179 return -1;
180 }
181
182 for (i = 0; i < seq_size; i++) {
183 PyObject *item = PySequence_GetItem(seq, i);
184
185 if (item == nullptr) {
186 PyErr_Format(PyExc_TypeError,
187 "%s sequence type '%s' failed to retrieve index %d",
188 error_prefix,
189 Py_TYPE(seq)->tp_name,
190 i);
191 return -1;
192 }
193 if (!check_item_type(item)) {
194 Py_DECREF(item);
195
196#if 0
197 SNPRINTF(error_str, "sequence items should be of type %s", item_type_str);
198#endif
199 PyErr_Format(PyExc_TypeError,
200 "%s expected sequence items of type %s, not %s",
201 error_prefix,
202 item_type_str,
203 Py_TYPE(item)->tp_name);
204 return -1;
205 }
206
207 Py_DECREF(item);
208 }
209 }
210
211 return 0; /* ok */
212}
213
214/* Returns the number of items in a single- or multi-dimensional sequence. */
215static int count_items(PyObject *seq, int dim)
216{
217 int totitem = 0;
218
219 if (dim > 1) {
220 const Py_ssize_t seq_size = PySequence_Size(seq);
221 Py_ssize_t i;
222 for (i = 0; i < seq_size; i++) {
223 PyObject *item = PySequence_GetItem(seq, i);
224 if (item) {
225 const int tot = count_items(item, dim - 1);
226 Py_DECREF(item);
227 if (tot != -1) {
228 totitem += tot;
229 }
230 else {
231 totitem = -1;
232 break;
233 }
234 }
235 else {
236 totitem = -1;
237 break;
238 }
239 }
240 }
241 else {
242 totitem = PySequence_Size(seq);
243 }
244
245 return totitem;
246}
247
248/* Modifies property array length if needed and PROP_DYNAMIC flag is set. */
249static int validate_array_length(PyObject *rvalue,
251 PropertyRNA *prop,
252 const bool prop_is_param_dyn_alloc,
253 int lvalue_dim,
254 int *r_totitem,
255 const char *error_prefix)
256{
257 int dimsize[MAX_ARRAY_DIMENSION];
258 int tot, totdim, len;
259
260 totdim = RNA_property_array_dimension(ptr, prop, dimsize);
261 tot = count_items(rvalue, totdim - lvalue_dim);
262
263 if (tot == -1) {
264 PyErr_Format(PyExc_ValueError,
265 "%s %.200s.%.200s, error validating the sequence length",
266 error_prefix,
269 return -1;
270 }
271 if ((RNA_property_flag(prop) & PROP_DYNAMIC) && lvalue_dim == 0) {
272 const int tot_expected = RNA_property_array_length(ptr, prop);
273 if (tot_expected != tot) {
274 *r_totitem = tot;
275 if (!prop_is_param_dyn_alloc) {
276 PyErr_Format(PyExc_ValueError,
277 "%s %s.%s: array length cannot be changed to %d (expected %d)",
278 error_prefix,
281 tot,
282 tot_expected);
283 return -1;
284 }
285 return 0;
286 }
287
288 len = tot;
289 }
290 else {
291 /* length is a constraint */
292 if (!lvalue_dim) {
294 }
295 /* array item assignment */
296 else {
297 int i;
298
299 len = 1;
300
301 /* arr[3][4][5]
302 *
303 * arr[2] = x
304 * dimsize = {4, 5}
305 * dimsize[1] = 4
306 * dimsize[2] = 5
307 * lvalue_dim = 0, totdim = 3
308 *
309 * arr[2][3] = x
310 * lvalue_dim = 1
311 *
312 * arr[2][3][4] = x
313 * lvalue_dim = 2 */
314 for (i = lvalue_dim; i < totdim; i++) {
315 len *= dimsize[i];
316 }
317 }
318
319 if (tot != len) {
320 // BLI_snprintf(error_str, error_str_size, "sequence must have length of %d", len);
321 PyErr_Format(PyExc_ValueError,
322 "%s %.200s.%.200s, sequence must have %d items total, not %d",
323 error_prefix,
326 len,
327 tot);
328 return -1;
329 }
330 }
331
332 *r_totitem = len;
333
334 return 0;
335}
336
337static int validate_array(PyObject *rvalue,
339 PropertyRNA *prop,
340 const bool prop_is_param_dyn_alloc,
341 int lvalue_dim,
342 ItemTypeCheckFunc check_item_type,
343 const char *item_type_str,
344 int *r_totitem,
345 const char *error_prefix)
346{
347 int dimsize[MAX_ARRAY_DIMENSION];
348 const int totdim = RNA_property_array_dimension(ptr, prop, dimsize);
349
350 /* validate type first because length validation may modify property array length */
351
352#ifdef USE_MATHUTILS
353 if (lvalue_dim == 0) { /* only valid for first level array */
354 if (MatrixObject_Check(rvalue)) {
355 MatrixObject *pymat = (MatrixObject *)rvalue;
356
357 if (BaseMath_ReadCallback(pymat) == -1) {
358 return -1;
359 }
360
361 if (RNA_property_type(prop) != PROP_FLOAT) {
362 PyErr_Format(PyExc_ValueError,
363 "%s %.200s.%.200s, matrix assign to non float array",
364 error_prefix,
367 return -1;
368 }
369 if (totdim != 2) {
370 PyErr_Format(PyExc_ValueError,
371 "%s %.200s.%.200s, matrix assign array with %d dimensions",
372 error_prefix,
375 totdim);
376 return -1;
377 }
378 if (pymat->col_num != dimsize[0] || pymat->row_num != dimsize[1]) {
379 PyErr_Format(PyExc_ValueError,
380 "%s %.200s.%.200s, matrix assign dimension size mismatch, "
381 "is %dx%d, expected be %dx%d",
382 error_prefix,
385 pymat->col_num,
386 pymat->row_num,
387 dimsize[0],
388 dimsize[1]);
389 return -1;
390 }
391
392 *r_totitem = dimsize[0] * dimsize[1];
393 return 0;
394 }
395 }
396#endif /* USE_MATHUTILS */
397
398 {
399 const int prop_flag = RNA_property_flag(prop);
400 if (validate_array_type(rvalue,
401 lvalue_dim,
402 totdim,
403 dimsize,
404 (prop_flag & PROP_DYNAMIC) != 0,
405 check_item_type,
406 item_type_str,
407 error_prefix) == -1)
408 {
409 return -1;
410 }
411
413 rvalue, ptr, prop, prop_is_param_dyn_alloc, lvalue_dim, r_totitem, error_prefix);
414 }
415}
416
417static char *copy_value_single(PyObject *item,
419 PropertyRNA *prop,
420 char *data,
421 uint item_size,
422 int *index,
423 const ItemConvert_FuncArg *convert_item,
424 RNA_SetIndexFunc rna_set_index)
425{
426 if (!data) {
427 union {
428 float fl;
429 int i;
430 } value_buf;
431 char *value = static_cast<char *>((void *)&value_buf);
432
433 convert_item->func(&convert_item->arg, item, value);
434 rna_set_index(ptr, prop, *index, value);
435 (*index) += 1;
436 }
437 else {
438 convert_item->func(&convert_item->arg, item, data);
439 data += item_size;
440 }
441
442 return data;
443}
444
445static char *copy_values(PyObject *seq,
447 PropertyRNA *prop,
448 int dim,
449 char *data,
450 uint item_size,
451 int *index,
452 const ItemConvert_FuncArg *convert_item,
453 RNA_SetIndexFunc rna_set_index)
454{
455 const int totdim = RNA_property_array_dimension(ptr, prop, nullptr);
456 const Py_ssize_t seq_size = PySequence_Size(seq);
457 Py_ssize_t i;
458
459 /* Regarding PySequence_GetItem() failing.
460 *
461 * This should never be nullptr since we validated it, _but_ some tricky python
462 * developer could write their own sequence type which succeeds on
463 * validating but fails later somehow, so include checks for safety.
464 */
465
466 /* Note that 'data can be nullptr' */
467
468 if (seq_size == -1) {
469 return nullptr;
470 }
471
472#ifdef USE_MATHUTILS
473 if (dim == 0) {
474 if (MatrixObject_Check(seq)) {
475 MatrixObject *pymat = (MatrixObject *)seq;
476 const size_t allocsize = pymat->col_num * pymat->row_num * sizeof(float);
477
478 /* read callback already done by validate */
479 /* since this is the first iteration we can assume data is allocated */
480 memcpy(data, pymat->matrix, allocsize);
481
482 /* not really needed but do for completeness */
483 data += allocsize;
484
485 return data;
486 }
487 }
488#endif /* USE_MATHUTILS */
489
490 for (i = 0; i < seq_size; i++) {
491 PyObject *item = PySequence_GetItem(seq, i);
492 if (item) {
493 if (dim + 1 < totdim) {
494 data = copy_values(
495 item, ptr, prop, dim + 1, data, item_size, index, convert_item, rna_set_index);
496 }
497 else {
498 data = copy_value_single(
499 item, ptr, prop, data, item_size, index, convert_item, rna_set_index);
500 }
501
502 Py_DECREF(item);
503
504 /* data may be nullptr, but the for loop checks */
505 }
506 else {
507 return nullptr;
508 }
509 }
510
511 return data;
512}
513
514static int py_to_array(PyObject *seq,
516 PropertyRNA *prop,
517 char *param_data,
518 ItemTypeCheckFunc check_item_type,
519 const char *item_type_str,
520 int item_size,
521 const ItemConvert_FuncArg *convert_item,
522 RNA_SetArrayFunc rna_set_array,
523 const char *error_prefix)
524{
525 // int totdim, dim_size[MAX_ARRAY_DIMENSION];
526 int totitem;
527 char *data = nullptr;
528
529 // totdim = RNA_property_array_dimension(ptr, prop, dim_size); /* UNUSED */
530 const int flag = RNA_property_flag(prop);
531
532 /* Use #ParameterDynAlloc which defines its own array length. */
533 const bool prop_is_param_dyn_alloc = param_data && (flag & PROP_DYNAMIC);
534
535 if (validate_array(seq,
536 ptr,
537 prop,
538 prop_is_param_dyn_alloc,
539 0,
540 check_item_type,
541 item_type_str,
542 &totitem,
543 error_prefix) == -1)
544 {
545 return -1;
546 }
547
548 if (totitem) {
549 /* NOTE: this code is confusing. */
550 if (prop_is_param_dyn_alloc) {
551 /* not freeing allocated mem, RNA_parameter_list_free() will do this */
552 ParameterDynAlloc *param_alloc = (ParameterDynAlloc *)param_data;
553 param_alloc->array_tot = int(totitem);
554
555 /* freeing param list will free */
556 param_alloc->array = MEM_callocN(item_size * totitem, "py_to_array dyn");
557
558 data = static_cast<char *>(param_alloc->array);
559 }
560 else if (param_data) {
561 data = param_data;
562 }
563 else {
564 data = static_cast<char *>(PyMem_MALLOC(item_size * totitem));
565 }
566
567 /* will only fail in very rare cases since we already validated the
568 * python data, the check here is mainly for completeness. */
569 if (copy_values(seq, ptr, prop, 0, data, item_size, nullptr, convert_item, nullptr) != nullptr)
570 {
571 if (param_data == nullptr) {
572 /* nullptr can only pass through in case RNA property array-length is 0 (impossible?) */
573 rna_set_array(ptr, prop, data);
574 PyMem_FREE(data);
575 }
576 }
577 else {
578 if (param_data == nullptr) {
579 PyMem_FREE(data);
580 }
581
582 PyErr_Format(PyExc_TypeError,
583 "%s internal error parsing sequence of type '%s' after successful validation",
584 error_prefix,
585 Py_TYPE(seq)->tp_name);
586 return -1;
587 }
588 }
589
590 return 0;
591}
592
593static int py_to_array_index(PyObject *py,
595 PropertyRNA *prop,
596 int lvalue_dim,
597 int arrayoffset,
598 int index,
599 ItemTypeCheckFunc check_item_type,
600 const char *item_type_str,
601 const ItemConvert_FuncArg *convert_item,
602 RNA_SetIndexFunc rna_set_index,
603 const char *error_prefix)
604{
605 int totdim, dimsize[MAX_ARRAY_DIMENSION];
606 int totitem, i;
607
608 totdim = RNA_property_array_dimension(ptr, prop, dimsize);
609
610 /* convert index */
611
612 /* arr[3][4][5]
613 *
614 * arr[2] = x
615 * lvalue_dim = 0, index = 0 + 2 * 4 * 5
616 *
617 * arr[2][3] = x
618 * lvalue_dim = 1, index = 40 + 3 * 5 */
619
620 lvalue_dim++;
621
622 for (i = lvalue_dim; i < totdim; i++) {
623 index *= dimsize[i];
624 }
625
626 index += arrayoffset;
627
628 if (lvalue_dim == totdim) { /* single item, assign directly */
629 if (!check_item_type(py)) {
630 PyErr_Format(PyExc_TypeError,
631 "%s %.200s.%.200s, expected a %s type, not %s",
632 error_prefix,
635 item_type_str,
636 Py_TYPE(py)->tp_name);
637 return -1;
638 }
639 copy_value_single(py, ptr, prop, nullptr, 0, &index, convert_item, rna_set_index);
640 }
641 else {
642 const bool prop_is_param_dyn_alloc = false;
643 if (validate_array(py,
644 ptr,
645 prop,
646 prop_is_param_dyn_alloc,
647 lvalue_dim,
648 check_item_type,
649 item_type_str,
650 &totitem,
651 error_prefix) == -1)
652 {
653 return -1;
654 }
655
656 if (totitem) {
657 copy_values(py, ptr, prop, lvalue_dim, nullptr, 0, &index, convert_item, rna_set_index);
658 }
659 }
660 return 0;
661}
662
663static void py_to_float(const ItemConvertArgData *arg, PyObject *py, char *data)
664{
665 const float *range = arg->float_data.range;
666 float value = float(PyFloat_AsDouble(py));
667 CLAMP(value, range[0], range[1]);
668 *(float *)data = value;
669}
670
671static void py_to_int(const ItemConvertArgData *arg, PyObject *py, char *data)
672{
673 const int *range = arg->int_data.range;
674 int value = PyC_Long_AsI32(py);
675 CLAMP(value, range[0], range[1]);
676 *(int *)data = value;
677}
678
679static void py_to_bool(const ItemConvertArgData * /*arg*/, PyObject *py, char *data)
680{
681 *(bool *)data = bool(PyObject_IsTrue(py));
682}
683
684static int py_float_check(PyObject *py)
685{
686 /* accept both floats and integers */
687 return PyNumber_Check(py);
688}
689
690static int py_int_check(PyObject *py)
691{
692 /* accept only integers */
693 return PyLong_Check(py);
694}
695
696static int py_bool_check(PyObject *py)
697{
698 return PyBool_Check(py);
699}
700
701static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
702{
703 RNA_property_float_set_index(ptr, prop, index, *(float *)value);
704}
705
706static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
707{
708 RNA_property_int_set_index(ptr, prop, index, *(int *)value);
709}
710
711static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
712{
713 RNA_property_boolean_set_index(ptr, prop, index, *(bool *)value);
714}
715
717 PropertyRNA *prop,
718 ItemConvert_FuncArg *convert_item)
719{
720 float *range = convert_item->arg.float_data.range;
721 convert_item->func = py_to_float;
722 RNA_property_float_range(ptr, prop, &range[0], &range[1]);
723}
724
726 PropertyRNA *prop,
727 ItemConvert_FuncArg *convert_item)
728{
729 int *range = convert_item->arg.int_data.range;
730 convert_item->func = py_to_int;
731 RNA_property_int_range(ptr, prop, &range[0], &range[1]);
732}
733
734static void convert_item_init_bool(PointerRNA * /*ptr*/,
735 PropertyRNA * /*prop*/,
736 ItemConvert_FuncArg *convert_item)
737{
738 convert_item->func = py_to_bool;
739}
740
742 PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix)
743{
744 int ret;
745 switch (RNA_property_type(prop)) {
746 case PROP_FLOAT: {
747 ItemConvert_FuncArg convert_item;
748 convert_item_init_float(ptr, prop, &convert_item);
749
750 ret = py_to_array(py,
751 ptr,
752 prop,
753 param_data,
755 "float",
756 sizeof(float),
757 &convert_item,
759 error_prefix);
760 break;
761 }
762 case PROP_INT: {
763 ItemConvert_FuncArg convert_item;
764 convert_item_init_int(ptr, prop, &convert_item);
765
766 ret = py_to_array(py,
767 ptr,
768 prop,
769 param_data,
771 "int",
772 sizeof(int),
773 &convert_item,
775 error_prefix);
776 break;
777 }
778 case PROP_BOOLEAN: {
779 ItemConvert_FuncArg convert_item;
780 convert_item_init_bool(ptr, prop, &convert_item);
781
782 ret = py_to_array(py,
783 ptr,
784 prop,
785 param_data,
787 "boolean",
788 sizeof(bool),
789 &convert_item,
791 error_prefix);
792 break;
793 }
794 default: {
795 PyErr_SetString(PyExc_TypeError, "not an array type");
796 ret = -1;
797 break;
798 }
799 }
800
801 return ret;
802}
803
805 PropertyRNA *prop,
806 int arraydim,
807 int arrayoffset,
808 int index,
809 PyObject *py,
810 const char *error_prefix)
811{
812 int ret;
813 switch (RNA_property_type(prop)) {
814 case PROP_FLOAT: {
815 ItemConvert_FuncArg convert_item;
816 convert_item_init_float(ptr, prop, &convert_item);
817
819 ptr,
820 prop,
821 arraydim,
822 arrayoffset,
823 index,
825 "float",
826 &convert_item,
828 error_prefix);
829 break;
830 }
831 case PROP_INT: {
832 ItemConvert_FuncArg convert_item;
833 convert_item_init_int(ptr, prop, &convert_item);
834
836 ptr,
837 prop,
838 arraydim,
839 arrayoffset,
840 index,
842 "int",
843 &convert_item,
845 error_prefix);
846 break;
847 }
848 case PROP_BOOLEAN: {
849 ItemConvert_FuncArg convert_item;
850 convert_item_init_bool(ptr, prop, &convert_item);
851
853 ptr,
854 prop,
855 arraydim,
856 arrayoffset,
857 index,
859 "boolean",
860 &convert_item,
862 error_prefix);
863 break;
864 }
865 default: {
866 PyErr_SetString(PyExc_TypeError, "not an array type");
867 ret = -1;
868 break;
869 }
870 }
871
872 return ret;
873}
874
875PyObject *pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
876{
877 PyObject *item;
878
879 switch (RNA_property_type(prop)) {
880 case PROP_FLOAT:
881 item = PyFloat_FromDouble(RNA_property_float_get_index(ptr, prop, index));
882 break;
883 case PROP_BOOLEAN:
884 item = PyBool_FromLong(RNA_property_boolean_get_index(ptr, prop, index));
885 break;
886 case PROP_INT:
887 item = PyLong_FromLong(RNA_property_int_get_index(ptr, prop, index));
888 break;
889 default:
890 PyErr_SetString(PyExc_TypeError, "not an array type");
891 item = nullptr;
892 break;
893 }
894
895 return item;
896}
897
898#if 0
899/* XXX this is not used (and never will?) */
900/* Given an array property, creates an N-dimensional tuple of values. */
901static PyObject *pyrna_py_from_array_internal(PointerRNA *ptr,
902 PropertyRNA *prop,
903 int dim,
904 int *index)
905{
906 PyObject *tuple;
907 int i, len;
908 int totdim = RNA_property_array_dimension(ptr, prop, nullptr);
909
911
912 tuple = PyTuple_New(len);
913
914 for (i = 0; i < len; i++) {
915 PyObject *item;
916
917 if (dim + 1 < totdim) {
918 item = pyrna_py_from_array_internal(ptr, prop, dim + 1, index);
919 }
920 else {
921 item = pyrna_array_index(ptr, prop, *index);
922 *index = *index + 1;
923 }
924
925 if (!item) {
926 Py_DECREF(tuple);
927 return nullptr;
928 }
929
930 PyTuple_SET_ITEM(tuple, i, item);
931 }
932
933 return tuple;
934}
935#endif
936
939 PropertyRNA *prop,
940 int index)
941{
942 int totdim, arraydim, arrayoffset, dimsize[MAX_ARRAY_DIMENSION], i, len;
943 BPy_PropertyArrayRNA *ret = nullptr;
944
945 arraydim = self ? self->arraydim : 0;
946 arrayoffset = self ? self->arrayoffset : 0;
947
948 /* just in case check */
949 len = RNA_property_multi_array_length(ptr, prop, arraydim);
950 if (index >= len || index < 0) {
951 /* This shouldn't happen because higher level functions must check for invalid index. */
952 CLOG_WARN(BPY_LOG_RNA, "invalid index %d for array with length=%d", index, len);
953
954 PyErr_SetString(PyExc_IndexError, "out of range");
955 return nullptr;
956 }
957
958 totdim = RNA_property_array_dimension(ptr, prop, dimsize);
959
960 if (arraydim + 1 < totdim) {
962 ret->arraydim = arraydim + 1;
963
964 /* arr[3][4][5]
965 *
966 * x = arr[2]
967 * index = 0 + 2 * 4 * 5
968 *
969 * x = arr[2][3]
970 * index = offset + 3 * 5 */
971
972 for (i = arraydim + 1; i < totdim; i++) {
973 index *= dimsize[i];
974 }
975
976 ret->arrayoffset = arrayoffset + index;
977 }
978 else {
979 index = arrayoffset + index;
981 }
982
983 return (PyObject *)ret;
984}
985
987{
988 PyObject *ret;
989
991
992 /* is this a maths object? */
993 if (ret) {
994 return ret;
995 }
996
997 return pyrna_prop_CreatePyObject(ptr, prop);
998}
999
1001{
1002 /* TODO: multi-dimensional arrays. */
1003
1004 const int len = RNA_property_array_length(ptr, prop);
1005 int type;
1006 int i;
1007
1008 if (len == 0) {
1009 /* possible with dynamic arrays */
1010 return 0;
1011 }
1012
1013 if (RNA_property_array_dimension(ptr, prop, nullptr) > 1) {
1014 PyErr_SetString(PyExc_TypeError, "PropertyRNA - multi dimensional arrays not supported yet");
1015 return -1;
1016 }
1017
1018 type = RNA_property_type(prop);
1019
1020 switch (type) {
1021 case PROP_FLOAT: {
1022 const float value_f = PyFloat_AsDouble(value);
1023 if (value_f == -1 && PyErr_Occurred()) {
1024 PyErr_Clear();
1025 return 0;
1026 }
1027
1028 float tmp[32];
1029 float *tmp_arr;
1030
1031 if (len * sizeof(float) > sizeof(tmp)) {
1032 tmp_arr = static_cast<float *>(PyMem_MALLOC(len * sizeof(float)));
1033 }
1034 else {
1035 tmp_arr = tmp;
1036 }
1037
1038 RNA_property_float_get_array(ptr, prop, tmp_arr);
1039
1040 for (i = 0; i < len; i++) {
1041 if (tmp_arr[i] == value_f) {
1042 break;
1043 }
1044 }
1045
1046 if (tmp_arr != tmp) {
1047 PyMem_FREE(tmp_arr);
1048 }
1049
1050 return i < len ? 1 : 0;
1051 }
1052 case PROP_INT: {
1053 const int value_i = PyC_Long_AsI32(value);
1054 if (value_i == -1 && PyErr_Occurred()) {
1055 PyErr_Clear();
1056 return 0;
1057 }
1058
1059 int tmp[32];
1060 int *tmp_arr;
1061
1062 if (len * sizeof(int) > sizeof(tmp)) {
1063 tmp_arr = static_cast<int *>(PyMem_MALLOC(len * sizeof(int)));
1064 }
1065 else {
1066 tmp_arr = tmp;
1067 }
1068
1069 RNA_property_int_get_array(ptr, prop, tmp_arr);
1070
1071 for (i = 0; i < len; i++) {
1072 if (tmp_arr[i] == value_i) {
1073 break;
1074 }
1075 }
1076
1077 if (tmp_arr != tmp) {
1078 PyMem_FREE(tmp_arr);
1079 }
1080
1081 return i < len ? 1 : 0;
1082 }
1083 case PROP_BOOLEAN: {
1084 const int value_i = PyC_Long_AsBool(value);
1085 if (value_i == -1 && PyErr_Occurred()) {
1086 PyErr_Clear();
1087 return 0;
1088 }
1089
1090 bool tmp[32];
1091 bool *tmp_arr;
1092
1093 if (len * sizeof(bool) > sizeof(tmp)) {
1094 tmp_arr = static_cast<bool *>(PyMem_MALLOC(len * sizeof(bool)));
1095 }
1096 else {
1097 tmp_arr = tmp;
1098 }
1099
1100 RNA_property_boolean_get_array(ptr, prop, tmp_arr);
1101
1102 for (i = 0; i < len; i++) {
1103 if (tmp_arr[i] == bool(value_i)) {
1104 break;
1105 }
1106 }
1107
1108 if (tmp_arr != tmp) {
1109 PyMem_FREE(tmp_arr);
1110 }
1111
1112 return i < len ? 1 : 0;
1113 }
1114 }
1115
1116 /* should never reach this */
1117 PyErr_SetString(PyExc_TypeError, "PropertyRNA - type not in float/bool/int");
1118 return -1;
1119}
#define SNPRINTF(dst, format,...)
Definition BLI_string.h:597
unsigned int uint
#define CLAMP(a, b, c)
struct CLG_LogRef * BPY_LOG_RNA
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
Read Guarded memory(de)allocation.
@ PROP_FLOAT
Definition RNA_types.hh:67
@ PROP_BOOLEAN
Definition RNA_types.hh:65
@ PROP_INT
Definition RNA_types.hh:66
@ PROP_DYNAMIC
Definition RNA_types.hh:317
PyObject * self
PyObject * pyrna_math_object_from_array(PointerRNA *ptr, PropertyRNA *prop)
Definition bpy_rna.cc:651
PyObject * pyrna_prop_CreatePyObject(PointerRNA *ptr, PropertyRNA *prop)
Definition bpy_rna.cc:7752
static void py_to_float(const ItemConvertArgData *arg, PyObject *py, char *data)
int pyrna_py_to_array(PointerRNA *ptr, PropertyRNA *prop, char *param_data, PyObject *py, const char *error_prefix)
static void convert_item_init_bool(PointerRNA *, PropertyRNA *, ItemConvert_FuncArg *convert_item)
static void int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
#define MAX_ARRAY_DIMENSION
static void py_to_bool(const ItemConvertArgData *, PyObject *py, char *data)
static void convert_item_init_int(PointerRNA *ptr, PropertyRNA *prop, ItemConvert_FuncArg *convert_item)
PyObject * pyrna_array_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void(*)(PointerRNA *ptr, PropertyRNA *prop, const char *data) RNA_SetArrayFunc
static int validate_array_type(PyObject *seq, int dim, int totdim, int dimsize[], const bool is_dynamic, ItemTypeCheckFunc check_item_type, const char *item_type_str, const char *error_prefix)
static int py_float_check(PyObject *py)
static int py_int_check(PyObject *py)
int pyrna_array_contains_py(PointerRNA *ptr, PropertyRNA *prop, PyObject *value)
static int validate_array(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, const bool prop_is_param_dyn_alloc, int lvalue_dim, ItemTypeCheckFunc check_item_type, const char *item_type_str, int *r_totitem, const char *error_prefix)
static void bool_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
int pyrna_py_to_array_index(PointerRNA *ptr, PropertyRNA *prop, int arraydim, int arrayoffset, int index, PyObject *py, const char *error_prefix)
int(*)(PyObject *py_data) ItemTypeCheckFunc
static void float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, void *value)
static int count_items(PyObject *seq, int dim)
static char * copy_values(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, int dim, char *data, uint item_size, int *index, const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index)
static void convert_item_init_float(PointerRNA *ptr, PropertyRNA *prop, ItemConvert_FuncArg *convert_item)
static void py_to_int(const ItemConvertArgData *arg, PyObject *py, char *data)
static int py_to_array(PyObject *seq, PointerRNA *ptr, PropertyRNA *prop, char *param_data, ItemTypeCheckFunc check_item_type, const char *item_type_str, int item_size, const ItemConvert_FuncArg *convert_item, RNA_SetArrayFunc rna_set_array, const char *error_prefix)
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, const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index, const char *error_prefix)
void(*)(const ItemConvertArgData *arg, PyObject *py_data, char *data) ItemConvertFunc
static int validate_array_length(PyObject *rvalue, PointerRNA *ptr, PropertyRNA *prop, const bool prop_is_param_dyn_alloc, int lvalue_dim, int *r_totitem, const char *error_prefix)
static int py_bool_check(PyObject *py)
PyObject * pyrna_py_from_array_index(BPy_PropertyArrayRNA *self, PointerRNA *ptr, PropertyRNA *prop, int index)
void(*)(PointerRNA *ptr, PropertyRNA *prop, int index, void *data_item) RNA_SetIndexFunc
static char * copy_value_single(PyObject *item, PointerRNA *ptr, PropertyRNA *prop, char *data, uint item_size, int *index, const ItemConvert_FuncArg *convert_item, RNA_SetIndexFunc rna_set_index)
PyObject * pyrna_py_from_array(PointerRNA *ptr, PropertyRNA *prop)
int len
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define BaseMath_ReadCallback(_self)
Definition mathutils.hh:125
#define MatrixObject_Check(v)
int PyC_Long_AsBool(PyObject *value)
return ret
void RNA_property_boolean_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, bool value)
void RNA_property_float_get_array(PointerRNA *ptr, PropertyRNA *prop, float *values)
int RNA_property_int_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_float_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, float value)
float RNA_property_float_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
void RNA_property_float_range(PointerRNA *ptr, PropertyRNA *prop, float *hardmin, float *hardmax)
void RNA_property_boolean_get_array(PointerRNA *ptr, PropertyRNA *prop, bool *values)
PropertyType RNA_property_type(PropertyRNA *prop)
const char * RNA_struct_identifier(const StructRNA *type)
void RNA_property_int_set_index(PointerRNA *ptr, PropertyRNA *prop, int index, int value)
int RNA_property_array_dimension(const PointerRNA *ptr, PropertyRNA *prop, int length[])
int RNA_property_flag(PropertyRNA *prop)
int RNA_property_array_length(PointerRNA *ptr, PropertyRNA *prop)
void RNA_property_float_set_array(PointerRNA *ptr, PropertyRNA *prop, const float *values)
void RNA_property_int_set_array(PointerRNA *ptr, PropertyRNA *prop, const int *values)
void RNA_property_int_get_array(PointerRNA *ptr, PropertyRNA *prop, int *values)
void RNA_property_int_range(PointerRNA *ptr, PropertyRNA *prop, int *hardmin, int *hardmax)
bool RNA_property_boolean_get_index(PointerRNA *ptr, PropertyRNA *prop, int index)
const char * RNA_property_identifier(const PropertyRNA *prop)
int RNA_property_multi_array_length(PointerRNA *ptr, PropertyRNA *prop, int dim)
void RNA_property_boolean_set_array(PointerRNA *ptr, PropertyRNA *prop, const bool *values)
struct ItemConvertArgData::@1351::@1354 float_data
struct ItemConvertArgData::@1351::@1353 int_data
ItemConvertFunc func
ItemConvertArgData arg
StructRNA * type
Definition RNA_types.hh:41
PointerRNA * ptr
Definition wm_files.cc:4126
uint8_t flag
Definition wm_window.cc:138