bmesh - python api
authorCampbell Barton <ideasman42@gmail.com>
Mon, 30 Apr 2012 18:54:14 +0000 (18:54 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Mon, 30 Apr 2012 18:54:14 +0000 (18:54 +0000)
- bm.*.layers.*.verify()
- bm.*.layers.*.is_singleton
- bm.*.layers.*.copy_from(other)

also added api functons
- BM_data_layer_copy(...)
- CustomData_layertype_is_singleton(type)

source/blender/blenkernel/BKE_customdata.h
source/blender/blenkernel/intern/customdata.c
source/blender/bmesh/intern/bmesh_interp.c
source/blender/bmesh/intern/bmesh_interp.h
source/blender/editors/mesh/mesh_data.c
source/blender/python/bmesh/bmesh_py_types_customdata.c

index 6a3625e213397aa4bacf315ce836c56c10960ea1..4b52189d8b77503cd35d7fc7359be4d0ad8250e0 100644 (file)
@@ -305,6 +305,7 @@ int CustomData_sizeof(int type);
 
 /* get the name of a layer type */
 const char *CustomData_layertype_name(int type);
+int         CustomData_layertype_is_singleton(int type);
 
 /* make sure the name of layer at index is unique */
 void CustomData_set_layer_unique_name(struct CustomData *data, int index);
index 4666aa6a4561468e350b5a85d54337efe56931b6..4cf48ff6005b25489349ea0dbbbc2d98a8e62a7d 100644 (file)
@@ -71,7 +71,11 @@ typedef struct LayerTypeInfo {
        int size;          /* the memory size of one element of this layer's data */
        const char *structname;  /* name of the struct used, for file writing */
        int structnum;     /* number of structs per element, for file writing */
-       const char *defaultname; /* default layer name */
+
+       /* default layer name.
+        * note! when NULL this is a way to ensure there is only ever one item
+        * see: CustomData_layertype_is_singleton() */
+       const char *defaultname;
 
        /* a function to copy count elements of this layer's data
         * (deep copy if appropriate)
@@ -2601,6 +2605,16 @@ const char *CustomData_layertype_name(int type)
        return layerType_getName(type);
 }
 
+
+/**
+ * Can only ever be one of these.
+ */
+int CustomData_layertype_is_singleton(int type)
+{
+       const LayerTypeInfo *typeInfo = layerType_getInfo(type);
+       return typeInfo->defaultname != NULL;
+}
+
 static int  CustomData_is_property_layer(int type)
 {
        if ((type == CD_PROP_FLT) || (type == CD_PROP_INT) || (type == CD_PROP_STR))
index 5149a5436a2ae3d835535848c3462d7fb748c04e..c774880332bf549ccb340939b621bf84145faf90 100644 (file)
@@ -853,6 +853,52 @@ void BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n)
        if (olddata.layers) MEM_freeN(olddata.layers);
 }
 
+void BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n)
+{
+       BMIter iter;
+
+       if (&bm->vdata == data) {
+               BMVert *eve;
+
+               BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) {
+                       void *ptr = CustomData_bmesh_get_n(data, eve->head.data, type, dst_n);
+                       CustomData_bmesh_set_n(data, eve->head.data, type, src_n, ptr);
+               }
+       }
+       else if (&bm->edata == data) {
+               BMEdge *eed;
+
+               BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) {
+                       void *ptr = CustomData_bmesh_get_n(data, eed->head.data, type, dst_n);
+                       CustomData_bmesh_set_n(data, eed->head.data, type, src_n, ptr);
+               }
+       }
+       else if (&bm->pdata == data) {
+               BMFace *efa;
+
+               BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+                       void *ptr = CustomData_bmesh_get_n(data, efa->head.data, type, dst_n);
+                       CustomData_bmesh_set_n(data, efa->head.data, type, src_n, ptr);
+               }
+       }
+       else if (&bm->ldata == data) {
+               BMIter liter;
+               BMFace *efa;
+               BMLoop *l;
+
+               BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
+                       BM_ITER_ELEM (l, &liter, efa, BM_LOOPS_OF_FACE) {
+                               void *ptr = CustomData_bmesh_get_n(data, l->head.data, type, dst_n);
+                               CustomData_bmesh_set_n(data, l->head.data, type, src_n, ptr);
+                       }
+               }
+       }
+       else {
+               /* should never reach this! */
+               BLI_assert(0);
+       }
+}
+
 float BM_elem_float_data_get(CustomData *cd, void *element, int type)
 {
        float *f = CustomData_bmesh_get(cd, ((BMHeader *)element)->data, type);
index 0d97fbcc0ec4f48a7aa4791cd790cdf0d4746d94..3380a3e6b1b7fe0f60aa19dc2e2573539082268c 100644 (file)
@@ -36,6 +36,8 @@ void  BM_data_layer_add(BMesh *em, CustomData *data, int type);
 void  BM_data_layer_add_named(BMesh *bm, CustomData *data, int type, const char *name);
 void  BM_data_layer_free(BMesh *em, CustomData *data, int type);
 void  BM_data_layer_free_n(BMesh *bm, CustomData *data, int type, int n);
+void  BM_data_layer_copy(BMesh *bm, CustomData *data, int type, int src_n, int dst_n);
+
 float BM_elem_float_data_get(CustomData *cd, void *element, int type);
 void  BM_elem_float_data_set(CustomData *cd, void *element, int type, const float val);
 
index 5aea6f8d1c394cda185b286807e8f4482d0d85b1..fb9b012a31a39268b6e200ddefde85a77d5602a6 100644 (file)
@@ -189,42 +189,6 @@ static void delete_customdata_layer(bContext *C, Object *ob, CustomDataLayer *la
        }
 }
 
-/* copies from active to 'index' */
-static void editmesh_face_copy_customdata(BMEditMesh *em, int type, int index)
-{
-       BMesh *bm = em->bm;
-       CustomData *pdata = &bm->pdata;
-       BMIter iter;
-       BMFace *efa;
-       const int n = CustomData_get_active_layer(pdata, type);
-
-       /* ensure all current elements follow new customdata layout */
-       BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
-               void *data = CustomData_bmesh_get_n(pdata, efa->head.data, type, n);
-               CustomData_bmesh_set_n(pdata, efa->head.data, type, index, data);
-       }
-}
-
-/* copies from active to 'index' */
-static void editmesh_loop_copy_customdata(BMEditMesh *em, int type, int index)
-{
-       BMesh *bm = em->bm;
-       CustomData *ldata = &bm->ldata;
-       BMIter iter;
-       BMIter liter;
-       BMFace *efa;
-       BMLoop *loop;
-       const int n = CustomData_get_active_layer(ldata, type);
-
-       /* ensure all current elements follow new customdata layout */
-       BM_ITER_MESH (efa, &iter, bm, BM_FACES_OF_MESH) {
-               BM_ITER_ELEM (loop, &liter, efa, BM_LOOPS_OF_FACE) {
-                       void *data = CustomData_bmesh_get_n(ldata, loop->head.data, type, n);
-                       CustomData_bmesh_set_n(ldata, loop->head.data, type, index, data);
-               }
-       }
-}
-
 int ED_mesh_uv_loop_reset_ex(struct bContext *C, struct Mesh *me, const int layernum)
 {
        BMEditMesh *em = me->edit_btmesh;
@@ -360,7 +324,8 @@ int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_s
                BM_data_layer_add_named(em->bm, &em->bm->pdata, CD_MTEXPOLY, name);
                /* copy data from active UV */
                if (layernum) {
-                       editmesh_face_copy_customdata(em, CD_MTEXPOLY, layernum);
+                       const int layernum_dst = CustomData_get_active_layer(&em->bm->pdata, CD_MTEXPOLY);
+                       BM_data_layer_copy(em->bm, &em->bm->pdata, CD_MTEXPOLY, layernum, layernum_dst);
                }
                if (active_set || layernum == 0) {
                        CustomData_set_layer_active(&em->bm->pdata, CD_MTEXPOLY, layernum);
@@ -370,7 +335,9 @@ int ED_mesh_uv_texture_add(bContext *C, Mesh *me, const char *name, int active_s
                BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPUV, name);
                /* copy data from active UV */
                if (layernum) {
-                       editmesh_loop_copy_customdata(em, CD_MLOOPUV, layernum);
+                       const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPUV);
+                       BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPUV, layernum, layernum_dst);
+
                        is_init = TRUE;
                }
                if (active_set || layernum == 0) {
@@ -457,7 +424,8 @@ int ED_mesh_color_add(bContext *C, Scene *UNUSED(scene), Object *UNUSED(ob), Mes
                BM_data_layer_add_named(em->bm, &em->bm->ldata, CD_MLOOPCOL, name);
                /* copy data from active vertex color layer */
                if (layernum) {
-                       editmesh_loop_copy_customdata(em, CD_MLOOPCOL, layernum);
+                       const int layernum_dst = CustomData_get_active_layer(&em->bm->ldata, CD_MLOOPCOL);
+                       BM_data_layer_copy(em->bm, &em->bm->ldata, CD_MLOOPUV, layernum, layernum_dst);
                }
                if (active_set || layernum == 0) {
                        CustomData_set_layer_active(&em->bm->ldata, CD_MLOOPCOL, layernum);
index 6a02d8e4a25639d4dfef87d63c9eef5103da5996..86cfa727e977aed9b5f1c6303fa8bf795e808b05 100644 (file)
@@ -124,7 +124,7 @@ static PyObject *bpy_bmlayeraccess_collection_get(BPy_BMLayerAccess *self, void
 
 
 PyDoc_STRVAR(bpy_bmlayercollection_active_doc,
-"This meshes vert sequence (read-only).\n\n:type: :class:`BMVertSeq`"
+"The active layer of this type (read-only).\n\n:type: :class:`BMLayerItem`"
 );
 static PyObject *bpy_bmlayercollection_active_get(BPy_BMLayerItem *self, void *UNUSED(flag))
 {
@@ -145,6 +145,17 @@ static PyObject *bpy_bmlayercollection_active_get(BPy_BMLayerItem *self, void *U
        }
 }
 
+
+PyDoc_STRVAR(bpy_bmlayercollection_is_singleton_doc,
+"This meshes vert sequence (read-only).\n\n:type: :class:`BMVertSeq`"
+);
+static PyObject *bpy_bmlayercollection_is_singleton_get(BPy_BMLayerItem *self, void *UNUSED(flag))
+{
+       BPY_BM_CHECK_OBJ(self);
+
+       return PyBool_FromLong(CustomData_layertype_is_singleton(self->type));
+}
+
 PyDoc_STRVAR(bpy_bmlayercollection_name_doc,
 "The layers unique name (read-only).\n\n:type: string"
 );
@@ -211,7 +222,8 @@ static PyGetSetDef bpy_bmlayeraccess_loop_getseters[] = {
 
 static PyGetSetDef bpy_bmlayercollection_getseters[] = {
     /* BMESH_TODO, make writeable */
-    {(char *)"active", (getter)bpy_bmlayercollection_active_get, (setter)NULL, (char *)bpy_bmlayercollection_active_doc, NULL},
+    {(char *)"active",       (getter)bpy_bmlayercollection_active_get,       (setter)NULL, (char *)bpy_bmlayercollection_active_doc, NULL},
+    {(char *)"is_singleton", (getter)bpy_bmlayercollection_is_singleton_get, (setter)NULL, (char *)bpy_bmlayercollection_is_singleton_doc, NULL},
 
     {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
 };
@@ -230,6 +242,87 @@ static PyGetSetDef bpy_bmlayeritem_getseters[] = {
 /* BMLayerCollection
  * ----------------- */
 
+PyDoc_STRVAR(bpy_bmlayeritem_copy_from_doc,
+".. method:: copy_from(other)\n"
+"\n"
+"   Return a copy of the layer\n"
+"\n"
+"   :arg other: Another layer to copy from.\n"
+"   :arg other: :class:`BMLayerItem`\n"
+);
+static PyObject *bpy_bmlayeritem_copy_from(BPy_BMLayerItem *self, BPy_BMLayerItem *value)
+{
+       CustomData *data;
+
+       if (!BPy_BMLayerItem_Check(value)) {
+               PyErr_Format(PyExc_TypeError,
+                            "layer.copy_from(x): expected BMLayerItem, not '%.200s'",
+                            Py_TYPE(value)->tp_name);
+               return NULL;
+       }
+
+       BPY_BM_CHECK_OBJ(self);
+       BPY_BM_CHECK_OBJ(value);
+
+       if (self->bm != value->bm) {
+               PyErr_SetString(PyExc_ValueError,
+                               "layer.copy_from(): layer is from another mesh");
+               return NULL;
+       }
+
+       else if ((self->htype != value->htype) ||
+                (self->type  != value->type) ||
+                (self->index != value->index))
+       {
+               PyErr_SetString(PyExc_ValueError,
+                               "layer.copy_from(other): layer type mismatch");
+       }
+
+       data = bpy_bm_customdata_get(self->bm, self->htype);
+
+       if ((bpy_bmlayeritem_get(self) == NULL) ||
+           (bpy_bmlayeritem_get(value) == NULL))
+       {
+               return NULL;
+       }
+
+       BM_data_layer_copy(self->bm, data, self->type, value->index, self->index);
+
+       Py_RETURN_NONE;
+}
+
+/* similar to new(), but no name arg. */
+PyDoc_STRVAR(bpy_bmlayercollection_verify_doc,
+".. method:: verify()\n"
+"\n"
+"   Create a new layer or return an existing active layer\n"
+"\n"
+"   :return: The newly verified layer.\n"
+"   :rtype: :class:`BMLayerItem`\n"
+);
+static PyObject *bpy_bmlayercollection_verify(BPy_BMLayerCollection *self)
+{
+       int index;
+       CustomData *data;
+
+       BPY_BM_CHECK_OBJ(self);
+
+       data = bpy_bm_customdata_get(self->bm, self->htype);
+
+       index = CustomData_get_layer_index(data, self->type);
+
+       if (index == -1) {
+               BM_data_layer_add(self->bm, data, self->type);
+               index = 0;
+       }
+       else {
+               index = CustomData_get_active_layer_index(data, self->type) - index; /* make relative */
+       }
+
+       BLI_assert(index >= 0);
+
+       return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
+}
 
 PyDoc_STRVAR(bpy_bmlayercollection_new_doc,
 ".. method:: new(name)\n"
@@ -255,6 +348,14 @@ static PyObject *bpy_bmlayercollection_new(BPy_BMLayerCollection *self, PyObject
 
        data = bpy_bm_customdata_get(self->bm, self->htype);
 
+       if (CustomData_layertype_is_singleton(self->type) &&
+           CustomData_has_layer(data, self->type))
+       {
+               PyErr_SetString(PyExc_ValueError,
+                               "layers.new(): is a singleton, use verify() instead");
+               return NULL;
+       }
+
        if (name) {
                BM_data_layer_add_named(self->bm, data, self->type, name);
        }
@@ -451,7 +552,13 @@ static PyObject *bpy_bmlayercollection_get(BPy_BMLayerCollection *self, PyObject
        return Py_INCREF(def), def;
 }
 
+static struct PyMethodDef bpy_bmlayeritem_methods[] = {
+    {"copy_from", (PyCFunction)bpy_bmlayeritem_copy_from,    METH_O,       bpy_bmlayeritem_copy_from_doc},
+    {NULL, NULL, 0, NULL}
+};
+
 static struct PyMethodDef bpy_bmelemseq_methods[] = {
+    {"verify",  (PyCFunction)bpy_bmlayercollection_verify,   METH_NOARGS,  bpy_bmlayercollection_verify_doc},
     {"new",     (PyCFunction)bpy_bmlayercollection_new,      METH_VARARGS, bpy_bmlayercollection_new_doc},
     {"remove",  (PyCFunction)bpy_bmlayercollection_remove,   METH_O,       bpy_bmlayercollection_remove_doc},
 
@@ -462,8 +569,6 @@ static struct PyMethodDef bpy_bmelemseq_methods[] = {
     {NULL, NULL, 0, NULL}
 };
 
-
-
 /* Sequences
  * ========= */
 
@@ -763,6 +868,7 @@ void BPy_BM_init_types_customdata(void)
 
 //     BPy_BMLayerAccess_Type.tp_methods     = bpy_bmeditselseq_methods;
        BPy_BMLayerCollection_Type.tp_methods = bpy_bmelemseq_methods;
+       BPy_BMLayerItem_Type.tp_methods       = bpy_bmlayeritem_methods;
 
        BPy_BMLayerCollection_Type.tp_as_sequence = &bpy_bmlayercollection_as_sequence;