bmesh python api change in internal behavior.
authorCampbell Barton <ideasman42@gmail.com>
Wed, 22 Feb 2012 16:08:30 +0000 (16:08 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 22 Feb 2012 16:08:30 +0000 (16:08 +0000)
* Only have 1 python object per bmesh, vertex, edge, loop, face.
* Store pointers back to the python data in a custom data layer so as not to use more memory for normal editing operations (when pythons not running).
* Currently this data is created and freed along with the BMesh PyObject.
* Incidentally - this fixes comparisons for bmesh elements which wasnt working before.

source/blender/blenkernel/intern/customdata.c
source/blender/bmesh/bmesh_class.h
source/blender/makesdna/DNA_customdata_types.h
source/blender/python/bmesh/bmesh_py_types.c

index f019fb740fba736919858acc9cb5a37c1e05e27c..b2aaa651912e357e390cecde90385c5e940555ba 100644 (file)
@@ -159,6 +159,33 @@ static void layerFree_mdeformvert(void *data, int count, int size)
        }
 }
 
+/* copy just zeros in this case */
+static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest,
+                                        int count)
+{
+       int i, size = sizeof(void *);
+
+       for(i = 0; i < count; ++i) {
+               void **ptr = (void  **)((char *)dest + i * size);
+               *ptr = NULL;
+       }
+}
+
+static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size)
+{
+       extern void bpy_bm_generic_invalidate(void *self);
+
+       int i;
+
+       for(i = 0; i < count; ++i) {
+               void **ptr = (void *)((char *)data + i * size);
+               if (*ptr) {
+                       bpy_bm_generic_invalidate(*ptr);
+               }
+       }
+}
+
+
 static void linklist_free_simple(void *link)
 {
        MEM_freeN(link);
@@ -1003,6 +1030,10 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = {
        {sizeof(MLoopCol), "MLoopCol", 1, "WeightLoopCol", NULL, NULL, layerInterp_mloopcol, NULL,
         layerDefault_mloopcol, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol,
         layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol},
+       /* 33: CD_BM_ELEM_PYPTR */
+       {sizeof(void *), "", 1, NULL, layerCopy_bmesh_elem_py_ptr,
+        layerFree_bmesh_elem_py_ptr, NULL, NULL, NULL},
+
 /* END BMESH ONLY */
 
 
index 3a62eaa2eeb7c7fdee0e0fd8cd83e3c3ccdad332..6c052a402c9067fc0873852c43662f76fb028386 100644 (file)
@@ -179,6 +179,8 @@ typedef struct BMesh {
        ListBase errorstack;
        struct Object *ob; /* owner object */
        
+       void *py_handle;
+
        int opflag; /* current operator flag */
 } BMesh;
 
index f7f40e996173271822df1a81337bfbd9ca0927a5..d7358a4df1e76ea063b930fe15fa38702cbd6136 100644 (file)
@@ -63,10 +63,9 @@ typedef struct CustomDataExternal {
  * layers, each with a data type (e.g. MTFace, MDeformVert, etc.). */
 typedef struct CustomData {
        CustomDataLayer *layers;      /* CustomDataLayers, ordered by type */
-       int typemap[33];              /* runtime only! - maps types to indices of first layer of that type,
+       int typemap[34];              /* runtime only! - maps types to indices of first layer of that type,
                                       * MUST be >= CD_NUMTYPES, but we cant use a define here.
                                       * Correct size is ensured in CustomData_update_typemap assert() */
-       int pad1;
 
        int totlayer, maxlayer;       /* number of layers, size of layers array */
        int totsize, pad2;             /* in editmode, total size of all data layers */
@@ -110,9 +109,10 @@ typedef struct CustomData {
 #define CD_CREASE              30
 #define CD_ORIGSPACE_MLOOP     31
 #define CD_WEIGHT_MLOOPCOL     32
+#define CD_BM_ELEM_PYPTR       33
 /* BMESH ONLY END */
 
-#define CD_NUMTYPES            33
+#define CD_NUMTYPES            34
 
 /* Bits for CustomDataMask */
 #define CD_MASK_MVERT          (1 << CD_MVERT)
@@ -148,6 +148,7 @@ typedef struct CustomData {
 #define CD_MASK_CREASE         (1 << CD_CREASE)
 #define CD_MASK_ORIGSPACE_MLOOP        (1 << CD_ORIGSPACE_MLOOP)
 #define CD_MASK_WEIGHT_MLOOPCOL (1LL << CD_WEIGHT_MLOOPCOL)
+#define CD_MASK_BM_ELEM_PYPTR (1LL << CD_BM_ELEM_PYPTR)
 /* BMESH ONLY END */
 
 /* CustomData.flag */
index f0189d2077bbf084a80d8bb98b599f8e2f34cf71..8350166c2d06d11747a3616e53c10f8151ec0ef5 100644 (file)
@@ -31,6 +31,8 @@
 
 #include "BLI_math.h"
 
+#include "BKE_customdata.h"
+
 #include "bmesh.h"
 
 #include "../mathutils/mathutils.h"
@@ -1129,7 +1131,7 @@ static PyObject *bpy_bm_seq_subscript(BPy_BMElemSeq *self, PyObject *key)
                        return NULL;
                }
                else if (step != 1) {
-                       PyErr_SetString(PyExc_TypeError, "bpy_prop_collection[slice]: slice steps not supported");
+                       PyErr_SetString(PyExc_TypeError, "BMElemSeq[slice]: slice steps not supported");
                        return NULL;
                }
                else if (key_slice->start == Py_None && key_slice->stop == Py_None) {
@@ -1231,6 +1233,60 @@ static PyObject *bpy_bm_iter_next(BPy_BMIter *self)
 /* Dealloc Functions
  * ================= */
 
+static void bpy_bmesh_dealloc(BPy_BMesh *self)
+{
+       BMesh *bm = self->bm;
+
+       BM_data_layer_free(bm, &bm->vdata, CD_BM_ELEM_PYPTR);
+       BM_data_layer_free(bm, &bm->edata, CD_BM_ELEM_PYPTR);
+       BM_data_layer_free(bm, &bm->pdata, CD_BM_ELEM_PYPTR);
+       BM_data_layer_free(bm, &bm->ldata, CD_BM_ELEM_PYPTR);
+
+       bm->py_handle = NULL;
+
+       PyObject_DEL(self);
+}
+
+static void bpy_bmvert_dealloc(BPy_BMElem *self)
+{
+       BMesh *bm = self->bm;
+       if (bm) {
+               void **ptr = CustomData_bmesh_get(&bm->vdata, self->ele->data, CD_BM_ELEM_PYPTR);
+               *ptr = NULL;
+       }
+       PyObject_DEL(self);
+}
+
+static void bpy_bmedge_dealloc(BPy_BMElem *self)
+{
+       BMesh *bm = self->bm;
+       if (bm) {
+               void **ptr = CustomData_bmesh_get(&bm->edata, self->ele->data, CD_BM_ELEM_PYPTR);
+               *ptr = NULL;
+       }
+       PyObject_DEL(self);
+}
+
+static void bpy_bmface_dealloc(BPy_BMElem *self)
+{
+       BMesh *bm = self->bm;
+       if (bm) {
+               void **ptr = CustomData_bmesh_get(&bm->pdata, self->ele->data, CD_BM_ELEM_PYPTR);
+               *ptr = NULL;
+       }
+       PyObject_DEL(self);
+}
+
+static void bpy_bmloop_dealloc(BPy_BMElem *self)
+{
+       BMesh *bm = self->bm;
+       if (bm) {
+               void **ptr = CustomData_bmesh_get(&bm->ldata, self->ele->data, CD_BM_ELEM_PYPTR);
+               *ptr = NULL;
+       }
+       PyObject_DEL(self);
+}
+
 static void bpy_bm_seq_dealloc(BPy_BMElemSeq *self)
 {
        Py_XDECREF(self->py_ele);
@@ -1309,11 +1365,11 @@ void BPy_BM_init_types(void)
        /* only 1 iteratir so far */
        BPy_BMIter_Type.tp_iternext = (iternextfunc)bpy_bm_iter_next;
 
-       BPy_BMesh_Type.tp_dealloc     = NULL;
-       BPy_BMVert_Type.tp_dealloc    = NULL;
-       BPy_BMEdge_Type.tp_dealloc    = NULL;
-       BPy_BMFace_Type.tp_dealloc    = NULL;
-       BPy_BMLoop_Type.tp_dealloc    = NULL;
+       BPy_BMesh_Type.tp_dealloc     = (destructor)bpy_bmesh_dealloc;
+       BPy_BMVert_Type.tp_dealloc    = (destructor)bpy_bmvert_dealloc;
+       BPy_BMEdge_Type.tp_dealloc    = (destructor)bpy_bmedge_dealloc;
+       BPy_BMFace_Type.tp_dealloc    = (destructor)bpy_bmface_dealloc;
+       BPy_BMLoop_Type.tp_dealloc    = (destructor)bpy_bmloop_dealloc;
        BPy_BMElemSeq_Type.tp_dealloc = (destructor)bpy_bm_seq_dealloc;
        BPy_BMIter_Type.tp_dealloc    = NULL;
 
@@ -1351,44 +1407,104 @@ void BPy_BM_init_types(void)
 
 PyObject *BPy_BMesh_CreatePyObject(BMesh *bm)
 {
-       BPy_BMesh *self = PyObject_New(BPy_BMesh, &BPy_BMesh_Type);
-       self->bm = bm;
+       BPy_BMesh *self;
+
+       if (bm->py_handle) {
+               self = bm->py_handle;
+               Py_INCREF(self);
+       }
+       else {
+               self = PyObject_New(BPy_BMesh, &BPy_BMesh_Type);
+               self->bm = bm;
+
+               BM_data_layer_add(bm, &bm->vdata, CD_BM_ELEM_PYPTR);
+               BM_data_layer_add(bm, &bm->edata, CD_BM_ELEM_PYPTR);
+               BM_data_layer_add(bm, &bm->pdata, CD_BM_ELEM_PYPTR);
+               BM_data_layer_add(bm, &bm->ldata, CD_BM_ELEM_PYPTR);
+       }
+
        return (PyObject *)self;
 }
 
+
+
 PyObject *BPy_BMVert_CreatePyObject(BMesh *bm, BMVert *v)
 {
-       BPy_BMVert *self = PyObject_New(BPy_BMVert, &BPy_BMVert_Type);
-       BLI_assert(v != NULL);
-       self->bm = bm;
-       self->v  = v;
+       BPy_BMVert *self;
+
+       void **ptr = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_BM_ELEM_PYPTR);
+
+       if (*ptr != NULL) {
+               self = *ptr;
+               Py_INCREF(self);
+       }
+       else {
+               self = PyObject_New(BPy_BMVert, &BPy_BMVert_Type);
+               BLI_assert(v != NULL);
+               self->bm = bm;
+               self->v  = v;
+               *ptr = self;
+       }
        return (PyObject *)self;
 }
 
 PyObject *BPy_BMEdge_CreatePyObject(BMesh *bm, BMEdge *e)
 {
-       BPy_BMEdge *self = PyObject_New(BPy_BMEdge, &BPy_BMEdge_Type);
-       BLI_assert(e != NULL);
-       self->bm = bm;
-       self->e  = e;
+       BPy_BMEdge *self;
+
+       void **ptr = CustomData_bmesh_get(&bm->edata, e->head.data, CD_BM_ELEM_PYPTR);
+
+       if (*ptr != NULL) {
+               self = *ptr;
+               Py_INCREF(self);
+       }
+       else {
+               self = PyObject_New(BPy_BMEdge, &BPy_BMEdge_Type);
+               BLI_assert(e != NULL);
+               self->bm = bm;
+               self->e  = e;
+               *ptr = self;
+       }
        return (PyObject *)self;
 }
 
 PyObject *BPy_BMFace_CreatePyObject(BMesh *bm, BMFace *f)
 {
-       BPy_BMFace *self = PyObject_New(BPy_BMFace, &BPy_BMFace_Type);
-       BLI_assert(f != NULL);
-       self->bm = bm;
-       self->f  = f;
+       BPy_BMFace *self;
+
+       void **ptr = CustomData_bmesh_get(&bm->pdata, f->head.data, CD_BM_ELEM_PYPTR);
+
+       if (*ptr != NULL) {
+               self = *ptr;
+               Py_INCREF(self);
+       }
+       else {
+               self = PyObject_New(BPy_BMFace, &BPy_BMFace_Type);
+               BLI_assert(f != NULL);
+               self->bm = bm;
+               self->f  = f;
+               *ptr = self;
+       }
        return (PyObject *)self;
 }
 
 PyObject *BPy_BMLoop_CreatePyObject(BMesh *bm, BMLoop *l)
 {
-       BPy_BMLoop *self = PyObject_New(BPy_BMLoop, &BPy_BMLoop_Type);
-       BLI_assert(l != NULL);
-       self->bm = bm;
-       self->l  = l;
+       BPy_BMLoop *self;
+
+       void **ptr = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_BM_ELEM_PYPTR);
+
+       if (*ptr != NULL) {
+               self = *ptr;
+               Py_INCREF(self);
+       }
+       else {
+               self = PyObject_New(BPy_BMLoop, &BPy_BMLoop_Type);
+               BLI_assert(l != NULL);
+               self->bm = bm;
+               self->l  = l;
+               *ptr = self;
+       }
        return (PyObject *)self;
 }