bmesh py api: change .from_mesh() / .to_mesh() to be class methods of BMesh rather than functions in the module.

added example script which converts a mesh to a bmesh, edits and converts back again.
This commit is contained in:
Campbell Barton 2012-03-11 02:45:27 +00:00
parent 0c50bedd9c
commit 21fd09c028
5 changed files with 123 additions and 65 deletions

@ -0,0 +1,21 @@
# This example assumes we have a mesh object selected
import bpy
import bmesh
# Get the active mesh
me = bpy.context.object.data
# Get a BMesh representation
bm = bmesh.new() # create an empty BMesh
bm.from_mesh(me) # fill it in from a Mesh
# Modify the BMesh, can do anything here...
for v in bm.verts:
v.co.x += 1.0
# Finish up, write the bmesh back to the mesh
bm.to_mesh(me)

@ -40,17 +40,14 @@
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BKE_tessmesh.h" #include "BKE_tessmesh.h"
#include "BKE_depsgraph.h"
#include "DNA_mesh_types.h" #include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "../generic/py_capi_utils.h" #include "../generic/py_capi_utils.h"
#include "bmesh_py_api.h" /* own include */ #include "bmesh_py_api.h" /* own include */
PyDoc_STRVAR(bpy_bm_new_doc, PyDoc_STRVAR(bpy_bm_new_doc,
".. method:: new()\n" ".. method:: new()\n"
"\n" "\n"
@ -70,88 +67,40 @@ static PyObject *bpy_bm_new(PyObject *UNUSED(self))
return (PyObject *)py_bmesh; return (PyObject *)py_bmesh;
} }
PyDoc_STRVAR(bpy_bm_from_mesh_doc, PyDoc_STRVAR(bpy_bm_from_edit_mesh_doc,
".. method:: from_mesh(mesh)\n" ".. method:: from_edit_mesh(mesh)\n"
"\n" "\n"
" Return a BMesh from this mesh, currently the mesh must already be in editmode.\n" " Return a BMesh from this mesh, currently the mesh must already be in editmode.\n"
"\n" "\n"
" :return: the BMesh assosiated with this mesh.\n" " :return: the BMesh assosiated with this mesh.\n"
" :rtype: :class:`bmesh.types.BMesh`\n" " :rtype: :class:`bmesh.types.BMesh`\n"
); );
static PyObject *bpy_bm_from_edit_mesh(PyObject *UNUSED(self), PyObject *value)
static PyObject *bpy_bm_from_mesh(PyObject *UNUSED(self), PyObject *value)
{ {
BPy_BMesh *py_bmesh; BPy_BMesh *py_bmesh;
BMesh *bm; BMesh *bm;
Mesh *me = PyC_RNA_AsPointer(value, "Mesh"); Mesh *me = PyC_RNA_AsPointer(value, "Mesh");
int py_owns;
if (me == NULL) { if (me == NULL) {
return NULL; return NULL;
} }
/* temp! */ if (me->edit_btmesh == NULL) {
if (!me->edit_btmesh) { PyErr_SetString(PyExc_ValueError,
bm = BM_mesh_create(NULL, &bm_mesh_allocsize_default); "The mesh must be in editmode");
BM_mesh_to_bmesh(bm, me, 0, 0); /* BMESH_TODO add args */ return NULL;
py_owns = TRUE;
}
else {
bm = me->edit_btmesh->bm;
py_owns = FALSE;
} }
bm = me->edit_btmesh->bm;
py_bmesh = (BPy_BMesh *)BPy_BMesh_CreatePyObject(bm); py_bmesh = (BPy_BMesh *)BPy_BMesh_CreatePyObject(bm);
py_bmesh->py_owns = py_owns; py_bmesh->py_owns = FALSE;
return (PyObject *)py_bmesh; return (PyObject *)py_bmesh;
} }
PyDoc_STRVAR(bpy_bm_to_mesh_doc,
".. method:: to_mesh(mesh, bmesh)\n"
"\n"
" Return a BMesh from this mesh, currently the mesh must already be in editmode.\n"
"\n"
" :return: the BMesh assosiated with this mesh.\n"
" :rtype: :class:`bmesh.types.BMesh`\n"
);
static PyObject *bpy_bm_to_mesh(PyObject *UNUSED(self), PyObject *args)
{
PyObject *py_mesh;
BPy_BMesh *py_bmesh;
Mesh *me;
BMesh *bm;
if (!PyArg_ParseTuple(args, "OO!:to_mesh", &py_mesh, &BPy_BMesh_Type, &py_bmesh) ||
!(me = PyC_RNA_AsPointer(py_mesh, "Mesh")))
{
return NULL;
}
BPY_BM_CHECK_OBJ(py_bmesh);
if (me->edit_btmesh) {
PyErr_Format(PyExc_ValueError,
"to_mesh(): Mesh '%s' is in editmode", me->id.name + 2);
return NULL;
}
bm = py_bmesh->bm;
BM_mesh_from_bmesh(bm, me, FALSE);
/* we could have the user do this but if they forget blender can easy crash
* since the references arrays for the objects derived meshes are now invalid */
DAG_id_tag_update(&me->id, OB_RECALC_DATA);
Py_RETURN_NONE;
}
static struct PyMethodDef BPy_BM_methods[] = { static struct PyMethodDef BPy_BM_methods[] = {
/* THESE NAMES MAY CHANGE! */ {"new", (PyCFunction)bpy_bm_new, METH_NOARGS, bpy_bm_new_doc},
{"new", (PyCFunction)bpy_bm_new, METH_NOARGS, bpy_bm_new_doc}, {"from_edit_mesh", (PyCFunction)bpy_bm_from_edit_mesh, METH_O, bpy_bm_from_edit_mesh_doc},
{"from_mesh", (PyCFunction)bpy_bm_from_mesh, METH_O, bpy_bm_from_mesh_doc},
{"to_mesh", (PyCFunction)bpy_bm_to_mesh, METH_VARARGS, bpy_bm_to_mesh_doc},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };
@ -163,6 +112,12 @@ PyDoc_STRVAR(BPy_BM_doc,
"\n" "\n"
"* :mod:`bmesh.utils`\n" "* :mod:`bmesh.utils`\n"
"* :mod:`bmesh.types`\n" "* :mod:`bmesh.types`\n"
"\n"
"\n"
"Example Script\n"
"--------------\n"
"\n"
".. literalinclude:: ../../../release/scripts/templates/bmesh_simple.py\n"
); );
static struct PyModuleDef BPy_BM_module_def = { static struct PyModuleDef BPy_BM_module_def = {
PyModuleDef_HEAD_INIT, PyModuleDef_HEAD_INIT,
@ -185,7 +140,6 @@ PyObject *BPyInit_bmesh(void)
BPy_BM_init_types(); BPy_BM_init_types();
BPy_BM_init_select_types(); BPy_BM_init_select_types();
mod = PyModule_Create(&BPy_BM_module_def); mod = PyModule_Create(&BPy_BM_module_def);
/* bmesh.types */ /* bmesh.types */

@ -31,6 +31,10 @@
#include "BLI_math.h" #include "BLI_math.h"
#include "DNA_mesh_types.h"
#include "DNA_object_types.h"
#include "BKE_depsgraph.h"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "bmesh.h" #include "bmesh.h"
@ -586,6 +590,82 @@ static PyGetSetDef bpy_bmloop_getseters[] = {
/* Mesh /* Mesh
* ---- */ * ---- */
PyDoc_STRVAR(bpy_bmesh_to_mesh_doc,
".. method:: to_mesh(mesh)\n"
"\n"
" Writes this BMesh data into an existing Mesh datablock.\n"
"\n"
" :arg mesh: The mesh data to write into.\n"
" :type mesh: :class:`Mesh`\n"
);
static PyObject *bpy_bmesh_to_mesh(BPy_BMesh *self, PyObject *args)
{
PyObject *py_mesh;
Mesh *me;
BMesh *bm;
BPY_BM_CHECK_OBJ(self);
if (!PyArg_ParseTuple(args, "O:to_mesh", &py_mesh) ||
!(me = PyC_RNA_AsPointer(py_mesh, "Mesh")))
{
return NULL;
}
/* we could allow this but its almost certainly _not_ what script authors want */
if (me->edit_btmesh) {
PyErr_Format(PyExc_ValueError,
"to_mesh(): Mesh '%s' is in editmode", me->id.name + 2);
return NULL;
}
bm = self->bm;
BM_mesh_from_bmesh(bm, me, FALSE);
/* we could have the user do this but if they forget blender can easy crash
* since the references arrays for the objects derived meshes are now invalid */
DAG_id_tag_update(&me->id, OB_RECALC_DATA);
Py_RETURN_NONE;
}
PyDoc_STRVAR(bpy_bmesh_from_mesh_doc,
".. method:: from_mesh(mesh, use_shape_key=False, shape_key_index=0)\n"
"\n"
" Initialize this bmesh from existing mesh datablock.\n"
"\n"
" :arg mesh: The mesh data to load.\n"
" :type mesh: :class:`Mesh`\n"
" :arg use_shape_key: Use the locations from a shape key.\n"
" :type use_shape_key: boolean\n"
" :arg shape_key_index: The shape key index to use.\n"
" :type shape_key_index: int\n"
);
static PyObject *bpy_bmesh_from_mesh(BPy_BMesh *self, PyObject *args, PyObject *kw)
{
static const char *kwlist[] = {"mesh", "use_shape_key", "shape_key_index", NULL};
BMesh *bm;
PyObject *py_mesh;
Mesh *me;
int use_shape_key = FALSE;
int shape_key_index = 0;
if (!PyArg_ParseTupleAndKeywords(args, kw, "O|ii:to_mesh", (char **)kwlist,
&py_mesh, &use_shape_key, &shape_key_index) ||
!(me = PyC_RNA_AsPointer(py_mesh, "Mesh")))
{
return NULL;
}
bm = self->bm;
BM_mesh_to_bmesh(bm, me, use_shape_key, shape_key_index + 1);
Py_RETURN_NONE;
}
PyDoc_STRVAR(bpy_bmesh_select_flush_mode_doc, PyDoc_STRVAR(bpy_bmesh_select_flush_mode_doc,
".. method:: select_flush_mode()\n" ".. method:: select_flush_mode()\n"
"\n" "\n"
@ -1716,6 +1796,9 @@ static PyObject *bpy_bmelemseq_index_update(BPy_BMElemSeq *self)
static struct PyMethodDef bpy_bmesh_methods[] = { static struct PyMethodDef bpy_bmesh_methods[] = {
{"from_mesh", (PyCFunction)bpy_bmesh_from_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bmesh_from_mesh_doc},
{"to_mesh", (PyCFunction)bpy_bmesh_to_mesh, METH_VARARGS, bpy_bmesh_to_mesh_doc},
{"select_flush_mode", (PyCFunction)bpy_bmesh_select_flush_mode, METH_NOARGS, bpy_bmesh_select_flush_mode_doc}, {"select_flush_mode", (PyCFunction)bpy_bmesh_select_flush_mode, METH_NOARGS, bpy_bmesh_select_flush_mode_doc},
{"select_flush", (PyCFunction)bpy_bmesh_select_flush, METH_O, bpy_bmesh_select_flush_doc}, {"select_flush", (PyCFunction)bpy_bmesh_select_flush, METH_O, bpy_bmesh_select_flush_doc},
{"normal_update", (PyCFunction)bpy_bmesh_normal_update, METH_VARARGS, bpy_bmesh_normal_update_doc}, {"normal_update", (PyCFunction)bpy_bmesh_normal_update, METH_VARARGS, bpy_bmesh_normal_update_doc},

@ -62,7 +62,7 @@ typedef struct BPy_BMElem {
typedef struct BPy_BMesh { typedef struct BPy_BMesh {
PyObject_VAR_HEAD PyObject_VAR_HEAD
struct BMesh *bm; /* keep first */ struct BMesh *bm; /* keep first */
char py_owns; char py_owns; /* when set, free along with the PyObject */
} BPy_BMesh; } BPy_BMesh;
/* element types */ /* element types */