This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/python/intern/bpy_array.c
Arystanbek Dyussenov 706a4c22b5 Implemented dynamic and multidimensional array support in RNA.
Example code: http://www.pasteall.org/7332/c.
New API functions: http://www.pasteall.org/7330/c.

Maximum number of dimensions is currently limited to 3, but can be increased arbitrarily if needed.

What this means for ID property access:

* MeshFace.verts - dynamic array, size 3 or 4 depending on MFace.v4
* MeshTextureFace.uv - dynamic, 2-dimensional array, size depends on MFace.v4
* Object.matrix - 2-dimensional array

What this means for functions:

* more intuitive API possibility, for example:
  Mesh.add_vertices([(x, y, z), (x, y, z), ...])
  Mesh.add_faces([(1, 2, 3), (4, 5, 6), ...])

Python part is not complete yet, e.g. it is possible to:

MeshFace.verts = (1, 2, 3) # even if Mesh.verts is (1, 2, 3, 4) and vice-versa
MeshTextureFace.uv = [(0.0, 0.0)] * 4 # only if a corresponding MFace is a quad

but the following won't work:

MeshTextureFace.uv[3] = (0.0, 0.0) # setting uv[3] modifies MTFace.uv[1][0] instead of MTFace.uv[3]
2009-08-25 17:06:36 +00:00

236 lines
6.8 KiB
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 *****
*/
#include "Python.h"
#include "bpy_rna.h"
#include "RNA_access.h"
#include "BLI_string.h"
#include "MEM_guardedalloc.h"
typedef void (*ItemConvertFunc)(PyObject *, char *);
typedef int (*ItemTypeCheckFunc)(PyObject *);
typedef void (*RNA_SetArrayFunc)(PointerRNA *, PropertyRNA *, const char *);
/* 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)
{
int i;
if (dim < totdim) {
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);
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]);
ok= 0;
}
if (!pyrna_validate_array(item, dim + 1, totdim, dim_size, check_item_type, item_type_str, error_str, error_str_size)) {
ok= 0;
}
Py_DECREF(item);
if (!ok)
return 0;
}
}
else {
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);
return 0;
}
Py_DECREF(item);
}
}
return 1;
}
/* Returns the number of items in a single- or multi-dimensional sequence. */
static int pyrna_count_items(PyObject *seq)
{
int totitem= 0;
if (PySequence_Check(seq)) {
int i;
for (i= 0; i < PySequence_Length(seq); i++) {
PyObject *item= PySequence_GetItem(seq, i);
totitem += pyrna_count_items(item);
Py_DECREF(item);
}
}
else
totitem= 1;
return totitem;
}
static int pyrna_apply_array_length(PointerRNA *ptr, PropertyRNA *prop, int totitem, char *error_str, int error_str_size)
{
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);
return 0;
}
}
}
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);
return 0;
}
}
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)
{
unsigned int i;
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);
}
else {
convert_item(item, data);
data += item_size;
}
Py_DECREF(item);
}
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)
{
unsigned short totdim, dim_size[100];
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))
return 0;
if (totitem) {
if (!param_data || RNA_property_flag(prop) & PROP_DYNAMIC)
data= MEM_callocN(item_size * totitem, "pyrna primitive type array");
else
data= param_data;
pyrna_py_to_array(py, 1, totdim, data, item_size, convert_item);
if (param_data) {
if (RNA_property_flag(prop) & PROP_DYNAMIC) {
/* not freeing allocated mem, RNA_parameter_list_free will do this */
*(char**)param_data= data;
}
}
else {
/* NULL can only pass through in case RNA property arraylength is 0 (impossible?) */
rna_set_array(ptr, prop, data);
MEM_freeN(data);
}
}
return 1;
}
static void pyrna_py_to_float(PyObject *py, char *data)
{
*(float*)data= (float)PyFloat_AsDouble(py);
}
static void pyrna_py_to_int(PyObject *py, char *data)
{
*(int*)data= (int)PyLong_AsSsize_t(py);
}
static void pyrna_py_to_boolean(PyObject *py, char *data)
{
*(int*)data= (int)PyObject_IsTrue(py);
}
static int py_float_check(PyObject *py)
{
return PyFloat_Check(py);
}
static int py_int_check(PyObject *py)
{
return PyLong_Check(py);
}
static int py_bool_check(PyObject *py)
{
return PyBool_Check(py);
}
int pyrna_py_to_float_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size)
{
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 pyrna_py_to_int_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size)
{
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);
}
int pyrna_py_to_boolean_array(PyObject *py, PointerRNA *ptr, PropertyRNA *prop, char *param_data, char *error_str, int error_str_size)
{
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);
}