PyAPI: Make use of PyC_LongAs... API
[blender.git] / source / blender / python / bmesh / bmesh_py_types_customdata.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_customdata.c
27  *  \ingroup pybmesh
28  *
29  * This file defines the types for 'BMesh.verts/edges/faces/loops.layers'
30  * customdata layer access.
31  */
32
33 #include <Python.h>
34
35 #include "BLI_utildefines.h"
36 #include "BLI_math_vector.h"
37
38 #include "bmesh.h"
39
40 #include "bmesh_py_types.h"
41 #include "bmesh_py_types_customdata.h"
42 #include "bmesh_py_types_meshdata.h"
43
44 #include "../mathutils/mathutils.h"
45 #include "../generic/python_utildefines.h"
46 #include "../generic/py_capi_utils.h"
47
48 #include "BKE_customdata.h"
49
50 #include "DNA_meshdata_types.h"
51
52 static CustomData *bpy_bm_customdata_get(BMesh *bm, char htype)
53 {
54         switch (htype) {
55                 case BM_VERT:  return &bm->vdata;
56                 case BM_EDGE:  return &bm->edata;
57                 case BM_FACE:  return &bm->pdata;
58                 case BM_LOOP:  return &bm->ldata;
59         }
60
61         BLI_assert(0);
62         return NULL;
63 }
64
65 static CustomDataLayer *bpy_bmlayeritem_get(BPy_BMLayerItem *self)
66 {
67         CustomData *data = bpy_bm_customdata_get(self->bm, self->htype);
68         const int index_absolute = CustomData_get_layer_index_n(data, self->type, self->index);
69         if (index_absolute != -1) {
70                 return &data->layers[index_absolute];
71         }
72         else {
73                 PyErr_SetString(PyExc_RuntimeError,
74                                 "layer has become invalid");
75                 return NULL;
76         }
77 }
78
79 /* py-type definitions
80  * ******************* */
81
82 /* getseters
83  * ========= */
84
85 /* used for many different types  */
86
87 PyDoc_STRVAR(bpy_bmlayeraccess_collection__float_doc,
88 "Generic float custom-data layer.\n\ntype: :class:`BMLayerCollection`"
89 );
90 PyDoc_STRVAR(bpy_bmlayeraccess_collection__int_doc,
91 "Generic int custom-data layer.\n\ntype: :class:`BMLayerCollection`"
92 );
93 PyDoc_STRVAR(bpy_bmlayeraccess_collection__string_doc,
94 "Generic string custom-data layer (exposed as bytes, 255 max length).\n\ntype: :class:`BMLayerCollection`"
95 );
96 PyDoc_STRVAR(bpy_bmlayeraccess_collection__deform_doc,
97 "Vertex deform weight :class:`BMDeformVert` (TODO).\n\ntype: :class:`BMLayerCollection`" // TYPE DOESN'T EXIST YET
98 );
99 PyDoc_STRVAR(bpy_bmlayeraccess_collection__shape_doc,
100 "Vertex shapekey absolute location (as a 3D Vector).\n\n:type: :class:`BMLayerCollection`"
101 );
102 PyDoc_STRVAR(bpy_bmlayeraccess_collection__bevel_weight_doc,
103 "Bevel weight float in [0 - 1].\n\n:type: :class:`BMLayerCollection`"
104 );
105 PyDoc_STRVAR(bpy_bmlayeraccess_collection__crease_doc,
106 "Edge crease for subsurf - float in [0 - 1].\n\n:type: :class:`BMLayerCollection`"
107 );
108 PyDoc_STRVAR(bpy_bmlayeraccess_collection__tex_doc,
109 "Accessor for :class:`BMTexPoly` layer (TODO).\n\ntype: :class:`BMLayerCollection`" // TYPE DOESN'T EXIST YET
110 );
111 PyDoc_STRVAR(bpy_bmlayeraccess_collection__uv_doc,
112 "Accessor for :class:`BMLoopUV` UV (as a 2D Vector).\n\ntype: :class:`BMLayerCollection`"
113 );
114 PyDoc_STRVAR(bpy_bmlayeraccess_collection__color_doc,
115 "Accessor for vertex color layer.\n\ntype: :class:`BMLayerCollection`"
116 );
117 PyDoc_STRVAR(bpy_bmlayeraccess_collection__skin_doc,
118 "Accessor for skin layer.\n\ntype: :class:`BMLayerCollection`"
119 );
120 PyDoc_STRVAR(bpy_bmlayeraccess_collection__paint_mask_doc,
121 "Accessor for paint mask layer.\n\ntype: :class:`BMLayerCollection`"
122 );
123 #ifdef WITH_FREESTYLE
124 PyDoc_STRVAR(bpy_bmlayeraccess_collection__freestyle_edge_doc,
125 "Accessor for Freestyle edge layer.\n\ntype: :class:`BMLayerCollection`"
126 );
127 PyDoc_STRVAR(bpy_bmlayeraccess_collection__freestyle_face_doc,
128 "Accessor for Freestyle face layer.\n\ntype: :class:`BMLayerCollection`"
129 );
130 #endif
131
132 static PyObject *bpy_bmlayeraccess_collection_get(BPy_BMLayerAccess *self, void *flag)
133 {
134         const int type = (int)GET_INT_FROM_POINTER(flag);
135
136         BPY_BM_CHECK_OBJ(self);
137
138         return BPy_BMLayerCollection_CreatePyObject(self->bm, self->htype, type);
139 }
140
141
142 PyDoc_STRVAR(bpy_bmlayercollection_active_doc,
143 "The active layer of this type (read-only).\n\n:type: :class:`BMLayerItem`"
144 );
145 static PyObject *bpy_bmlayercollection_active_get(BPy_BMLayerItem *self, void *UNUSED(flag))
146 {
147         CustomData *data;
148         int index;
149
150         BPY_BM_CHECK_OBJ(self);
151
152         data = bpy_bm_customdata_get(self->bm, self->htype);
153         index = CustomData_get_active_layer(data, self->type);  /* type relative */
154
155         if (index != -1) {
156                 return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
157         }
158         else {
159                 Py_RETURN_NONE;
160         }
161 }
162
163
164 PyDoc_STRVAR(bpy_bmlayercollection_is_singleton_doc,
165 "True if there can exists only one layer of this type (read-only).\n\n:type: boolean"
166 );
167 static PyObject *bpy_bmlayercollection_is_singleton_get(BPy_BMLayerItem *self, void *UNUSED(flag))
168 {
169         BPY_BM_CHECK_OBJ(self);
170
171         return PyBool_FromLong(CustomData_layertype_is_singleton(self->type));
172 }
173
174 PyDoc_STRVAR(bpy_bmlayercollection_name_doc,
175 "The layers unique name (read-only).\n\n:type: string"
176 );
177 static PyObject *bpy_bmlayeritem_name_get(BPy_BMLayerItem *self, void *UNUSED(flag))
178 {
179         CustomDataLayer *layer;
180
181         BPY_BM_CHECK_OBJ(self);
182
183         layer = bpy_bmlayeritem_get(self);
184         if (layer) {
185                 return PyUnicode_FromString(layer->name);
186         }
187         else {
188                 return NULL;
189         }
190 }
191
192 static PyGetSetDef bpy_bmlayeraccess_vert_getseters[] = {
193         {(char *)"deform", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__deform_doc, (void *)CD_MDEFORMVERT},
194
195         {(char *)"float",  (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__float_doc, (void *)CD_PROP_FLT},
196         {(char *)"int",    (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT},
197         {(char *)"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__string_doc, (void *)CD_PROP_STR},
198
199         {(char *)"shape",        (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__shape_doc, (void *)CD_SHAPEKEY},
200         {(char *)"bevel_weight", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__bevel_weight_doc, (void *)CD_BWEIGHT},
201         {(char *)"skin",         (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__skin_doc, (void *)CD_MVERT_SKIN},
202         {(char *)"paint_mask",   (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__paint_mask_doc, (void *)CD_PAINT_MASK},
203
204         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
205 };
206
207 static PyGetSetDef bpy_bmlayeraccess_edge_getseters[] = {
208         {(char *)"float",  (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__float_doc, (void *)CD_PROP_FLT},
209         {(char *)"int",    (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT},
210         {(char *)"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__string_doc, (void *)CD_PROP_STR},
211
212         {(char *)"bevel_weight", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__bevel_weight_doc, (void *)CD_BWEIGHT},
213         {(char *)"crease",       (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__crease_doc, (void *)CD_CREASE},
214 #ifdef WITH_FREESTYLE
215         {(char *)"freestyle", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__freestyle_edge_doc, (void *)CD_FREESTYLE_EDGE},
216 #endif
217
218         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
219 };
220
221 static PyGetSetDef bpy_bmlayeraccess_face_getseters[] = {
222         {(char *)"float",  (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__float_doc, (void *)CD_PROP_FLT},
223         {(char *)"int",    (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT},
224         {(char *)"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__string_doc, (void *)CD_PROP_STR},
225
226         {(char *)"tex",   (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__tex_doc, (void *)CD_MTEXPOLY},
227
228 #ifdef WITH_FREESTYLE
229         {(char *)"freestyle", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__freestyle_face_doc, (void *)CD_FREESTYLE_FACE},
230 #endif
231
232         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
233 };
234
235 static PyGetSetDef bpy_bmlayeraccess_loop_getseters[] = {
236         {(char *)"float",  (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__float_doc, (void *)CD_PROP_FLT},
237         {(char *)"int",    (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__int_doc, (void *)CD_PROP_INT},
238         {(char *)"string", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__string_doc, (void *)CD_PROP_STR},
239
240         {(char *)"uv",    (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__uv_doc, (void *)CD_MLOOPUV},
241         {(char *)"color", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__color_doc, (void *)CD_MLOOPCOL},
242
243         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
244 };
245
246
247 static PyGetSetDef bpy_bmlayercollection_getseters[] = {
248         /* BMESH_TODO, make writeable */
249         {(char *)"active",       (getter)bpy_bmlayercollection_active_get,       (setter)NULL, (char *)bpy_bmlayercollection_active_doc, NULL},
250         {(char *)"is_singleton", (getter)bpy_bmlayercollection_is_singleton_get, (setter)NULL, (char *)bpy_bmlayercollection_is_singleton_doc, NULL},
251
252         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
253 };
254
255 static PyGetSetDef bpy_bmlayeritem_getseters[] = {
256         /* BMESH_TODO, make writeable */
257         {(char *)"name", (getter)bpy_bmlayeritem_name_get, (setter)NULL, (char *)bpy_bmlayercollection_name_doc, NULL},
258
259         {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
260 };
261
262
263 /* Methods
264  * ======= */
265
266 /* BMLayerCollection
267  * ----------------- */
268
269 PyDoc_STRVAR(bpy_bmlayeritem_copy_from_doc,
270 ".. method:: copy_from(other)\n"
271 "\n"
272 "   Return a copy of the layer\n"
273 "\n"
274 "   :arg other: Another layer to copy from.\n"
275 "   :arg other: :class:`BMLayerItem`\n"
276 );
277 static PyObject *bpy_bmlayeritem_copy_from(BPy_BMLayerItem *self, BPy_BMLayerItem *value)
278 {
279         CustomData *data;
280
281         if (!BPy_BMLayerItem_Check(value)) {
282                 PyErr_Format(PyExc_TypeError,
283                              "layer.copy_from(x): expected BMLayerItem, not '%.200s'",
284                              Py_TYPE(value)->tp_name);
285                 return NULL;
286         }
287
288         BPY_BM_CHECK_OBJ(self);
289         BPY_BM_CHECK_SOURCE_OBJ(self->bm, "layer.copy_from()", value);
290
291         if ((self->htype != value->htype) ||
292             (self->type  != value->type))
293         {
294                 PyErr_SetString(PyExc_ValueError,
295                                 "layer.copy_from(other): layer type mismatch");
296         }
297
298         else if (self->index == value->index) {
299                 Py_RETURN_NONE;
300         }
301
302         data = bpy_bm_customdata_get(self->bm, self->htype);
303
304         if ((bpy_bmlayeritem_get(self) == NULL) ||
305             (bpy_bmlayeritem_get(value) == NULL))
306         {
307                 return NULL;
308         }
309
310         BM_data_layer_copy(self->bm, data, self->type, value->index, self->index);
311
312         Py_RETURN_NONE;
313 }
314
315 /* similar to new(), but no name arg. */
316 PyDoc_STRVAR(bpy_bmlayercollection_verify_doc,
317 ".. method:: verify()\n"
318 "\n"
319 "   Create a new layer or return an existing active layer\n"
320 "\n"
321 "   :return: The newly verified layer.\n"
322 "   :rtype: :class:`BMLayerItem`\n"
323 );
324 static PyObject *bpy_bmlayercollection_verify(BPy_BMLayerCollection *self)
325 {
326         int index;
327         CustomData *data;
328
329         BPY_BM_CHECK_OBJ(self);
330
331         data = bpy_bm_customdata_get(self->bm, self->htype);
332
333         index = CustomData_get_active_layer(data, self->type);  /* type relative */
334
335         if (index == -1) {
336                 BM_data_layer_add(self->bm, data, self->type);
337                 index = 0;
338         }
339
340         BLI_assert(index >= 0);
341
342         return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
343 }
344
345 PyDoc_STRVAR(bpy_bmlayercollection_new_doc,
346 ".. method:: new(name)\n"
347 "\n"
348 "   Create a new layer\n"
349 "\n"
350 "   :arg name: Optional name argument (will be made unique).\n"
351 "   :type name: string\n"
352 "   :return: The newly created layer.\n"
353 "   :rtype: :class:`BMLayerItem`\n"
354 );
355 static PyObject *bpy_bmlayercollection_new(BPy_BMLayerCollection *self, PyObject *args)
356 {
357         const char *name = NULL;
358         int index;
359         CustomData *data;
360
361         BPY_BM_CHECK_OBJ(self);
362
363         if (!PyArg_ParseTuple(args, "|s:new", &name)) {
364                 return NULL;
365         }
366
367         data = bpy_bm_customdata_get(self->bm, self->htype);
368
369         if (CustomData_layertype_is_singleton(self->type) &&
370             CustomData_has_layer(data, self->type))
371         {
372                 PyErr_SetString(PyExc_ValueError,
373                                 "layers.new(): is a singleton, use verify() instead");
374                 return NULL;
375         }
376
377         if (name) {
378                 BM_data_layer_add_named(self->bm, data, self->type, name);
379         }
380         else {
381                 BM_data_layer_add(self->bm, data, self->type);
382         }
383
384         index = CustomData_number_of_layers(data, self->type) - 1;
385         BLI_assert(index >= 0);
386
387         return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
388 }
389
390 PyDoc_STRVAR(bpy_bmlayercollection_remove_doc,
391 ".. method:: remove(layer)\n"
392 "\n"
393 "   Remove a layer\n"
394 "\n"
395 "   :arg layer: The layer to remove.\n"
396 "   :type layer: :class:`BMLayerItem`\n"
397 );
398 static PyObject *bpy_bmlayercollection_remove(BPy_BMLayerCollection *self, BPy_BMLayerItem *value)
399 {
400         CustomData *data;
401
402         BPY_BM_CHECK_OBJ(self);
403
404         if (!BPy_BMLayerItem_Check(value)) {
405                 PyErr_Format(PyExc_TypeError,
406                              "layers.remove(x): expected BMLayerItem, not '%.200s'",
407                              Py_TYPE(value)->tp_name);
408                 return NULL;
409         }
410
411         BPY_BM_CHECK_OBJ(value);
412
413         if ((self->bm != value->bm) ||
414             (self->type != value->type) ||
415             (self->htype != value->htype))
416         {
417                 PyErr_SetString(PyExc_ValueError,
418                                 "layers.remove(x): x not in layers");
419         }
420
421         data = bpy_bm_customdata_get(self->bm, self->htype);
422         BM_data_layer_free_n(self->bm, data, self->type, value->index);
423
424         Py_RETURN_NONE;
425 }
426
427
428 PyDoc_STRVAR(bpy_bmlayercollection_keys_doc,
429 ".. method:: keys()\n"
430 "\n"
431 "   Return the identifiers of collection members\n"
432 "   (matching pythons dict.keys() functionality).\n"
433 "\n"
434 "   :return: the identifiers for each member of this collection.\n"
435 "   :rtype: list of strings\n"
436 );
437 static PyObject *bpy_bmlayercollection_keys(BPy_BMLayerCollection *self)
438 {
439         PyObject *ret;
440         PyObject *item;
441         int index;
442         CustomData *data;
443         int tot, i;
444
445         BPY_BM_CHECK_OBJ(self);
446
447         data = bpy_bm_customdata_get(self->bm, self->htype);
448         index = CustomData_get_layer_index(data, self->type); /* absolute, but no need to make relative */
449         tot = (index != -1) ? CustomData_number_of_layers(data, self->type) : 0;
450
451         ret = PyList_New(tot);
452
453         for (i = 0; tot-- > 0; index++) {
454                 item = PyUnicode_FromString(data->layers[index].name);
455                 PyList_SET_ITEM(ret, i++, item);
456         }
457
458         return ret;
459 }
460
461 PyDoc_STRVAR(bpy_bmlayercollection_items_doc,
462 ".. method:: items()\n"
463 "\n"
464 "   Return the identifiers of collection members\n"
465 "   (matching pythons dict.items() functionality).\n"
466 "\n"
467 "   :return: (key, value) pairs for each member of this collection.\n"
468 "   :rtype: list of tuples\n"
469 );
470 static PyObject *bpy_bmlayercollection_items(BPy_BMLayerCollection *self)
471 {
472         PyObject *ret;
473         PyObject *item;
474         int index;
475         CustomData *data;
476         int tot, i;
477
478         BPY_BM_CHECK_OBJ(self);
479
480         data = bpy_bm_customdata_get(self->bm, self->htype);
481         index = CustomData_get_layer_index(data, self->type);
482         tot = (index != -1) ? CustomData_number_of_layers(data, self->type) : 0;
483
484         ret = PyList_New(tot);
485
486         for (i = 0; tot-- > 0; index++) {
487                 item = PyTuple_New(2);
488                 PyTuple_SET_ITEMS(item,
489                         PyUnicode_FromString(data->layers[index].name),
490                         BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, i));
491                 PyList_SET_ITEM(ret, i++, item);
492         }
493
494         return ret;
495 }
496
497 PyDoc_STRVAR(bpy_bmlayercollection_values_doc,
498 ".. method:: values()\n"
499 "\n"
500 "   Return the values of collection\n"
501 "   (matching pythons dict.values() functionality).\n"
502 "\n"
503 "   :return: the members of this collection.\n"
504 "   :rtype: list\n"
505 );
506 static PyObject *bpy_bmlayercollection_values(BPy_BMLayerCollection *self)
507 {
508         PyObject *ret;
509         PyObject *item;
510         int index;
511         CustomData *data;
512         int tot, i;
513
514         BPY_BM_CHECK_OBJ(self);
515
516         data = bpy_bm_customdata_get(self->bm, self->htype);
517         index = CustomData_get_layer_index(data, self->type);
518         tot = (index != -1) ? CustomData_number_of_layers(data, self->type) : 0;
519
520         ret = PyList_New(tot);
521
522         for (i = 0; tot-- > 0; index++) {
523                 item = BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, i);
524                 PyList_SET_ITEM(ret, i++, item);
525         }
526
527         return ret;
528 }
529
530 PyDoc_STRVAR(bpy_bmlayercollection_get_doc,
531 ".. method:: get(key, default=None)\n"
532 "\n"
533 "   Returns the value of the layer matching the key or default\n"
534 "   when not found (matches pythons dictionary function of the same name).\n"
535 "\n"
536 "   :arg key: The key associated with the layer.\n"
537 "   :type key: string\n"
538 "   :arg default: Optional argument for the value to return if\n"
539 "      *key* is not found.\n"
540 "   :type default: Undefined\n"
541 );
542 static PyObject *bpy_bmlayercollection_get(BPy_BMLayerCollection *self, PyObject *args)
543 {
544         const char *key;
545         PyObject *def = Py_None;
546
547         BPY_BM_CHECK_OBJ(self);
548
549         if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) {
550                 return NULL;
551         }
552         else {
553                 CustomData *data;
554                 int index;
555
556                 data = bpy_bm_customdata_get(self->bm, self->htype);
557                 index = CustomData_get_named_layer(data, self->type, key);  /* type relative */
558
559                 if (index != -1) {
560                         return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
561                 }
562         }
563
564         return Py_INCREF_RET(def);
565 }
566
567 static struct PyMethodDef bpy_bmlayeritem_methods[] = {
568         {"copy_from", (PyCFunction)bpy_bmlayeritem_copy_from,    METH_O,       bpy_bmlayeritem_copy_from_doc},
569         {NULL, NULL, 0, NULL}
570 };
571
572 static struct PyMethodDef bpy_bmelemseq_methods[] = {
573         {"verify",  (PyCFunction)bpy_bmlayercollection_verify,   METH_NOARGS,  bpy_bmlayercollection_verify_doc},
574         {"new",     (PyCFunction)bpy_bmlayercollection_new,      METH_VARARGS, bpy_bmlayercollection_new_doc},
575         {"remove",  (PyCFunction)bpy_bmlayercollection_remove,   METH_O,       bpy_bmlayercollection_remove_doc},
576
577         {"keys",    (PyCFunction)bpy_bmlayercollection_keys,     METH_NOARGS,  bpy_bmlayercollection_keys_doc},
578         {"values",  (PyCFunction)bpy_bmlayercollection_values,   METH_NOARGS,  bpy_bmlayercollection_values_doc},
579         {"items",   (PyCFunction)bpy_bmlayercollection_items,    METH_NOARGS,  bpy_bmlayercollection_items_doc},
580         {"get",     (PyCFunction)bpy_bmlayercollection_get,      METH_VARARGS, bpy_bmlayercollection_get_doc},
581         {NULL, NULL, 0, NULL}
582 };
583
584 /* Sequences
585  * ========= */
586
587 static Py_ssize_t bpy_bmlayercollection_length(BPy_BMLayerCollection *self)
588 {
589         CustomData *data;
590
591         BPY_BM_CHECK_INT(self);
592
593         data = bpy_bm_customdata_get(self->bm, self->htype);
594
595         return CustomData_number_of_layers(data, self->type);
596 }
597
598 static PyObject *bpy_bmlayercollection_subscript_str(BPy_BMLayerCollection *self, const char *keyname)
599 {
600         CustomData *data;
601         int index;
602
603         BPY_BM_CHECK_OBJ(self);
604
605         data = bpy_bm_customdata_get(self->bm, self->htype);
606         index = CustomData_get_named_layer(data, self->type, keyname);  /* type relative */
607
608         if (index != -1) {
609                 return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
610         }
611         else {
612                 PyErr_Format(PyExc_KeyError,
613                              "BMLayerCollection[key]: key \"%.200s\" not found", keyname);
614                 return NULL;
615         }
616 }
617
618 static PyObject *bpy_bmlayercollection_subscript_int(BPy_BMLayerCollection *self, int keynum)
619 {
620         Py_ssize_t len;
621         BPY_BM_CHECK_OBJ(self);
622
623         len = bpy_bmlayercollection_length(self);
624
625         if (keynum < 0) keynum += len;
626         if (keynum >= 0) {
627                 if (keynum < len) {
628                         return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, keynum);
629                 }
630         }
631
632         PyErr_Format(PyExc_IndexError,
633                      "BMLayerCollection[index]: index %d out of range", keynum);
634         return NULL;
635 }
636
637 static PyObject *bpy_bmlayercollection_subscript_slice(BPy_BMLayerCollection *self, Py_ssize_t start, Py_ssize_t stop)
638 {
639         Py_ssize_t len = bpy_bmlayercollection_length(self);
640         int count = 0;
641
642         PyObject *tuple;
643
644         BPY_BM_CHECK_OBJ(self);
645
646         if (start >= len) start = len - 1;
647         if (stop  >= len) stop  = len - 1;
648
649         tuple = PyTuple_New(stop - start);
650
651         for (count = start; count < stop; count++) {
652                 PyTuple_SET_ITEM(tuple, count - start, BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, count));
653         }
654
655         return tuple;
656 }
657
658 static PyObject *bpy_bmlayercollection_subscript(BPy_BMLayerCollection *self, PyObject *key)
659 {
660         /* don't need error check here */
661         if (PyUnicode_Check(key)) {
662                 return bpy_bmlayercollection_subscript_str(self, _PyUnicode_AsString(key));
663         }
664         else if (PyIndex_Check(key)) {
665                 Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
666                 if (i == -1 && PyErr_Occurred())
667                         return NULL;
668                 return bpy_bmlayercollection_subscript_int(self, i);
669         }
670         else if (PySlice_Check(key)) {
671                 PySliceObject *key_slice = (PySliceObject *)key;
672                 Py_ssize_t step = 1;
673
674                 if (key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
675                         return NULL;
676                 }
677                 else if (step != 1) {
678                         PyErr_SetString(PyExc_TypeError,
679                                         "BMLayerCollection[slice]: slice steps not supported");
680                         return NULL;
681                 }
682                 else if (key_slice->start == Py_None && key_slice->stop == Py_None) {
683                         return bpy_bmlayercollection_subscript_slice(self, 0, PY_SSIZE_T_MAX);
684                 }
685                 else {
686                         Py_ssize_t start = 0, stop = PY_SSIZE_T_MAX;
687
688                         /* avoid PySlice_GetIndicesEx because it needs to know the length ahead of time. */
689                         if (key_slice->start != Py_None && !_PyEval_SliceIndex(key_slice->start, &start)) return NULL;
690                         if (key_slice->stop != Py_None && !_PyEval_SliceIndex(key_slice->stop, &stop))    return NULL;
691
692                         if (start < 0 || stop < 0) {
693                                 /* only get the length for negative values */
694                                 Py_ssize_t len = bpy_bmlayercollection_length(self);
695                                 if (start < 0) start += len;
696                                 if (stop  < 0) stop  += len;
697                         }
698
699                         if (stop - start <= 0) {
700                                 return PyTuple_New(0);
701                         }
702                         else {
703                                 return bpy_bmlayercollection_subscript_slice(self, start, stop);
704                         }
705                 }
706         }
707         else {
708                 PyErr_SetString(PyExc_AttributeError,
709                                 "BMLayerCollection[key]: invalid key, key must be an int");
710                 return NULL;
711         }
712 }
713
714 static int bpy_bmlayercollection_contains(BPy_BMLayerCollection *self, PyObject *value)
715 {
716         const char *keyname = _PyUnicode_AsString(value);
717         CustomData *data;
718         int index;
719
720         BPY_BM_CHECK_INT(self);
721
722         if (keyname == NULL) {
723                 PyErr_SetString(PyExc_TypeError,
724                                 "BMLayerCollection.__contains__: expected a string");
725                 return -1;
726         }
727
728         data = bpy_bm_customdata_get(self->bm, self->htype);
729         index = CustomData_get_named_layer_index(data, self->type, keyname);
730
731         return (index != -1) ? 1 : 0;
732 }
733
734 static PySequenceMethods bpy_bmlayercollection_as_sequence = {
735         (lenfunc)bpy_bmlayercollection_length,       /* sq_length */
736         NULL,                                        /* sq_concat */
737         NULL,                                        /* sq_repeat */
738         (ssizeargfunc)bpy_bmlayercollection_subscript_int, /* sq_item */ /* Only set this so PySequence_Check() returns True */
739         NULL,                                        /* sq_slice */
740         (ssizeobjargproc)NULL,                       /* sq_ass_item */
741         NULL,                                        /* *was* sq_ass_slice */
742         (objobjproc)bpy_bmlayercollection_contains,  /* sq_contains */
743         (binaryfunc) NULL,                           /* sq_inplace_concat */
744         (ssizeargfunc) NULL,                         /* sq_inplace_repeat */
745 };
746
747 static PyMappingMethods bpy_bmlayercollection_as_mapping = {
748         (lenfunc)bpy_bmlayercollection_length,       /* mp_length */
749         (binaryfunc)bpy_bmlayercollection_subscript, /* mp_subscript */
750         (objobjargproc)NULL,                         /* mp_ass_subscript */
751 };
752
753 /* Iterator
754  * -------- */
755
756 static PyObject *bpy_bmlayercollection_iter(BPy_BMLayerCollection *self)
757 {
758         /* fake it with a list iterator */
759         PyObject *ret;
760         PyObject *iter = NULL;
761
762         BPY_BM_CHECK_OBJ(self);
763
764         ret = bpy_bmlayercollection_subscript_slice(self, 0, PY_SSIZE_T_MIN);
765
766         if (ret) {
767                 iter = PyObject_GetIter(ret);
768                 Py_DECREF(ret);
769         }
770
771         return iter;
772 }
773
774 PyDoc_STRVAR(bpy_bmlayeraccess_type_doc,
775 "Exposes custom-data layer attributes."
776 );
777
778 PyDoc_STRVAR(bpy_bmlayercollection_type_doc,
779 "Gives access to a collection of custom-data layers of the same type and behaves like python dictionaries, "
780 "except for the ability to do list like index access."
781 );
782
783 PyDoc_STRVAR(bpy_bmlayeritem_type_doc,
784 "Exposes a single custom data layer, "
785 "their main purpose is for use as item accessors to custom-data when used with vert/edge/face/loop data."
786 );
787
788
789 PyTypeObject BPy_BMLayerAccessVert_Type; /* bm.verts.layers */
790 PyTypeObject BPy_BMLayerAccessEdge_Type; /* bm.edges.layers */
791 PyTypeObject BPy_BMLayerAccessFace_Type; /* bm.faces.layers */
792 PyTypeObject BPy_BMLayerAccessLoop_Type; /* bm.loops.layers */
793 PyTypeObject BPy_BMLayerCollection_Type; /* bm.loops.layers.uv */
794 PyTypeObject BPy_BMLayerItem_Type;       /* bm.loops.layers.uv["UVMap"] */
795
796
797 PyObject *BPy_BMLayerAccess_CreatePyObject(BMesh *bm, const char htype)
798 {
799         BPy_BMLayerAccess *self;
800         PyTypeObject *type;
801
802         switch (htype) {
803                 case BM_VERT:  type = &BPy_BMLayerAccessVert_Type;  break;
804                 case BM_EDGE:  type = &BPy_BMLayerAccessEdge_Type;  break;
805                 case BM_FACE:  type = &BPy_BMLayerAccessFace_Type;  break;
806                 case BM_LOOP:  type = &BPy_BMLayerAccessLoop_Type;  break;
807                 default:
808                 {
809                         BLI_assert(0);
810                         type = NULL;
811                         break;
812                 }
813         }
814
815         self = PyObject_New(BPy_BMLayerAccess, type);
816         self->bm = bm;
817         self->htype = htype;
818         return (PyObject *)self;
819 }
820
821 PyObject *BPy_BMLayerCollection_CreatePyObject(BMesh *bm, const char htype, int type)
822 {
823         BPy_BMLayerCollection *self = PyObject_New(BPy_BMLayerCollection, &BPy_BMLayerCollection_Type);
824         self->bm = bm;
825         self->htype = htype;
826         self->type = type;
827         return (PyObject *)self;
828 }
829
830 PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, const char htype, int type, int index)
831 {
832         BPy_BMLayerItem *self = PyObject_New(BPy_BMLayerItem, &BPy_BMLayerItem_Type);
833         self->bm = bm;
834         self->htype = htype;
835         self->type = type;
836         self->index = index;
837         return (PyObject *)self;
838 }
839
840
841 void BPy_BM_init_types_customdata(void)
842 {
843         BPy_BMLayerAccessVert_Type.tp_basicsize = sizeof(BPy_BMLayerAccess);
844         BPy_BMLayerAccessEdge_Type.tp_basicsize = sizeof(BPy_BMLayerAccess);
845         BPy_BMLayerAccessFace_Type.tp_basicsize = sizeof(BPy_BMLayerAccess);
846         BPy_BMLayerAccessLoop_Type.tp_basicsize = sizeof(BPy_BMLayerAccess);
847         BPy_BMLayerCollection_Type.tp_basicsize = sizeof(BPy_BMLayerCollection);
848         BPy_BMLayerItem_Type.tp_basicsize       = sizeof(BPy_BMLayerItem);
849
850         BPy_BMLayerAccessVert_Type.tp_name = "BMLayerAccessVert";
851         BPy_BMLayerAccessEdge_Type.tp_name = "BMLayerAccessEdge";
852         BPy_BMLayerAccessFace_Type.tp_name = "BMLayerAccessFace";
853         BPy_BMLayerAccessLoop_Type.tp_name = "BMLayerAccessLoop";
854         BPy_BMLayerCollection_Type.tp_name = "BMLayerCollection";
855         BPy_BMLayerItem_Type.tp_name       = "BMLayerItem";
856
857         /* todo */
858         BPy_BMLayerAccessVert_Type.tp_doc = bpy_bmlayeraccess_type_doc;
859         BPy_BMLayerAccessEdge_Type.tp_doc = bpy_bmlayeraccess_type_doc;
860         BPy_BMLayerAccessFace_Type.tp_doc = bpy_bmlayeraccess_type_doc;
861         BPy_BMLayerAccessLoop_Type.tp_doc = bpy_bmlayeraccess_type_doc;
862         BPy_BMLayerCollection_Type.tp_doc = bpy_bmlayercollection_type_doc;
863         BPy_BMLayerItem_Type.tp_doc       = bpy_bmlayeritem_type_doc;
864
865         BPy_BMLayerAccessVert_Type.tp_repr = (reprfunc)NULL;
866         BPy_BMLayerAccessEdge_Type.tp_repr = (reprfunc)NULL;
867         BPy_BMLayerAccessFace_Type.tp_repr = (reprfunc)NULL;
868         BPy_BMLayerAccessLoop_Type.tp_repr = (reprfunc)NULL;
869         BPy_BMLayerCollection_Type.tp_repr = (reprfunc)NULL;
870         BPy_BMLayerItem_Type.tp_repr = (reprfunc)NULL;
871
872         BPy_BMLayerAccessVert_Type.tp_getset = bpy_bmlayeraccess_vert_getseters;
873         BPy_BMLayerAccessEdge_Type.tp_getset = bpy_bmlayeraccess_edge_getseters;
874         BPy_BMLayerAccessFace_Type.tp_getset = bpy_bmlayeraccess_face_getseters;
875         BPy_BMLayerAccessLoop_Type.tp_getset = bpy_bmlayeraccess_loop_getseters;
876         BPy_BMLayerCollection_Type.tp_getset = bpy_bmlayercollection_getseters;
877         BPy_BMLayerItem_Type.tp_getset       = bpy_bmlayeritem_getseters;
878
879
880 //      BPy_BMLayerAccess_Type.tp_methods     = bpy_bmeditselseq_methods;
881         BPy_BMLayerCollection_Type.tp_methods = bpy_bmelemseq_methods;
882         BPy_BMLayerItem_Type.tp_methods       = bpy_bmlayeritem_methods;
883
884         BPy_BMLayerCollection_Type.tp_as_sequence = &bpy_bmlayercollection_as_sequence;
885
886         BPy_BMLayerCollection_Type.tp_as_mapping = &bpy_bmlayercollection_as_mapping;
887
888         BPy_BMLayerCollection_Type.tp_iter = (getiterfunc)bpy_bmlayercollection_iter;
889
890         BPy_BMLayerAccessVert_Type.tp_dealloc = NULL;
891         BPy_BMLayerAccessEdge_Type.tp_dealloc = NULL;
892         BPy_BMLayerAccessFace_Type.tp_dealloc = NULL;
893         BPy_BMLayerAccessLoop_Type.tp_dealloc = NULL;
894         BPy_BMLayerCollection_Type.tp_dealloc = NULL;
895         BPy_BMLayerItem_Type.tp_dealloc       = NULL;
896
897
898
899         BPy_BMLayerAccessVert_Type.tp_flags = Py_TPFLAGS_DEFAULT;
900         BPy_BMLayerAccessEdge_Type.tp_flags = Py_TPFLAGS_DEFAULT;
901         BPy_BMLayerAccessFace_Type.tp_flags = Py_TPFLAGS_DEFAULT;
902         BPy_BMLayerAccessLoop_Type.tp_flags = Py_TPFLAGS_DEFAULT;
903         BPy_BMLayerCollection_Type.tp_flags = Py_TPFLAGS_DEFAULT;
904         BPy_BMLayerItem_Type.tp_flags       = Py_TPFLAGS_DEFAULT;
905
906         PyType_Ready(&BPy_BMLayerAccessVert_Type);
907         PyType_Ready(&BPy_BMLayerAccessEdge_Type);
908         PyType_Ready(&BPy_BMLayerAccessFace_Type);
909         PyType_Ready(&BPy_BMLayerAccessLoop_Type);
910         PyType_Ready(&BPy_BMLayerCollection_Type);
911         PyType_Ready(&BPy_BMLayerItem_Type);
912 }
913
914
915 /* Per Element Get/Set
916  * ******************* */
917
918 /**
919  * helper function for get/set, NULL return means the error is set
920  */
921 static void *bpy_bmlayeritem_ptr_get(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
922 {
923         void *value;
924         BMElem *ele = py_ele->ele;
925         CustomData *data;
926
927         /* error checking */
928         if (UNLIKELY(!BPy_BMLayerItem_Check(py_layer))) {
929                 PyErr_SetString(PyExc_AttributeError,
930                                 "BMElem[key]: invalid key, must be a BMLayerItem");
931                 return NULL;
932         }
933         else if (UNLIKELY(py_ele->bm != py_layer->bm)) {
934                 PyErr_SetString(PyExc_ValueError,
935                                 "BMElem[layer]: layer is from another mesh");
936                 return NULL;
937         }
938         else if (UNLIKELY(ele->head.htype != py_layer->htype)) {
939                 char namestr_1[32], namestr_2[32];
940                 PyErr_Format(PyExc_ValueError,
941                              "Layer/Element type mismatch, expected %.200s got layer type %.200s",
942                              BPy_BMElem_StringFromHType_ex(ele->head.htype, namestr_1),
943                              BPy_BMElem_StringFromHType_ex(py_layer->htype, namestr_2));
944                 return NULL;
945         }
946
947         data = bpy_bm_customdata_get(py_layer->bm, py_layer->htype);
948
949         value = CustomData_bmesh_get_n(data, ele->head.data, py_layer->type, py_layer->index);
950
951         if (UNLIKELY(value == NULL)) {
952                 /* this should be fairly unlikely but possible if layers move about after we get them */
953                 PyErr_SetString(PyExc_KeyError,
954                                 "BMElem[key]: layer not found");
955                 return NULL;
956         }
957         else {
958                 return value;
959         }
960 }
961
962
963 /**
964  *\brief BMElem.__getitem__()
965  *
966  * assume all error checks are done, eg:
967  *
968  *     uv = vert[uv_layer]
969  */
970 PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
971 {
972         void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer);
973         PyObject *ret;
974
975         if (UNLIKELY(value == NULL)) {
976                 return NULL;
977         }
978
979         switch (py_layer->type) {
980                 case CD_MDEFORMVERT:
981                 {
982                         ret = BPy_BMDeformVert_CreatePyObject(value);
983                         break;
984                 }
985                 case CD_PROP_FLT:
986                 case CD_PAINT_MASK:
987                 {
988                         ret = PyFloat_FromDouble(*(float *)value);
989                         break;
990                 }
991                 case CD_PROP_INT:
992                 {
993                         ret = PyLong_FromLong(*(int *)value);
994                         break;
995                 }
996                 case CD_PROP_STR:
997                 {
998                         MStringProperty *mstring = value;
999                         ret = PyBytes_FromStringAndSize(mstring->s, mstring->s_len);
1000                         break;
1001                 }
1002                 case CD_MTEXPOLY:
1003                 {
1004                         ret = BPy_BMTexPoly_CreatePyObject(value);
1005                         break;
1006                 }
1007                 case CD_MLOOPUV:
1008                 {
1009                         ret = BPy_BMLoopUV_CreatePyObject(value);
1010                         break;
1011                 }
1012                 case CD_MLOOPCOL:
1013                 {
1014                         ret = BPy_BMLoopColor_CreatePyObject(value);
1015                         break;
1016                 }
1017                 case CD_SHAPEKEY:
1018                 {
1019                         ret = Vector_CreatePyObject_wrap((float *)value, 3, NULL);
1020                         break;
1021                 }
1022                 case CD_BWEIGHT:
1023                 {
1024                         ret = PyFloat_FromDouble(*(float *)value);
1025                         break;
1026                 }
1027                 case CD_CREASE:
1028                 {
1029                         ret = PyFloat_FromDouble(*(float *)value);
1030                         break;
1031                 }
1032                 case CD_MVERT_SKIN:
1033                 {
1034                         ret = BPy_BMVertSkin_CreatePyObject(value);
1035                         break;
1036                 }
1037                 default:
1038                 {
1039                         ret = Py_NotImplemented; /* TODO */
1040                         Py_INCREF(ret);
1041                         break;
1042                 }
1043         }
1044
1045         return ret;
1046 }
1047
1048 int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *py_value)
1049 {
1050         int ret = 0;
1051         void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer);
1052
1053         if (UNLIKELY(value == NULL)) {
1054                 return -1;
1055         }
1056
1057         switch (py_layer->type) {
1058                 case CD_MDEFORMVERT:
1059                 {
1060                         ret = BPy_BMDeformVert_AssignPyObject(value, py_value);
1061                         break;
1062                 }
1063                 case CD_PROP_FLT:
1064                 case CD_PAINT_MASK:
1065                 {
1066                         float tmp_val = PyFloat_AsDouble(py_value);
1067                         if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) {
1068                                 PyErr_Format(PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name);
1069                                 ret = -1;
1070                         }
1071                         else {
1072                                 *(float *)value = tmp_val;
1073                         }
1074                         break;
1075                 }
1076                 case CD_PROP_INT:
1077                 {
1078                         int tmp_val = PyC_Long_AsI32(py_value);
1079                         if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) {
1080                                 /* error is set */
1081                                 ret = -1;
1082                         }
1083                         else {
1084                                 *(int *)value = tmp_val;
1085                         }
1086                         break;
1087                 }
1088                 case CD_PROP_STR:
1089                 {
1090                         MStringProperty *mstring = value;
1091                         char *tmp_val;
1092                         Py_ssize_t tmp_val_len;
1093                         if (UNLIKELY(PyBytes_AsStringAndSize(py_value, &tmp_val, &tmp_val_len) == -1)) {
1094                                 PyErr_Format(PyExc_TypeError, "expected bytes, not a %.200s", Py_TYPE(py_value)->tp_name);
1095                                 ret = -1;
1096                         }
1097                         else {
1098                                 if (tmp_val_len > sizeof(mstring->s))
1099                                         tmp_val_len = sizeof(mstring->s);
1100                                 memcpy(mstring->s, tmp_val, tmp_val_len);
1101                                 mstring->s_len = tmp_val_len;
1102                         }
1103                         break;
1104                 }
1105                 case CD_MTEXPOLY:
1106                 {
1107                         ret = BPy_BMTexPoly_AssignPyObject(value, py_value);
1108                         break;
1109                 }
1110                 case CD_MLOOPUV:
1111                 {
1112                         ret = BPy_BMLoopUV_AssignPyObject(value, py_value);
1113                         break;
1114                 }
1115                 case CD_MLOOPCOL:
1116                 {
1117                         ret = BPy_BMLoopColor_AssignPyObject(value, py_value);
1118                         break;
1119                 }
1120                 case CD_SHAPEKEY:
1121                 {
1122                         float tmp_val[3];
1123                         if (UNLIKELY(mathutils_array_parse(tmp_val, 3, 3, py_value, "BMVert[shape] = value") == -1)) {
1124                                 ret = -1;
1125                         }
1126                         else {
1127                                 copy_v3_v3((float *)value, tmp_val);
1128                         }
1129                         break;
1130                 }
1131                 case CD_BWEIGHT:
1132                 {
1133                         float tmp_val = PyFloat_AsDouble(py_value);
1134                         if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) {
1135                                 PyErr_Format(PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name);
1136                                 ret = -1;
1137                         }
1138                         else {
1139                                 *(float *)value = CLAMPIS(tmp_val, 0.0f, 1.0f);
1140                         }
1141                         break;
1142                 }
1143                 case CD_CREASE:
1144                 {
1145                         float tmp_val = PyFloat_AsDouble(py_value);
1146                         if (UNLIKELY(tmp_val == -1 && PyErr_Occurred())) {
1147                                 PyErr_Format(PyExc_TypeError, "expected a float, not a %.200s", Py_TYPE(py_value)->tp_name);
1148                                 ret = -1;
1149                         }
1150                         else {
1151                                 *(float *)value = CLAMPIS(tmp_val, 0.0f, 1.0f);
1152                         }
1153                         break;
1154                 }
1155                 case CD_MVERT_SKIN:
1156                 {
1157                         ret = BPy_BMVertSkin_AssignPyObject(value, py_value);
1158                         break;
1159                 }
1160                 default:
1161                 {
1162                         PyErr_SetString(PyExc_AttributeError, "readonly / unsupported type");
1163                         ret = -1;
1164                         break;
1165                 }
1166         }
1167
1168         return ret;
1169 }