8316d33ea385639dde86ee7afb3ec15864fb6bef
[blender.git] / source / blender / python / bmesh / bmesh_py_types_meshdata.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2012 Blender Foundation.
19  * All rights reserved.
20  *
21  * Contributor(s): Campbell Barton
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/python/bmesh/bmesh_py_types_meshdata.c
27  *  \ingroup pybmesh
28  *
29  * This file defines customdata types which can't be accessed as primitive
30  * python types such as MDeformVert, MLoopUV, MTexPoly
31  */
32
33 #include <Python.h>
34
35 #include "../mathutils/mathutils.h"
36
37 #include "DNA_object_types.h"
38 #include "DNA_meshdata_types.h"
39
40 #include "BLI_utildefines.h"
41 #include "BLI_math_vector.h"
42
43 #include "BKE_deform.h"
44 #include "BKE_library.h"
45
46 #include "bmesh_py_types_meshdata.h"
47
48
49 /* Mesh BMTexPoly
50  * ************** */
51
52 #define BPy_BMTexPoly_Check(v)  (Py_TYPE(v) == &BPy_BMTexPoly_Type)
53
54 typedef struct BPy_BMTexPoly {
55         PyObject_VAR_HEAD
56         MTexPoly *data;
57 } BPy_BMTexPoly;
58
59 extern PyObject *pyrna_id_CreatePyObject(ID *id);
60 extern int       pyrna_id_FromPyObject(PyObject *obj, ID **id);
61
62 PyDoc_STRVAR(bpy_bmtexpoly_image_doc,
63 "Image or None.\n\n:type: :class:`bpy.types.Image`"
64 );
65 static PyObject *bpy_bmtexpoly_image_get(BPy_BMTexPoly *self, void *UNUSED(closure))
66 {
67         return pyrna_id_CreatePyObject((ID *)self->data->tpage);
68 }
69
70 static int bpy_bmtexpoly_image_set(BPy_BMTexPoly *self, PyObject *value, void *UNUSED(closure))
71 {
72         ID *id;
73
74         if (value == Py_None) {
75                 id = NULL;
76         }
77         else if (pyrna_id_FromPyObject(value, &id) && id && GS(id->name) == ID_IM) {
78                 /* pass */
79         }
80         else {
81                 PyErr_Format(PyExc_KeyError, "BMTexPoly.image = x"
82                              "expected an image or None, not '%.200s'",
83                              Py_TYPE(value)->tp_name);
84                 return -1;
85         }
86
87         id_lib_extern(id);
88         self->data->tpage = (struct Image *)id;
89
90         return 0;
91 }
92
93 static PyGetSetDef bpy_bmtexpoly_getseters[] = {
94         /* attributes match rna_def_mtpoly  */
95         {(char *)"image", (getter)bpy_bmtexpoly_image_get, (setter)bpy_bmtexpoly_image_set, (char *)bpy_bmtexpoly_image_doc, NULL},
96
97         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
98 };
99
100 PyTypeObject BPy_BMTexPoly_Type = {{{0}}}; /* bm.loops.layers.uv.active */
101
102 static void bm_init_types_bmtexpoly(void)
103 {
104         BPy_BMTexPoly_Type.tp_basicsize = sizeof(BPy_BMTexPoly);
105
106         BPy_BMTexPoly_Type.tp_name = "BMTexPoly";
107
108         BPy_BMTexPoly_Type.tp_doc = NULL; // todo
109
110         BPy_BMTexPoly_Type.tp_getset = bpy_bmtexpoly_getseters;
111
112         BPy_BMTexPoly_Type.tp_flags = Py_TPFLAGS_DEFAULT;
113
114         PyType_Ready(&BPy_BMTexPoly_Type);
115 }
116
117 int BPy_BMTexPoly_AssignPyObject(struct MTexPoly *mtpoly, PyObject *value)
118 {
119         if (UNLIKELY(!BPy_BMTexPoly_Check(value))) {
120                 PyErr_Format(PyExc_TypeError, "expected BMTexPoly, not a %.200s", Py_TYPE(value)->tp_name);
121                 return -1;
122         }
123         else {
124                 *((MTexPoly *)mtpoly) = *(((BPy_BMTexPoly *)value)->data);
125                 return 0;
126         }
127 }
128
129 PyObject *BPy_BMTexPoly_CreatePyObject(struct MTexPoly *mtpoly)
130 {
131         BPy_BMTexPoly *self = PyObject_New(BPy_BMTexPoly, &BPy_BMTexPoly_Type);
132         self->data = mtpoly;
133         return (PyObject *)self;
134 }
135
136 /* --- End Mesh BMTexPoly --- */
137
138 /* Mesh Loop UV
139  * ************ */
140
141 #define BPy_BMLoopUV_Check(v)  (Py_TYPE(v) == &BPy_BMLoopUV_Type)
142
143 typedef struct BPy_BMLoopUV {
144         PyObject_VAR_HEAD
145         MLoopUV *data;
146 } BPy_BMLoopUV;
147
148 PyDoc_STRVAR(bpy_bmloopuv_uv_doc,
149 "Loops UV (as a 2D Vector).\n\n:type: :class:`mathutils.Vector`"
150 );
151 static PyObject *bpy_bmloopuv_uv_get(BPy_BMLoopUV *self, void *UNUSED(closure))
152 {
153         return Vector_CreatePyObject(self->data->uv, 2, Py_WRAP, NULL);
154 }
155
156 static int bpy_bmloopuv_uv_set(BPy_BMLoopUV *self, PyObject *value, void *UNUSED(closure))
157 {
158         float tvec[2];
159         if (mathutils_array_parse(tvec, 2, 2, value, "BMLoopUV.uv") != -1) {
160                 copy_v2_v2(self->data->uv, tvec);
161                 return 0;
162         }
163         else {
164                 return -1;
165         }
166 }
167
168 PyDoc_STRVAR(bpy_bmloopuv_flag__pin_uv_doc,
169 "UV pin state.\n\n:type: boolean"
170 );
171 PyDoc_STRVAR(bpy_bmloopuv_flag__select_doc,
172 "UV select state.\n\n:type: boolean"
173 );
174 PyDoc_STRVAR(bpy_bmloopuv_flag__select_edge_doc,
175 "UV edge select state.\n\n:type: boolean"
176 );
177
178
179 static PyObject *bpy_bmloopuv_flag_get(BPy_BMLoopUV *self, void *flag_p)
180 {
181         const int flag = GET_INT_FROM_POINTER(flag_p);
182         return PyBool_FromLong(self->data->flag & flag);
183 }
184
185 static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag_p)
186 {
187         const int flag = GET_INT_FROM_POINTER(flag_p);
188
189         switch (PyLong_AsLong(value)) {
190                 case TRUE:
191                         self->data->flag |= flag;
192                         return 0;
193                 case FALSE:
194                         self->data->flag &= ~flag;
195                         return 0;
196                 default:
197                         PyErr_SetString(PyExc_TypeError,
198                                         "expected a boolean type 0/1");
199                         return -1;
200         }
201 }
202
203 static PyGetSetDef bpy_bmloopuv_getseters[] = {
204         /* attributes match rna_def_mloopuv  */
205         {(char *)"uv",          (getter)bpy_bmloopuv_uv_get,   (setter)bpy_bmloopuv_uv_set,   (char *)bpy_bmloopuv_uv_doc, NULL},
206         {(char *)"pin_uv",      (getter)bpy_bmloopuv_flag_get, (setter)bpy_bmloopuv_flag_set, (char *)bpy_bmloopuv_flag__pin_uv_doc, (void *)MLOOPUV_PINNED},
207         {(char *)"select",      (getter)bpy_bmloopuv_flag_get, (setter)bpy_bmloopuv_flag_set, (char *)bpy_bmloopuv_flag__select_doc, (void *)MLOOPUV_VERTSEL},
208         {(char *)"select_edge", (getter)bpy_bmloopuv_flag_get, (setter)bpy_bmloopuv_flag_set, (char *)bpy_bmloopuv_flag__select_edge_doc, (void *)MLOOPUV_EDGESEL},
209
210         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
211 };
212
213 PyTypeObject BPy_BMLoopUV_Type = {{{0}}}; /* bm.loops.layers.uv.active */
214
215 static void bm_init_types_bmloopuv(void)
216 {
217         BPy_BMLoopUV_Type.tp_basicsize = sizeof(BPy_BMLoopUV);
218
219         BPy_BMLoopUV_Type.tp_name = "BMLoopUV";
220
221         BPy_BMLoopUV_Type.tp_doc = NULL; // todo
222
223         BPy_BMLoopUV_Type.tp_getset = bpy_bmloopuv_getseters;
224
225         BPy_BMLoopUV_Type.tp_flags = Py_TPFLAGS_DEFAULT;
226
227         PyType_Ready(&BPy_BMLoopUV_Type);
228 }
229
230 int BPy_BMLoopUV_AssignPyObject(struct MLoopUV *mloopuv, PyObject *value)
231 {
232         if (UNLIKELY(!BPy_BMLoopUV_Check(value))) {
233                 PyErr_Format(PyExc_TypeError, "expected BMLoopUV, not a %.200s", Py_TYPE(value)->tp_name);
234                 return -1;
235         }
236         else {
237                 *((MLoopUV *)mloopuv) = *(((BPy_BMLoopUV *)value)->data);
238                 return 0;
239         }
240 }
241
242 PyObject *BPy_BMLoopUV_CreatePyObject(struct MLoopUV *mloopuv)
243 {
244         BPy_BMLoopUV *self = PyObject_New(BPy_BMLoopUV, &BPy_BMLoopUV_Type);
245         self->data = mloopuv;
246         return (PyObject *)self;
247 }
248
249 /* --- End Mesh Loop UV --- */
250
251 /* Mesh Loop Color
252  * *************** */
253
254 /* This simply provides a color wrapper for
255  * color which uses mathutils callbacks for mathutils.Color
256  */
257
258 #define MLOOPCOL_FROM_CAPSULE(color_capsule)  \
259         ((MLoopCol *)PyCapsule_GetPointer(color_capsule, NULL))
260
261 static void mloopcol_to_float(const MLoopCol *mloopcol, float col_r[3])
262 {
263         rgb_uchar_to_float(col_r, (unsigned char *)&mloopcol->r);
264 }
265
266 static void mloopcol_from_float(MLoopCol *mloopcol, const float col[3])
267 {
268         rgb_float_to_uchar((unsigned char *)&mloopcol->r, col);
269 }
270
271 static unsigned char mathutils_bmloopcol_cb_index = -1;
272
273 static int mathutils_bmloopcol_check(BaseMathObject *UNUSED(bmo))
274 {
275         /* always ok */
276         return 0;
277 }
278
279 static int mathutils_bmloopcol_get(BaseMathObject *bmo, int UNUSED(subtype))
280 {
281         MLoopCol *mloopcol = MLOOPCOL_FROM_CAPSULE(bmo->cb_user);
282         mloopcol_to_float(mloopcol, bmo->data);
283         return 0;
284 }
285
286 static int mathutils_bmloopcol_set(BaseMathObject *bmo, int UNUSED(subtype))
287 {
288         MLoopCol *mloopcol = MLOOPCOL_FROM_CAPSULE(bmo->cb_user);
289         mloopcol_from_float(mloopcol, bmo->data);
290         return 0;
291 }
292
293 static int mathutils_bmloopcol_get_index(BaseMathObject *bmo, int subtype, int UNUSED(index))
294 {
295         /* lazy, avoid repeteing the case statement */
296         if (mathutils_bmloopcol_get(bmo, subtype) == -1)
297                 return -1;
298         return 0;
299 }
300
301 static int mathutils_bmloopcol_set_index(BaseMathObject *bmo, int subtype, int index)
302 {
303         const float f = bmo->data[index];
304
305         /* lazy, avoid repeteing the case statement */
306         if (mathutils_bmloopcol_get(bmo, subtype) == -1)
307                 return -1;
308
309         bmo->data[index] = f;
310         return mathutils_bmloopcol_set(bmo, subtype);
311 }
312
313 Mathutils_Callback mathutils_bmloopcol_cb = {
314         mathutils_bmloopcol_check,
315         mathutils_bmloopcol_get,
316         mathutils_bmloopcol_set,
317         mathutils_bmloopcol_get_index,
318         mathutils_bmloopcol_set_index
319 };
320
321 static void bm_init_types_bmloopcol(void)
322 {
323         /* pass */
324         mathutils_bmloopcol_cb_index = Mathutils_RegisterCallback(&mathutils_bmloopcol_cb);
325 }
326
327 int BPy_BMLoopColor_AssignPyObject(struct MLoopCol *mloopcol, PyObject *value)
328 {
329         float tvec[3];
330         if (mathutils_array_parse(tvec, 3, 3, value, "BMLoopCol") != -1) {
331                 mloopcol_from_float(mloopcol, tvec);
332                 return 0;
333         }
334         else {
335                 return -1;
336         }
337 }
338
339 PyObject *BPy_BMLoopColor_CreatePyObject(struct MLoopCol *data)
340 {
341         PyObject *color_capsule;
342         color_capsule = PyCapsule_New(data, NULL, NULL);
343         return Color_CreatePyObject_cb(color_capsule, mathutils_bmloopcol_cb_index, 0);
344 }
345
346 #undef MLOOPCOL_FROM_CAPSULE
347
348 /* --- End Mesh Loop Color --- */
349
350
351 /* Mesh Deform Vert
352  * **************** */
353
354 /**
355  * This is python type wraps a deform vert as a python dictionary,
356  * hiding the #MDeformWeight on access, since the mapping is very close, eg:
357  *
358  * C:
359  *     weight = defvert_find_weight(dv, group_nr);
360  *     defvert_remove_group(dv, dw)
361  *
362  * Py:
363  *     weight = dv[group_nr]
364  *     del dv[group_nr]
365  *
366  * \note: there is nothing BMesh specific here,
367  * its only that BMesh is the only part of blender that uses a hand written api like this.
368  * This type could eventually be used to access lattice weights.
369  *
370  * \note: Many of blender-api's dict-like-wrappers act like ordered dicts,
371  * This is intentional _not_ ordered, the weights can be in any order and it wont matter,
372  * the order should not be used in the api in any meaningful way (as with a python dict)
373  * only expose as mapping, not a sequence.
374  */
375
376 #define BPy_BMDeformVert_Check(v)  (Py_TYPE(v) == &BPy_BMDeformVert_Type)
377
378 typedef struct BPy_BMDeformVert {
379         PyObject_VAR_HEAD
380         MDeformVert *data;
381 } BPy_BMDeformVert;
382
383
384 /* Mapping Protocols
385  * ================= */
386
387 static int bpy_bmdeformvert_len(BPy_BMDeformVert *self)
388 {
389         return self->data->totweight;
390 }
391
392 static PyObject *bpy_bmdeformvert_subscript(BPy_BMDeformVert *self, PyObject *key)
393 {
394         if (PyIndex_Check(key)) {
395                 int i;
396                 i = PyNumber_AsSsize_t(key, PyExc_IndexError);
397                 if (i == -1 && PyErr_Occurred()) {
398                         return NULL;
399                 }
400                 else {
401                         MDeformWeight *dw = defvert_find_index(self->data, i);
402
403                         if (dw == NULL) {
404                                 PyErr_SetString(PyExc_KeyError, "BMDeformVert[key] = x: "
405                                                 "key not found");
406                                 return NULL;
407                         }
408                         else {
409                                 return PyFloat_FromDouble(dw->weight);
410                         }
411                 }
412         }
413         else {
414                 PyErr_Format(PyExc_TypeError,
415                              "BMDeformVert keys must be integers, not %.200s",
416                              Py_TYPE(key)->tp_name);
417                 return NULL;
418         }
419 }
420
421 static int bpy_bmdeformvert_ass_subscript(BPy_BMDeformVert *self, PyObject *key, PyObject *value)
422 {
423         if (PyIndex_Check(key)) {
424                 int i;
425
426                 i = PyNumber_AsSsize_t(key, PyExc_IndexError);
427                 if (i == -1 && PyErr_Occurred()) {
428                         return -1;
429                 }
430
431                 if (value) {
432                         /* dvert[group_index] = 0.5 */
433                         if (i < 0) {
434                                 PyErr_SetString(PyExc_KeyError, "BMDeformVert[key] = x: "
435                                                 "weight keys can't be negative");
436                                 return -1;
437                         }
438                         else {
439                                 MDeformWeight *dw = defvert_verify_index(self->data, i);
440                                 const float f = PyFloat_AsDouble(value);
441                                 if (f == -1 && PyErr_Occurred()) { // parsed key not a number
442                                         PyErr_SetString(PyExc_TypeError,
443                                                         "BMDeformVert[key] = x: "
444                                                         "argument not a number");
445                                         return -1;
446                                 }
447
448                                 dw->weight = CLAMPIS(f, 0.0f, 1.0f);
449                         }
450                 }
451                 else {
452                         /* del dvert[group_index] */
453                         MDeformWeight *dw = defvert_find_index(self->data, i);
454
455                         if (dw == NULL) {
456                                 PyErr_SetString(PyExc_KeyError, "del BMDeformVert[key]: "
457                                                 "key not found");
458                         }
459                         defvert_remove_group(self->data, dw);
460                 }
461
462                 return 0;
463
464         }
465         else {
466                 PyErr_Format(PyExc_TypeError,
467                              "BMDeformVert keys must be integers, not %.200s",
468                              Py_TYPE(key)->tp_name);
469                 return -1;
470         }
471 }
472
473 static int bpy_bmdeformvert_contains(BPy_BMDeformVert *self, PyObject *value)
474 {
475         const int key = PyLong_AsSsize_t(value);
476
477         if (key == -1 && PyErr_Occurred()) {
478                 PyErr_SetString(PyExc_TypeError,
479                                 "BMDeformVert.__contains__: expected an int");
480                 return -1;
481         }
482
483         return (defvert_find_index(self->data, key) != NULL) ? 1 : 0;
484 }
485
486 /* only defined for __contains__ */
487 static PySequenceMethods bpy_bmdeformvert_as_sequence = {
488         (lenfunc)bpy_bmdeformvert_len,               /* sq_length */
489         NULL,                                        /* sq_concat */
490         NULL,                                        /* sq_repeat */
491
492         /* note: if this is set PySequence_Check() returns True,
493          * but in this case we dont want to be treated as a seq */
494         NULL,                                        /* sq_item */
495
496         NULL,                                        /* sq_slice */
497         NULL,                                        /* sq_ass_item */
498         NULL,                                        /* *was* sq_ass_slice */
499         (objobjproc)bpy_bmdeformvert_contains,       /* sq_contains */
500         (binaryfunc) NULL,                           /* sq_inplace_concat */
501         (ssizeargfunc) NULL,                         /* sq_inplace_repeat */
502         };
503
504 static PyMappingMethods bpy_bmdeformvert_as_mapping = {
505         (lenfunc)bpy_bmdeformvert_len,
506         (binaryfunc)bpy_bmdeformvert_subscript,
507         (objobjargproc)bpy_bmdeformvert_ass_subscript
508 };
509
510 /* Methods
511  * ======= */
512
513 PyDoc_STRVAR(bpy_bmdeformvert_keys_doc,
514 ".. method:: keys()\n"
515 "\n"
516 "   Return the group indices used by this vertex\n"
517 "   (matching pythons dict.keys() functionality).\n"
518 "\n"
519 "   :return: the deform group this vertex uses\n"
520 "   :rtype: list of ints\n"
521 );
522 static PyObject *bpy_bmdeformvert_keys(BPy_BMDeformVert *self)
523 {
524         PyObject *ret;
525         int i;
526         MDeformWeight *dw = self->data->dw;
527
528         ret = PyList_New(self->data->totweight);
529         for (i = 0; i < self->data->totweight; i++, dw++) {
530                 PyList_SET_ITEM(ret, i, PyLong_FromSsize_t(dw->def_nr));
531         }
532
533         return ret;
534 }
535
536 PyDoc_STRVAR(bpy_bmdeformvert_values_doc,
537 ".. method:: items()\n"
538 "\n"
539 "   Return (group, weight) pairs for this vertex\n"
540 "   (matching pythons dict.items() functionality).\n"
541 "\n"
542 "   :return: (key, value) pairs for each deform weight of this vertex.\n"
543 "   :rtype: list of tuples\n"
544 );
545 static PyObject *bpy_bmdeformvert_values(BPy_BMDeformVert *self)
546 {
547         PyObject *ret;
548         int i;
549         MDeformWeight *dw = self->data->dw;
550
551         ret = PyList_New(self->data->totweight);
552         for (i = 0; i < self->data->totweight; i++, dw++) {
553                 PyList_SET_ITEM(ret, i, PyFloat_FromDouble(dw->weight));
554         }
555
556         return ret;
557 }
558
559 PyDoc_STRVAR(bpy_bmdeformvert_items_doc,
560 ".. method:: values()\n"
561 "\n"
562 "   Return the weights of the deform vertex\n"
563 "   (matching pythons dict.values() functionality).\n"
564 "\n"
565 "   :return: The weights that influence this vertex\n"
566 "   :rtype: list of floats\n"
567 );
568 static PyObject *bpy_bmdeformvert_items(BPy_BMDeformVert *self)
569 {
570         PyObject *ret;
571         PyObject *item;
572         int i;
573         MDeformWeight *dw = self->data->dw;
574
575         ret = PyList_New(self->data->totweight);
576         for (i = 0; i < self->data->totweight; i++, dw++) {
577                 item = PyTuple_New(2);
578
579                 PyTuple_SET_ITEM(item, 0, PyLong_FromSsize_t(dw->def_nr));
580                 PyTuple_SET_ITEM(item, 1, PyFloat_FromDouble(dw->weight));
581
582                 PyList_SET_ITEM(ret, i, item);
583         }
584
585         return ret;
586 }
587
588 PyDoc_STRVAR(bpy_bmdeformvert_get_doc,
589 ".. method:: get(key, default=None)\n"
590 "\n"
591 "   Returns the deform weight matching the key or default\n"
592 "   when not found (matches pythons dictionary function of the same name).\n"
593 "\n"
594 "   :arg key: The key associated with deform weight.\n"
595 "   :type key: int\n"
596 "   :arg default: Optional argument for the value to return if\n"
597 "      *key* is not found.\n"
598 "   :type default: Undefined\n"
599 );
600 static PyObject *bpy_bmdeformvert_get(BPy_BMDeformVert *self, PyObject *args)
601 {
602         int key;
603         PyObject *def = Py_None;
604
605         if (!PyArg_ParseTuple(args, "i|O:get", &key, &def)) {
606                 return NULL;
607         }
608         else {
609                 MDeformWeight *dw = defvert_find_index(self->data, key);
610
611                 if (dw) {
612                         return PyFloat_FromDouble(dw->weight);
613                 }
614                 else {
615                         return Py_INCREF(def), def;
616                 }
617         }
618 }
619
620
621 PyDoc_STRVAR(bpy_bmdeformvert_clear_doc,
622 ".. method:: clear()\n"
623 "\n"
624 "   Clears all weights.\n"
625 );
626 static PyObject *bpy_bmdeformvert_clear(BPy_BMDeformVert *self)
627 {
628         defvert_clear(self->data);
629
630         Py_RETURN_NONE;
631 }
632
633 static struct PyMethodDef bpy_bmdeformvert_methods[] = {
634         {"keys",    (PyCFunction)bpy_bmdeformvert_keys,    METH_NOARGS,  bpy_bmdeformvert_keys_doc},
635         {"values",  (PyCFunction)bpy_bmdeformvert_values,  METH_NOARGS,  bpy_bmdeformvert_values_doc},
636         {"items",   (PyCFunction)bpy_bmdeformvert_items,   METH_NOARGS,  bpy_bmdeformvert_items_doc},
637         {"get",     (PyCFunction)bpy_bmdeformvert_get,     METH_VARARGS, bpy_bmdeformvert_get_doc},
638         /* BMESH_TODO pop, popitem, update */
639         {"clear",   (PyCFunction)bpy_bmdeformvert_clear,   METH_NOARGS,  bpy_bmdeformvert_clear_doc},
640         {NULL, NULL, 0, NULL}
641 };
642
643 PyTypeObject BPy_BMDeformVert_Type = {{{0}}}; /* bm.loops.layers.uv.active */
644
645 static void bm_init_types_bmdvert(void)
646 {
647         BPy_BMDeformVert_Type.tp_basicsize = sizeof(BPy_BMDeformVert);
648
649         BPy_BMDeformVert_Type.tp_name = "BMDeformVert";
650
651         BPy_BMDeformVert_Type.tp_doc = NULL; // todo
652
653         BPy_BMDeformVert_Type.tp_as_sequence = &bpy_bmdeformvert_as_sequence;
654         BPy_BMDeformVert_Type.tp_as_mapping = &bpy_bmdeformvert_as_mapping;
655
656         BPy_BMDeformVert_Type.tp_methods = bpy_bmdeformvert_methods;
657
658         BPy_BMDeformVert_Type.tp_flags = Py_TPFLAGS_DEFAULT;
659
660         PyType_Ready(&BPy_BMDeformVert_Type);
661 }
662
663 int BPy_BMDeformVert_AssignPyObject(struct MDeformVert *dvert, PyObject *value)
664 {
665         if (UNLIKELY(!BPy_BMDeformVert_Check(value))) {
666                 PyErr_Format(PyExc_TypeError, "expected BMDeformVert, not a %.200s", Py_TYPE(value)->tp_name);
667                 return -1;
668         }
669         else {
670                 MDeformVert *dvert_src = ((BPy_BMDeformVert *)value)->data;
671                 if (LIKELY(dvert != dvert_src)) {
672                         defvert_copy(dvert, dvert_src);
673                 }
674                 return 0;
675         }
676 }
677
678 PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert)
679 {
680         BPy_BMDeformVert *self = PyObject_New(BPy_BMDeformVert, &BPy_BMDeformVert_Type);
681         self->data = dvert;
682         return (PyObject *)self;
683 }
684
685 /* --- End Mesh Deform Vert --- */
686
687
688 /* call to init all types */
689 void BPy_BM_init_types_meshdata(void)
690 {
691         bm_init_types_bmtexpoly();
692         bm_init_types_bmloopuv();
693         bm_init_types_bmloopcol();
694         bm_init_types_bmdvert();
695 }
696