[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [44918] trunk/blender/source/blender: bmesh py api:

Campbell Barton ideasman42 at gmail.com
Fri Mar 16 09:26:43 CET 2012


Revision: 44918
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=44918
Author:   campbellbarton
Date:     2012-03-16 08:26:22 +0000 (Fri, 16 Mar 2012)
Log Message:
-----------
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.

Modified Paths:
--------------
    trunk/blender/source/blender/bmesh/bmesh_error.h
    trunk/blender/source/blender/python/bmesh/bmesh_py_types.c
    trunk/blender/source/blender/python/bmesh/bmesh_py_types.h
    trunk/blender/source/blender/python/bmesh/bmesh_py_types_customdata.c
    trunk/blender/source/blender/python/bmesh/bmesh_py_types_customdata.h

Modified: trunk/blender/source/blender/bmesh/bmesh_error.h
===================================================================
--- trunk/blender/source/blender/bmesh/bmesh_error.h	2012-03-16 05:25:02 UTC (rev 44917)
+++ trunk/blender/source/blender/bmesh/bmesh_error.h	2012-03-16 08:26:22 UTC (rev 44918)
@@ -49,7 +49,7 @@
  * errorcode is either the errorcode, or BMERR_ALL for any
  * error.*/
 
-/* not yet implimented.
+/* not yet implemented.
  * int BMO_error_catch_op(BMesh *bm, BMOperator *catchop, int errorcode, char **msg);
  */
 

Modified: trunk/blender/source/blender/python/bmesh/bmesh_py_types.c
===================================================================
--- trunk/blender/source/blender/python/bmesh/bmesh_py_types.c	2012-03-16 05:25:02 UTC (rev 44917)
+++ trunk/blender/source/blender/python/bmesh/bmesh_py_types.c	2012-03-16 08:26:22 UTC (rev 44918)
@@ -2097,6 +2097,9 @@
 /* Sequences
  * ========= */
 
+/* BMElemSeq / Iter
+ * ---------------- */
+
 static PyTypeObject *bpy_bm_itype_as_pytype(const char itype)
 {
 	/* should cover all types */
@@ -2305,6 +2308,23 @@
 	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 @@
     (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 @@
 
 	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 @@
  *
  * \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 @@
 	*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);
+}

Modified: trunk/blender/source/blender/python/bmesh/bmesh_py_types.h
===================================================================
--- trunk/blender/source/blender/python/bmesh/bmesh_py_types.h	2012-03-16 05:25:02 UTC (rev 44917)
+++ trunk/blender/source/blender/python/bmesh/bmesh_py_types.h	2012-03-16 08:26:22 UTC (rev 44918)
@@ -145,6 +145,7 @@
 
 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);
 
 

Modified: trunk/blender/source/blender/python/bmesh/bmesh_py_types_customdata.c
===================================================================
--- trunk/blender/source/blender/python/bmesh/bmesh_py_types_customdata.c	2012-03-16 05:25:02 UTC (rev 44917)
+++ trunk/blender/source/blender/python/bmesh/bmesh_py_types_customdata.c	2012-03-16 08:26:22 UTC (rev 44918)
@@ -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 @@
     {(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 @@
 	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 {

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list