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