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]
236 lines
6.8 KiB
C
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);
|
|
}
|