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