Cleanup: indentation
[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_base.h"
42 #include "BLI_math_vector.h"
43
44 #include "BKE_deform.h"
45 #include "BKE_library.h"
46
47 #include "bmesh_py_types_meshdata.h"
48
49 #include "../generic/py_capi_utils.h"
50 #include "../generic/python_utildefines.h"
51
52
53 /* Mesh BMTexPoly
54  * ************** */
55
56 #define BPy_BMTexPoly_Check(v)  (Py_TYPE(v) == &BPy_BMTexPoly_Type)
57
58 typedef struct BPy_BMTexPoly {
59         PyObject_VAR_HEAD
60         MTexPoly *data;
61 } BPy_BMTexPoly;
62
63 extern PyObject *pyrna_id_CreatePyObject(ID *id);
64 extern bool      pyrna_id_FromPyObject(PyObject *obj, ID **id);
65
66 PyDoc_STRVAR(bpy_bmtexpoly_image_doc,
67 "Image or None.\n\n:type: :class:`bpy.types.Image`"
68 );
69 static PyObject *bpy_bmtexpoly_image_get(BPy_BMTexPoly *self, void *UNUSED(closure))
70 {
71         return pyrna_id_CreatePyObject((ID *)self->data->tpage);
72 }
73
74 static int bpy_bmtexpoly_image_set(BPy_BMTexPoly *self, PyObject *value, void *UNUSED(closure))
75 {
76         ID *id;
77
78         if (value == Py_None) {
79                 id = NULL;
80         }
81         else if (pyrna_id_FromPyObject(value, &id) && id && GS(id->name) == ID_IM) {
82                 /* pass */
83         }
84         else {
85                 PyErr_Format(PyExc_KeyError, "BMTexPoly.image = x"
86                              "expected an image or None, not '%.200s'",
87                              Py_TYPE(value)->tp_name);
88                 return -1;
89         }
90
91         id_lib_extern(id);
92         self->data->tpage = (struct Image *)id;
93
94         return 0;
95 }
96
97 static PyGetSetDef bpy_bmtexpoly_getseters[] = {
98         /* attributes match rna_def_mtpoly  */
99         {(char *)"image", (getter)bpy_bmtexpoly_image_get, (setter)bpy_bmtexpoly_image_set, (char *)bpy_bmtexpoly_image_doc, NULL},
100
101         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
102 };
103
104 static PyTypeObject BPy_BMTexPoly_Type; /* bm.loops.layers.uv.active */
105
106 static void bm_init_types_bmtexpoly(void)
107 {
108         BPy_BMTexPoly_Type.tp_basicsize = sizeof(BPy_BMTexPoly);
109
110         BPy_BMTexPoly_Type.tp_name = "BMTexPoly";
111
112         BPy_BMTexPoly_Type.tp_doc = NULL; // todo
113
114         BPy_BMTexPoly_Type.tp_getset = bpy_bmtexpoly_getseters;
115
116         BPy_BMTexPoly_Type.tp_flags = Py_TPFLAGS_DEFAULT;
117
118         PyType_Ready(&BPy_BMTexPoly_Type);
119 }
120
121 int BPy_BMTexPoly_AssignPyObject(struct MTexPoly *mtpoly, PyObject *value)
122 {
123         if (UNLIKELY(!BPy_BMTexPoly_Check(value))) {
124                 PyErr_Format(PyExc_TypeError, "expected BMTexPoly, not a %.200s", Py_TYPE(value)->tp_name);
125                 return -1;
126         }
127         else {
128                 *((MTexPoly *)mtpoly) = *(((BPy_BMTexPoly *)value)->data);
129                 return 0;
130         }
131 }
132
133 PyObject *BPy_BMTexPoly_CreatePyObject(struct MTexPoly *mtpoly)
134 {
135         BPy_BMTexPoly *self = PyObject_New(BPy_BMTexPoly, &BPy_BMTexPoly_Type);
136         self->data = mtpoly;
137         return (PyObject *)self;
138 }
139
140 /* --- End Mesh BMTexPoly --- */
141
142 /* Mesh Loop UV
143  * ************ */
144
145 #define BPy_BMLoopUV_Check(v)  (Py_TYPE(v) == &BPy_BMLoopUV_Type)
146
147 typedef struct BPy_BMLoopUV {
148         PyObject_VAR_HEAD
149         MLoopUV *data;
150 } BPy_BMLoopUV;
151
152 PyDoc_STRVAR(bpy_bmloopuv_uv_doc,
153 "Loops UV (as a 2D Vector).\n\n:type: :class:`mathutils.Vector`"
154 );
155 static PyObject *bpy_bmloopuv_uv_get(BPy_BMLoopUV *self, void *UNUSED(closure))
156 {
157         return Vector_CreatePyObject_wrap(self->data->uv, 2, NULL);
158 }
159
160 static int bpy_bmloopuv_uv_set(BPy_BMLoopUV *self, PyObject *value, void *UNUSED(closure))
161 {
162         float tvec[2];
163         if (mathutils_array_parse(tvec, 2, 2, value, "BMLoopUV.uv") != -1) {
164                 copy_v2_v2(self->data->uv, tvec);
165                 return 0;
166         }
167         else {
168                 return -1;
169         }
170 }
171
172 PyDoc_STRVAR(bpy_bmloopuv_flag__pin_uv_doc,
173 "UV pin state.\n\n:type: boolean"
174 );
175 PyDoc_STRVAR(bpy_bmloopuv_flag__select_doc,
176 "UV select state.\n\n:type: boolean"
177 );
178 PyDoc_STRVAR(bpy_bmloopuv_flag__select_edge_doc,
179 "UV edge select state.\n\n:type: boolean"
180 );
181
182
183 static PyObject *bpy_bmloopuv_flag_get(BPy_BMLoopUV *self, void *flag_p)
184 {
185         const int flag = GET_INT_FROM_POINTER(flag_p);
186         return PyBool_FromLong(self->data->flag & flag);
187 }
188
189 static int bpy_bmloopuv_flag_set(BPy_BMLoopUV *self, PyObject *value, void *flag_p)
190 {
191         const int flag = GET_INT_FROM_POINTER(flag_p);
192
193         switch (PyC_Long_AsBool(value)) {
194                 case true:
195                         self->data->flag |= flag;
196                         return 0;
197                 case false:
198                         self->data->flag &= ~flag;
199                         return 0;
200                 default:
201                         /* error is set */
202                         return -1;
203         }
204 }
205
206 static PyGetSetDef bpy_bmloopuv_getseters[] = {
207         /* attributes match rna_def_mloopuv  */
208         {(char *)"uv",          (getter)bpy_bmloopuv_uv_get,   (setter)bpy_bmloopuv_uv_set,   (char *)bpy_bmloopuv_uv_doc, NULL},
209         {(char *)"pin_uv",      (getter)bpy_bmloopuv_flag_get, (setter)bpy_bmloopuv_flag_set, (char *)bpy_bmloopuv_flag__pin_uv_doc, (void *)MLOOPUV_PINNED},
210         {(char *)"select",      (getter)bpy_bmloopuv_flag_get, (setter)bpy_bmloopuv_flag_set, (char *)bpy_bmloopuv_flag__select_doc, (void *)MLOOPUV_VERTSEL},
211         {(char *)"select_edge", (getter)bpy_bmloopuv_flag_get, (setter)bpy_bmloopuv_flag_set, (char *)bpy_bmloopuv_flag__select_edge_doc, (void *)MLOOPUV_EDGESEL},
212
213         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
214 };
215
216 PyTypeObject BPy_BMLoopUV_Type; /* bm.loops.layers.uv.active */
217
218 static void bm_init_types_bmloopuv(void)
219 {
220         BPy_BMLoopUV_Type.tp_basicsize = sizeof(BPy_BMLoopUV);
221
222         BPy_BMLoopUV_Type.tp_name = "BMLoopUV";
223
224         BPy_BMLoopUV_Type.tp_doc = NULL; // todo
225
226         BPy_BMLoopUV_Type.tp_getset = bpy_bmloopuv_getseters;
227
228         BPy_BMLoopUV_Type.tp_flags = Py_TPFLAGS_DEFAULT;
229
230         PyType_Ready(&BPy_BMLoopUV_Type);
231 }
232
233 int BPy_BMLoopUV_AssignPyObject(struct MLoopUV *mloopuv, PyObject *value)
234 {
235         if (UNLIKELY(!BPy_BMLoopUV_Check(value))) {
236                 PyErr_Format(PyExc_TypeError, "expected BMLoopUV, not a %.200s", Py_TYPE(value)->tp_name);
237                 return -1;
238         }
239         else {
240                 *((MLoopUV *)mloopuv) = *(((BPy_BMLoopUV *)value)->data);
241                 return 0;
242         }
243 }
244
245 PyObject *BPy_BMLoopUV_CreatePyObject(struct MLoopUV *mloopuv)
246 {
247         BPy_BMLoopUV *self = PyObject_New(BPy_BMLoopUV, &BPy_BMLoopUV_Type);
248         self->data = mloopuv;
249         return (PyObject *)self;
250 }
251
252 /* --- End Mesh Loop UV --- */
253
254 /* Mesh Vert Skin
255  * ************ */
256
257 #define BPy_BMVertSkin_Check(v)  (Py_TYPE(v) == &BPy_BMVertSkin_Type)
258
259 typedef struct BPy_BMVertSkin {
260         PyObject_VAR_HEAD
261         MVertSkin *data;
262 } BPy_BMVertSkin;
263
264 PyDoc_STRVAR(bpy_bmvertskin_radius_doc,
265 "Vert skin radii (as a 2D Vector).\n\n:type: :class:`mathutils.Vector`"
266 );
267 static PyObject *bpy_bmvertskin_radius_get(BPy_BMVertSkin *self, void *UNUSED(closure))
268 {
269         return Vector_CreatePyObject_wrap(self->data->radius, 2, NULL);
270 }
271
272 static int bpy_bmvertskin_radius_set(BPy_BMVertSkin *self, PyObject *value, void *UNUSED(closure))
273 {
274         float tvec[2];
275         if (mathutils_array_parse(tvec, 2, 2, value, "BMVertSkin.radius") != -1) {
276                 copy_v2_v2(self->data->radius, tvec);
277                 return 0;
278         }
279         else {
280                 return -1;
281         }
282 }
283
284 PyDoc_STRVAR(bpy_bmvertskin_flag__use_root_doc,
285 "Use as root vertex. Setting this flag does not clear other roots in the same mesh island.\n\n:type: boolean"
286 );
287 PyDoc_STRVAR(bpy_bmvertskin_flag__use_loose_doc,
288 "Use loose vertex.\n\n:type: boolean"
289 );
290
291 static PyObject *bpy_bmvertskin_flag_get(BPy_BMVertSkin *self, void *flag_p)
292 {
293         const int flag = GET_INT_FROM_POINTER(flag_p);
294         return PyBool_FromLong(self->data->flag & flag);
295 }
296
297 static int bpy_bmvertskin_flag_set(BPy_BMVertSkin *self, PyObject *value, void *flag_p)
298 {
299         const int flag = GET_INT_FROM_POINTER(flag_p);
300
301         switch (PyC_Long_AsBool(value)) {
302                 case true:
303                         self->data->flag |= flag;
304                         return 0;
305                 case false:
306                         self->data->flag &= ~flag;
307                         return 0;
308                 default:
309                         /* error is set */
310                         return -1;
311         }
312 }
313
314 static PyGetSetDef bpy_bmvertskin_getseters[] = {
315         /* attributes match rna_mesh_gen  */
316         {(char *)"radius",    (getter)bpy_bmvertskin_radius_get, (setter)bpy_bmvertskin_radius_set, (char *)bpy_bmvertskin_radius_doc, NULL},
317         {(char *)"use_root",  (getter)bpy_bmvertskin_flag_get,   (setter)bpy_bmvertskin_flag_set,   (char *)bpy_bmvertskin_flag__use_root_doc,  (void *)MVERT_SKIN_ROOT},
318         {(char *)"use_loose", (getter)bpy_bmvertskin_flag_get,   (setter)bpy_bmvertskin_flag_set,   (char *)bpy_bmvertskin_flag__use_loose_doc, (void *)MVERT_SKIN_LOOSE},
319
320         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
321 };
322
323 static PyTypeObject BPy_BMVertSkin_Type; /* bm.loops.layers.skin.active */
324
325 static void bm_init_types_bmvertskin(void)
326 {
327         BPy_BMVertSkin_Type.tp_basicsize = sizeof(BPy_BMVertSkin);
328
329         BPy_BMVertSkin_Type.tp_name = "BMVertSkin";
330
331         BPy_BMVertSkin_Type.tp_doc = NULL; // todo
332
333         BPy_BMVertSkin_Type.tp_getset = bpy_bmvertskin_getseters;
334
335         BPy_BMVertSkin_Type.tp_flags = Py_TPFLAGS_DEFAULT;
336
337         PyType_Ready(&BPy_BMVertSkin_Type);
338 }
339
340 int BPy_BMVertSkin_AssignPyObject(struct MVertSkin *mvertskin, PyObject *value)
341 {
342         if (UNLIKELY(!BPy_BMVertSkin_Check(value))) {
343                 PyErr_Format(PyExc_TypeError, "expected BMVertSkin, not a %.200s", Py_TYPE(value)->tp_name);
344                 return -1;
345         }
346         else {
347                 *((MVertSkin *)mvertskin) = *(((BPy_BMVertSkin *)value)->data);
348                 return 0;
349         }
350 }
351
352 PyObject *BPy_BMVertSkin_CreatePyObject(struct MVertSkin *mvertskin)
353 {
354         BPy_BMVertSkin *self = PyObject_New(BPy_BMVertSkin, &BPy_BMVertSkin_Type);
355         self->data = mvertskin;
356         return (PyObject *)self;
357 }
358
359 /* --- End Mesh Vert Skin --- */
360
361 /* Mesh Loop Color
362  * *************** */
363
364 /* This simply provides a color wrapper for
365  * color which uses mathutils callbacks for mathutils.Color
366  */
367
368 #define MLOOPCOL_FROM_CAPSULE(color_capsule)  \
369         ((MLoopCol *)PyCapsule_GetPointer(color_capsule, NULL))
370
371 static void mloopcol_to_float(const MLoopCol *mloopcol, float r_col[3])
372 {
373         rgba_uchar_to_float(r_col, (const unsigned char *)&mloopcol->r);
374 }
375
376 static void mloopcol_from_float(MLoopCol *mloopcol, const float col[3])
377 {
378         rgba_float_to_uchar((unsigned char *)&mloopcol->r, col);
379 }
380
381 static unsigned char mathutils_bmloopcol_cb_index = -1;
382
383 static int mathutils_bmloopcol_check(BaseMathObject *UNUSED(bmo))
384 {
385         /* always ok */
386         return 0;
387 }
388
389 static int mathutils_bmloopcol_get(BaseMathObject *bmo, int UNUSED(subtype))
390 {
391         MLoopCol *mloopcol = MLOOPCOL_FROM_CAPSULE(bmo->cb_user);
392         mloopcol_to_float(mloopcol, bmo->data);
393         return 0;
394 }
395
396 static int mathutils_bmloopcol_set(BaseMathObject *bmo, int UNUSED(subtype))
397 {
398         MLoopCol *mloopcol = MLOOPCOL_FROM_CAPSULE(bmo->cb_user);
399         mloopcol_from_float(mloopcol, bmo->data);
400         return 0;
401 }
402
403 static int mathutils_bmloopcol_get_index(BaseMathObject *bmo, int subtype, int UNUSED(index))
404 {
405         /* lazy, avoid repeteing the case statement */
406         if (mathutils_bmloopcol_get(bmo, subtype) == -1)
407                 return -1;
408         return 0;
409 }
410
411 static int mathutils_bmloopcol_set_index(BaseMathObject *bmo, int subtype, int index)
412 {
413         const float f = bmo->data[index];
414
415         /* lazy, avoid repeteing the case statement */
416         if (mathutils_bmloopcol_get(bmo, subtype) == -1)
417                 return -1;
418
419         bmo->data[index] = f;
420         return mathutils_bmloopcol_set(bmo, subtype);
421 }
422
423 static Mathutils_Callback mathutils_bmloopcol_cb = {
424         mathutils_bmloopcol_check,
425         mathutils_bmloopcol_get,
426         mathutils_bmloopcol_set,
427         mathutils_bmloopcol_get_index,
428         mathutils_bmloopcol_set_index
429 };
430
431 static void bm_init_types_bmloopcol(void)
432 {
433         /* pass */
434         mathutils_bmloopcol_cb_index = Mathutils_RegisterCallback(&mathutils_bmloopcol_cb);
435 }
436
437 int BPy_BMLoopColor_AssignPyObject(struct MLoopCol *mloopcol, PyObject *value)
438 {
439         float tvec[4];
440         if (mathutils_array_parse(tvec, 4, 4, value, "BMLoopCol") != -1) {
441                 mloopcol_from_float(mloopcol, tvec);
442                 return 0;
443         }
444         else {
445                 return -1;
446         }
447 }
448
449 PyObject *BPy_BMLoopColor_CreatePyObject(struct MLoopCol *data)
450 {
451         PyObject *color_capsule;
452         color_capsule = PyCapsule_New(data, NULL, NULL);
453         return Vector_CreatePyObject_cb(color_capsule, 4, mathutils_bmloopcol_cb_index, 0);
454 }
455
456 #undef MLOOPCOL_FROM_CAPSULE
457
458 /* --- End Mesh Loop Color --- */
459
460
461 /* Mesh Deform Vert
462  * **************** */
463
464 /**
465  * This is python type wraps a deform vert as a python dictionary,
466  * hiding the #MDeformWeight on access, since the mapping is very close, eg:
467  *
468  * C:
469  *     weight = defvert_find_weight(dv, group_nr);
470  *     defvert_remove_group(dv, dw)
471  *
472  * Py:
473  *     weight = dv[group_nr]
474  *     del dv[group_nr]
475  *
476  * \note: there is nothing BMesh specific here,
477  * its only that BMesh is the only part of blender that uses a hand written api like this.
478  * This type could eventually be used to access lattice weights.
479  *
480  * \note: Many of blender-api's dict-like-wrappers act like ordered dicts,
481  * This is intentional _not_ ordered, the weights can be in any order and it wont matter,
482  * the order should not be used in the api in any meaningful way (as with a python dict)
483  * only expose as mapping, not a sequence.
484  */
485
486 #define BPy_BMDeformVert_Check(v)  (Py_TYPE(v) == &BPy_BMDeformVert_Type)
487
488 typedef struct BPy_BMDeformVert {
489         PyObject_VAR_HEAD
490         MDeformVert *data;
491 } BPy_BMDeformVert;
492
493
494 /* Mapping Protocols
495  * ================= */
496
497 static int bpy_bmdeformvert_len(BPy_BMDeformVert *self)
498 {
499         return self->data->totweight;
500 }
501
502 static PyObject *bpy_bmdeformvert_subscript(BPy_BMDeformVert *self, PyObject *key)
503 {
504         if (PyIndex_Check(key)) {
505                 int i;
506                 i = PyNumber_AsSsize_t(key, PyExc_IndexError);
507                 if (i == -1 && PyErr_Occurred()) {
508                         return NULL;
509                 }
510                 else {
511                         MDeformWeight *dw = defvert_find_index(self->data, i);
512
513                         if (dw == NULL) {
514                                 PyErr_SetString(PyExc_KeyError, "BMDeformVert[key] = x: "
515                                                 "key not found");
516                                 return NULL;
517                         }
518                         else {
519                                 return PyFloat_FromDouble(dw->weight);
520                         }
521                 }
522         }
523         else {
524                 PyErr_Format(PyExc_TypeError,
525                              "BMDeformVert keys must be integers, not %.200s",
526                              Py_TYPE(key)->tp_name);
527                 return NULL;
528         }
529 }
530
531 static int bpy_bmdeformvert_ass_subscript(BPy_BMDeformVert *self, PyObject *key, PyObject *value)
532 {
533         if (PyIndex_Check(key)) {
534                 int i;
535
536                 i = PyNumber_AsSsize_t(key, PyExc_IndexError);
537                 if (i == -1 && PyErr_Occurred()) {
538                         return -1;
539                 }
540
541                 if (value) {
542                         /* dvert[group_index] = 0.5 */
543                         if (i < 0) {
544                                 PyErr_SetString(PyExc_KeyError, "BMDeformVert[key] = x: "
545                                                 "weight keys can't be negative");
546                                 return -1;
547                         }
548                         else {
549                                 MDeformWeight *dw = defvert_verify_index(self->data, i);
550                                 const float f = PyFloat_AsDouble(value);
551                                 if (f == -1 && PyErr_Occurred()) { // parsed key not a number
552                                         PyErr_SetString(PyExc_TypeError,
553                                                         "BMDeformVert[key] = x: "
554                                                         "assigned value not a number");
555                                         return -1;
556                                 }
557
558                                 dw->weight = clamp_f(f, 0.0f, 1.0f);
559                         }
560                 }
561                 else {
562                         /* del dvert[group_index] */
563                         MDeformWeight *dw = defvert_find_index(self->data, i);
564
565                         if (dw == NULL) {
566                                 PyErr_SetString(PyExc_KeyError, "del BMDeformVert[key]: "
567                                                 "key not found");
568                         }
569                         defvert_remove_group(self->data, dw);
570                 }
571
572                 return 0;
573
574         }
575         else {
576                 PyErr_Format(PyExc_TypeError,
577                              "BMDeformVert keys must be integers, not %.200s",
578                              Py_TYPE(key)->tp_name);
579                 return -1;
580         }
581 }
582
583 static int bpy_bmdeformvert_contains(BPy_BMDeformVert *self, PyObject *value)
584 {
585         const int key = PyLong_AsSsize_t(value);
586
587         if (key == -1 && PyErr_Occurred()) {
588                 PyErr_SetString(PyExc_TypeError,
589                                 "BMDeformVert.__contains__: expected an int");
590                 return -1;
591         }
592
593         return (defvert_find_index(self->data, key) != NULL) ? 1 : 0;
594 }
595
596 /* only defined for __contains__ */
597 static PySequenceMethods bpy_bmdeformvert_as_sequence = {
598         (lenfunc)bpy_bmdeformvert_len,               /* sq_length */
599         NULL,                                        /* sq_concat */
600         NULL,                                        /* sq_repeat */
601
602         /* note: if this is set PySequence_Check() returns True,
603          * but in this case we dont want to be treated as a seq */
604         NULL,                                        /* sq_item */
605
606         NULL,                                        /* sq_slice */
607         NULL,                                        /* sq_ass_item */
608         NULL,                                        /* *was* sq_ass_slice */
609         (objobjproc)bpy_bmdeformvert_contains,       /* sq_contains */
610         (binaryfunc) NULL,                           /* sq_inplace_concat */
611         (ssizeargfunc) NULL,                         /* sq_inplace_repeat */
612 };
613
614 static PyMappingMethods bpy_bmdeformvert_as_mapping = {
615         (lenfunc)bpy_bmdeformvert_len,
616         (binaryfunc)bpy_bmdeformvert_subscript,
617         (objobjargproc)bpy_bmdeformvert_ass_subscript
618 };
619
620 /* Methods
621  * ======= */
622
623 PyDoc_STRVAR(bpy_bmdeformvert_keys_doc,
624 ".. method:: keys()\n"
625 "\n"
626 "   Return the group indices used by this vertex\n"
627 "   (matching pythons dict.keys() functionality).\n"
628 "\n"
629 "   :return: the deform group this vertex uses\n"
630 "   :rtype: list of ints\n"
631 );
632 static PyObject *bpy_bmdeformvert_keys(BPy_BMDeformVert *self)
633 {
634         PyObject *ret;
635         int i;
636         MDeformWeight *dw = self->data->dw;
637
638         ret = PyList_New(self->data->totweight);
639         for (i = 0; i < self->data->totweight; i++, dw++) {
640                 PyList_SET_ITEM(ret, i, PyLong_FromLong(dw->def_nr));
641         }
642
643         return ret;
644 }
645
646 PyDoc_STRVAR(bpy_bmdeformvert_values_doc,
647 ".. method:: values()\n"
648 "\n"
649 "   Return the weights of the deform vertex\n"
650 "   (matching pythons dict.values() functionality).\n"
651 "\n"
652 "   :return: The weights that influence this vertex\n"
653 "   :rtype: list of floats\n"
654 );
655 static PyObject *bpy_bmdeformvert_values(BPy_BMDeformVert *self)
656 {
657         PyObject *ret;
658         int i;
659         MDeformWeight *dw = self->data->dw;
660
661         ret = PyList_New(self->data->totweight);
662         for (i = 0; i < self->data->totweight; i++, dw++) {
663                 PyList_SET_ITEM(ret, i, PyFloat_FromDouble(dw->weight));
664         }
665
666         return ret;
667 }
668
669 PyDoc_STRVAR(bpy_bmdeformvert_items_doc,
670 ".. method:: items()\n"
671 "\n"
672 "   Return (group, weight) pairs for this vertex\n"
673 "   (matching pythons dict.items() functionality).\n"
674 "\n"
675 "   :return: (key, value) pairs for each deform weight of this vertex.\n"
676 "   :rtype: list of tuples\n"
677 );
678 static PyObject *bpy_bmdeformvert_items(BPy_BMDeformVert *self)
679 {
680         PyObject *ret;
681         PyObject *item;
682         int i;
683         MDeformWeight *dw = self->data->dw;
684
685         ret = PyList_New(self->data->totweight);
686         for (i = 0; i < self->data->totweight; i++, dw++) {
687                 item = PyTuple_New(2);
688                 PyTuple_SET_ITEMS(item,
689                         PyLong_FromLong(dw->def_nr),
690                         PyFloat_FromDouble(dw->weight));
691                 PyList_SET_ITEM(ret, i, item);
692         }
693
694         return ret;
695 }
696
697 PyDoc_STRVAR(bpy_bmdeformvert_get_doc,
698 ".. method:: get(key, default=None)\n"
699 "\n"
700 "   Returns the deform weight matching the key or default\n"
701 "   when not found (matches pythons dictionary function of the same name).\n"
702 "\n"
703 "   :arg key: The key associated with deform weight.\n"
704 "   :type key: int\n"
705 "   :arg default: Optional argument for the value to return if\n"
706 "      *key* is not found.\n"
707 "   :type default: Undefined\n"
708 );
709 static PyObject *bpy_bmdeformvert_get(BPy_BMDeformVert *self, PyObject *args)
710 {
711         int key;
712         PyObject *def = Py_None;
713
714         if (!PyArg_ParseTuple(args, "i|O:get", &key, &def)) {
715                 return NULL;
716         }
717         else {
718                 MDeformWeight *dw = defvert_find_index(self->data, key);
719
720                 if (dw) {
721                         return PyFloat_FromDouble(dw->weight);
722                 }
723                 else {
724                         return Py_INCREF_RET(def);
725                 }
726         }
727 }
728
729
730 PyDoc_STRVAR(bpy_bmdeformvert_clear_doc,
731 ".. method:: clear()\n"
732 "\n"
733 "   Clears all weights.\n"
734 );
735 static PyObject *bpy_bmdeformvert_clear(BPy_BMDeformVert *self)
736 {
737         defvert_clear(self->data);
738
739         Py_RETURN_NONE;
740 }
741
742 static struct PyMethodDef bpy_bmdeformvert_methods[] = {
743         {"keys",    (PyCFunction)bpy_bmdeformvert_keys,    METH_NOARGS,  bpy_bmdeformvert_keys_doc},
744         {"values",  (PyCFunction)bpy_bmdeformvert_values,  METH_NOARGS,  bpy_bmdeformvert_values_doc},
745         {"items",   (PyCFunction)bpy_bmdeformvert_items,   METH_NOARGS,  bpy_bmdeformvert_items_doc},
746         {"get",     (PyCFunction)bpy_bmdeformvert_get,     METH_VARARGS, bpy_bmdeformvert_get_doc},
747         /* BMESH_TODO pop, popitem, update */
748         {"clear",   (PyCFunction)bpy_bmdeformvert_clear,   METH_NOARGS,  bpy_bmdeformvert_clear_doc},
749         {NULL, NULL, 0, NULL}
750 };
751
752 PyTypeObject BPy_BMDeformVert_Type; /* bm.loops.layers.uv.active */
753
754 static void bm_init_types_bmdvert(void)
755 {
756         BPy_BMDeformVert_Type.tp_basicsize = sizeof(BPy_BMDeformVert);
757
758         BPy_BMDeformVert_Type.tp_name = "BMDeformVert";
759
760         BPy_BMDeformVert_Type.tp_doc = NULL; // todo
761
762         BPy_BMDeformVert_Type.tp_as_sequence = &bpy_bmdeformvert_as_sequence;
763         BPy_BMDeformVert_Type.tp_as_mapping = &bpy_bmdeformvert_as_mapping;
764
765         BPy_BMDeformVert_Type.tp_methods = bpy_bmdeformvert_methods;
766
767         BPy_BMDeformVert_Type.tp_flags = Py_TPFLAGS_DEFAULT;
768
769         PyType_Ready(&BPy_BMDeformVert_Type);
770 }
771
772 int BPy_BMDeformVert_AssignPyObject(struct MDeformVert *dvert, PyObject *value)
773 {
774         if (UNLIKELY(!BPy_BMDeformVert_Check(value))) {
775                 PyErr_Format(PyExc_TypeError, "expected BMDeformVert, not a %.200s", Py_TYPE(value)->tp_name);
776                 return -1;
777         }
778         else {
779                 MDeformVert *dvert_src = ((BPy_BMDeformVert *)value)->data;
780                 if (LIKELY(dvert != dvert_src)) {
781                         defvert_copy(dvert, dvert_src);
782                 }
783                 return 0;
784         }
785 }
786
787 PyObject *BPy_BMDeformVert_CreatePyObject(struct MDeformVert *dvert)
788 {
789         BPy_BMDeformVert *self = PyObject_New(BPy_BMDeformVert, &BPy_BMDeformVert_Type);
790         self->data = dvert;
791         return (PyObject *)self;
792 }
793
794 /* --- End Mesh Deform Vert --- */
795
796
797 /* call to init all types */
798 void BPy_BM_init_types_meshdata(void)
799 {
800         bm_init_types_bmtexpoly();
801         bm_init_types_bmloopuv();
802         bm_init_types_bmloopcol();
803         bm_init_types_bmdvert();
804         bm_init_types_bmvertskin();
805 }