diff options
author | Campbell Barton <ideasman42@gmail.com> | 2012-03-16 12:26:22 +0400 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2012-03-16 12:26:22 +0400 |
commit | f91407150a9415b55765abc7ac870c2be2703334 (patch) | |
tree | ad689025f6accf3d6d8da367353bde161781700e /source/blender/python | |
parent | 1823bb4abb68b24b6c8db4cd388a855457dc45f4 (diff) |
bmesh py api:
initial support for editing bmesh customdata per vert/edge/face/loop
shapes, crease, bevel weights working, missing UVs and Vertex Colors still.
Diffstat (limited to 'source/blender/python')
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_types.c | 40 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_types.h | 1 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_types_customdata.c | 258 | ||||
-rw-r--r-- | source/blender/python/bmesh/bmesh_py_types_customdata.h | 5 |
4 files changed, 301 insertions, 3 deletions
diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index d9344c3b690..8b3a32ea923 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -2097,6 +2097,9 @@ static struct PyMethodDef bpy_bmelemseq_methods[] = { /* Sequences * ========= */ +/* BMElemSeq / Iter + * ---------------- */ + static PyTypeObject *bpy_bm_itype_as_pytype(const char itype) { /* should cover all types */ @@ -2305,6 +2308,23 @@ static int bpy_bmelemseq_contains(BPy_BMElemSeq *self, PyObject *value) return 0; } +/* BMElem (customdata) + * ------------------- */ + +static PyObject *bpy_bmelem_subscript(BPy_BMElem *self, BPy_BMLayerItem *key) +{ + BPY_BM_CHECK_OBJ(self); + + return BPy_BMLayerItem_GetItem(self, key); +} + +static int bpy_bmelem_ass_subscript(BPy_BMElem *self, BPy_BMLayerItem *key, PyObject *value) +{ + BPY_BM_CHECK_INT(self); + + return BPy_BMLayerItem_SetItem(self, key, value); +} + static PySequenceMethods bpy_bmelemseq_as_sequence = { (lenfunc)bpy_bmelemseq_length, /* sq_length */ NULL, /* sq_concat */ @@ -2324,6 +2344,13 @@ static PyMappingMethods bpy_bmelemseq_as_mapping = { (objobjargproc)NULL, /* mp_ass_subscript */ }; +/* for customdata access */ +static PyMappingMethods bpy_bm_elem_as_mapping = { + (lenfunc)NULL, /* mp_length */ /* keep this empty, messes up 'if elem: ...' test */ + (binaryfunc)bpy_bmelem_subscript, /* mp_subscript */ + (objobjargproc)bpy_bmelem_ass_subscript, /* mp_ass_subscript */ +}; + /* Iterator * -------- */ @@ -2613,6 +2640,10 @@ void BPy_BM_init_types(void) BPy_BMElemSeq_Type.tp_as_sequence = &bpy_bmelemseq_as_sequence; + BPy_BMVert_Type.tp_as_mapping = &bpy_bm_elem_as_mapping; + BPy_BMEdge_Type.tp_as_mapping = &bpy_bm_elem_as_mapping; + BPy_BMFace_Type.tp_as_mapping = &bpy_bm_elem_as_mapping; + BPy_BMLoop_Type.tp_as_mapping = &bpy_bm_elem_as_mapping; BPy_BMElemSeq_Type.tp_as_mapping = &bpy_bmelemseq_as_mapping; BPy_BMElemSeq_Type.tp_iter = (getiterfunc)bpy_bmelemseq_iter; @@ -3015,10 +3046,9 @@ int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype) * * \return a sting like '(BMVert/BMEdge/BMFace/BMLoop)' */ -char *BPy_BMElem_StringFromHType(const char htype) +char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32]) { /* zero to ensure string is always NULL terminated */ - static char ret[32]; char *ret_ptr = ret; if (htype & BM_VERT) ret_ptr += sprintf(ret_ptr, "/%s", BPy_BMVert_Type.tp_name); if (htype & BM_EDGE) ret_ptr += sprintf(ret_ptr, "/%s", BPy_BMEdge_Type.tp_name); @@ -3028,3 +3058,9 @@ char *BPy_BMElem_StringFromHType(const char htype) *ret_ptr = ')'; return ret; } +char *BPy_BMElem_StringFromHType(const char htype) +{ + /* zero to ensure string is always NULL terminated */ + static char ret[32]; + return BPy_BMElem_StringFromHType_ex(htype, ret); +} diff --git a/source/blender/python/bmesh/bmesh_py_types.h b/source/blender/python/bmesh/bmesh_py_types.h index 452c8b2103f..cb4646330a7 100644 --- a/source/blender/python/bmesh/bmesh_py_types.h +++ b/source/blender/python/bmesh/bmesh_py_types.h @@ -145,6 +145,7 @@ void *BPy_BMElem_PySeq_As_Array(BMesh **r_bm, PyObject *seq, Py_ssize_t min, Py_ PyObject *BPy_BMElem_Array_As_Tuple(BMesh *bm, BMHeader **elem, Py_ssize_t elem_len); int BPy_BMElem_CheckHType(PyTypeObject *type, const char htype); +char *BPy_BMElem_StringFromHType_ex(const char htype, char ret[32]); char *BPy_BMElem_StringFromHType(const char htype); diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c index 4b53b6e11d0..a44cc78088d 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.c +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c @@ -32,13 +32,20 @@ #include <Python.h> +#include "BLI_string.h" +#include "BLI_math_vector.h" + #include "bmesh.h" #include "bmesh_py_types.h" #include "bmesh_py_types_customdata.h" +#include "../mathutils/mathutils.h" + #include "BKE_customdata.h" +#include "DNA_meshdata_types.h" + static CustomData *bpy_bm_customdata_get(BMesh *bm, char htype) { switch (htype) { @@ -95,7 +102,7 @@ static PyGetSetDef bpy_bmlayeraccess_getseters[] = { {(char *)"color", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)NULL, (void *)CD_MLOOPCOL}, {(char *)"shape", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)NULL, (void *)CD_SHAPEKEY}, - {(char *)"bevel_weight", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)NULL, (void *)CD_SHAPEKEY}, + {(char *)"bevel_weight", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)NULL, (void *)CD_BWEIGHT}, {(char *)"crease", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)NULL, (void *)CD_CREASE}, {NULL, NULL, NULL, NULL, NULL} /* Sentinel */ @@ -545,3 +552,252 @@ void BPy_BM_init_types_customdata(void) PyType_Ready(&BPy_BMLayerCollection_Type); PyType_Ready(&BPy_BMLayerItem_Type); } + + +/* Per Element Get/Set + * ******************* */ + +/** + * helper function for get/set, NULL return means the error is set +*/ +static void *bpy_bmlayeritem_ptr_get(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer) +{ + void *value; + BMElem *ele = py_ele->ele; + CustomData *data; + + /* error checking */ + if (UNLIKELY(!BPy_BMLayerItem_Check(py_layer))) { + PyErr_SetString(PyExc_AttributeError, + "BMElem[key]: invalid key, must be a BMLayerItem"); + return NULL; + } + else if (UNLIKELY(py_ele->bm != py_layer->bm)) { + PyErr_SetString(PyExc_ValueError, + "BMElem[layer]: layer is from another mesh"); + return NULL; + } + else if (UNLIKELY(ele->head.htype != py_layer->htype)) { + char namestr_1[32], namestr_2[32]; + PyErr_Format(PyExc_ValueError, + "Layer/Element type mismatch, expected %.200s got layer type %.200s", + BPy_BMElem_StringFromHType_ex(ele->head.htype, namestr_1), + BPy_BMElem_StringFromHType_ex(py_layer->htype, namestr_2)); + return NULL; + } + + data = bpy_bm_customdata_get(py_layer->bm, py_layer->htype); + + value = CustomData_bmesh_get_n(data, ele->head.data, py_layer->type, py_layer->index); + + if (UNLIKELY(value == NULL)) { + /* this should be fairly unlikely but possible if layers move about after we get them */ + PyErr_SetString(PyExc_KeyError, + "BMElem[key]: layer not found"); + return NULL; + } + else { + return value; + } +} + + +/** + *\brief BMElem.__getitem__() + * + * assume all error checks are done, eg: + * + * uv = vert[uv_layer] + */ +PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer) +{ + void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer); + PyObject *ret; + + if (UNLIKELY(value == NULL)) { + return NULL; + } + + switch (py_layer->type) { + case CD_MDEFORMVERT: + { + ret = Py_NotImplemented; /* TODO */ + Py_INCREF(ret); + break; + } + case CD_PROP_FLT: + { + ret = PyFloat_FromDouble(*(float *)value); + break; + } + case CD_PROP_INT: + { + ret = PyLong_FromSsize_t((Py_ssize_t)(*(int *)value)); + break; + } + case CD_PROP_STR: + { + MStringProperty *mstring = value; + ret = PyBytes_FromStringAndSize(mstring->s, BLI_strnlen(mstring->s, sizeof(mstring->s))); + break; + } + case CD_MTEXPOLY: + { + ret = Py_NotImplemented; /* TODO */ + Py_INCREF(ret); + break; + } + case CD_MLOOPUV: + { + ret = Py_NotImplemented; /* TODO */ + Py_INCREF(ret); + break; + } + case CD_MLOOPCOL: + { + ret = Py_NotImplemented; /* TODO */ + Py_INCREF(ret); + break; + } + case CD_SHAPEKEY: + { + ret = Vector_CreatePyObject((float *)value, 3, Py_WRAP, NULL); + break; + } + case CD_BWEIGHT: + { + ret = PyFloat_FromDouble(*(float *)value); + break; + } + case CD_CREASE: + { + ret = PyFloat_FromDouble(*(float *)value); + break; + } + default: + { + ret = Py_NotImplemented; /* TODO */ + Py_INCREF(ret); + break; + } + } + + return ret; +} + +int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *py_value) +{ + int ret = 0; + void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer); + + if (UNLIKELY(value == NULL)) { + return -1; + } + + switch (py_layer->type) { + case CD_MDEFORMVERT: + { + PyErr_SetString(PyExc_AttributeError, "readonly"); /* could make this writeable later */ + ret = -1; + break; + } + case CD_PROP_FLT: + { + float tmp_val = PyFloat_AsDouble(py_value); + if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { + PyErr_Format(PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name); + ret = -1; + } + else { + *(float *)value = tmp_val; + } + break; + } + case CD_PROP_INT: + { + int tmp_val = PyLong_AsSsize_t(py_value); + if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { + PyErr_Format(PyExc_TypeError, "expected an int, not a %.200s", Py_TYPE(py_value)->tp_name); + ret = -1; + } + else { + *(int *)value = tmp_val; + } + break; + } + case CD_PROP_STR: + { + MStringProperty *mstring = value; + const char *tmp_val = PyBytes_AsString(py_value); + if (UNLIKELY(tmp_val == NULL)) { + PyErr_Format(PyExc_TypeError, "expected bytes, not a %.200s", Py_TYPE(py_value)->tp_name); + ret = -1; + } + else { + BLI_strncpy(mstring->s, tmp_val, sizeof(mstring->s)); + } + break; + } + case CD_MTEXPOLY: + { + PyErr_SetString(PyExc_AttributeError, "readonly"); /* could make this writeable later */ + ret = -1; + break; + } + case CD_MLOOPUV: + { + PyErr_SetString(PyExc_AttributeError, "readonly"); /* could make this writeable later */ + ret = -1; + break; + } + case CD_MLOOPCOL: + { + PyErr_SetString(PyExc_AttributeError, "readonly"); + ret = -1; + break; + } + case CD_SHAPEKEY: + { + float tmp_val[3]; + if (UNLIKELY(mathutils_array_parse(tmp_val, 3, 3, py_value, "BMVert[shape] = value") == -1)) { + ret = -1; + } + else { + copy_v3_v3((float *)value,tmp_val); + } + break; + } + case CD_BWEIGHT: + { + float tmp_val = PyFloat_AsDouble(py_value); + if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { + PyErr_Format(PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name); + ret = -1; + } + else { + *(float *)value = CLAMPIS(tmp_val, 0.0f, 1.0f); + } + break; + } + case CD_CREASE: + { + float tmp_val = PyFloat_AsDouble(py_value); + if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) { + PyErr_Format(PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name); + ret = -1; + } + else { + *(float *)value = CLAMPIS(tmp_val, 0.0f, 1.0f); + } + break; + } + default: + { + PyErr_SetString(PyExc_AttributeError, "readonly / unsupported type"); + ret = -1; + break; + } + } + + return ret; +} diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.h b/source/blender/python/bmesh/bmesh_py_types_customdata.h index 0de79d7bd21..6ec947f98fa 100644 --- a/source/blender/python/bmesh/bmesh_py_types_customdata.h +++ b/source/blender/python/bmesh/bmesh_py_types_customdata.h @@ -68,4 +68,9 @@ PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, const char htype, int type, void BPy_BM_init_types_customdata(void); +/* __getitem__ / __setitem__ */ +PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer); +int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *value); + + #endif /* __BMESH_PY_TYPES_CUSTOMDATA_H__ */ |