2 * ***** BEGIN GPL LICENSE BLOCK *****
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.
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.
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.
18 * The Original Code is Copyright (C) 2012 Blender Foundation.
19 * All rights reserved.
21 * Contributor(s): Campbell Barton
23 * ***** END GPL LICENSE BLOCK *****
26 /** \file blender/python/bmesh/bmesh_py_types_customdata.c
29 * This file defines the types for 'BMesh.verts/edges/faces/loops.layers'
30 * customdata layer access.
35 #include "BLI_string.h"
36 #include "BLI_math_vector.h"
40 #include "bmesh_py_types.h"
41 #include "bmesh_py_types_customdata.h"
42 #include "bmesh_py_types_meshdata.h"
44 #include "../mathutils/mathutils.h"
46 #include "BKE_customdata.h"
48 #include "DNA_meshdata_types.h"
50 static CustomData *bpy_bm_customdata_get(BMesh *bm, char 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;
63 static CustomDataLayer *bpy_bmlayeritem_get(BPy_BMLayerItem *self)
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)];
69 /* py-type definitions
70 * ******************* */
75 /* used for many different types */
77 PyDoc_STRVAR(bpy_bmlayeraccess_collection__float_doc,
78 "Generic float custom-data layer.\n\ntype: :class:`BMLayerCollection`"
80 PyDoc_STRVAR(bpy_bmlayeraccess_collection__int_doc,
81 "Generic int custom-data layer.\n\ntype: :class:`BMLayerCollection`"
83 PyDoc_STRVAR(bpy_bmlayeraccess_collection__string_doc,
84 "Generic string custom-data layer (exposed as bytes, 255 max length).\n\ntype: :class:`BMLayerCollection`"
86 PyDoc_STRVAR(bpy_bmlayeraccess_collection__deform_doc,
87 "Vertex deform weight :class:`BMDeformVert` (TODO).\n\ntype: :class:`BMLayerCollection`" // TYPE DOESN'T EXIST YET
89 PyDoc_STRVAR(bpy_bmlayeraccess_collection__shape_doc,
90 "Vertex shapekey absolute location (as a 3D Vector).\n\n:type: :class:`BMLayerCollection`"
92 PyDoc_STRVAR(bpy_bmlayeraccess_collection__bevel_weight_doc,
93 "Bevel weight float in [0 - 1].\n\n:type: :class:`BMLayerCollection`"
95 PyDoc_STRVAR(bpy_bmlayeraccess_collection__crease_doc,
96 "Edge crease for subsurf - float in [0 - 1].\n\n:type: :class:`BMLayerCollection`"
98 PyDoc_STRVAR(bpy_bmlayeraccess_collection__tex_doc,
99 "Accessor for :class:`BMTexPoly` layer (TODO).\n\ntype: :class:`BMLayerCollection`" // TYPE DOESN'T EXIST YET
101 PyDoc_STRVAR(bpy_bmlayeraccess_collection__uv_doc,
102 "Accessor for :class:`BMLoopUV` UV (as a 2D Vector).\n\ntype: :class:`BMLayerCollection`"
104 PyDoc_STRVAR(bpy_bmlayeraccess_collection__color_doc,
105 "Accessor for vertex color layer.\n\ntype: :class:`BMLayerCollection`"
108 static PyObject *bpy_bmlayeraccess_collection_get(BPy_BMLayerAccess *self, void *flag)
110 const int type = (int)GET_INT_FROM_POINTER(flag);
112 BPY_BM_CHECK_OBJ(self);
114 return BPy_BMLayerCollection_CreatePyObject(self->bm, self->htype, type);
118 PyDoc_STRVAR(bpy_bmlayercollection_active_doc,
119 "This meshes vert sequence (read-only).\n\n:type: :class:`BMVertSeq`"
121 static PyObject *bpy_bmlayercollection_active_get(BPy_BMLayerItem *self, void *UNUSED(flag))
126 BPY_BM_CHECK_OBJ(self);
128 data = bpy_bm_customdata_get(self->bm, self->htype);
129 index = CustomData_get_active_layer_index(data, self->type);
132 return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
139 PyDoc_STRVAR(bpy_bmlayercollection_name_doc,
140 "The layers unique name (read-only).\n\n:type: string"
142 static PyObject *bpy_bmlayeritem_name_get(BPy_BMLayerItem *self, void *UNUSED(flag))
144 CustomDataLayer *layer;
146 BPY_BM_CHECK_OBJ(self);
148 layer = bpy_bmlayeritem_get(self);
149 return PyUnicode_FromString(layer->name);
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},
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},
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},
162 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
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},
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},
173 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
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},
181 {(char *)"tex", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__tex_doc, (void *)CD_MTEXPOLY},
183 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
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},
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},
194 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
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},
202 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
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},
209 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
217 * ----------------- */
219 PyDoc_STRVAR(bpy_bmlayercollection_keys_doc,
220 ".. method:: keys()\n"
222 " Return the identifiers of collection members\n"
223 " (matching pythons dict.keys() functionality).\n"
225 " :return: the identifiers for each member of this collection.\n"
226 " :rtype: list of strings\n"
228 static PyObject *bpy_bmlayercollection_keys(BPy_BMLayerCollection *self)
235 BPY_BM_CHECK_OBJ(self);
237 data = bpy_bm_customdata_get(self->bm, self->htype);
238 index = CustomData_get_layer_index(data, self->type);
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);
254 PyDoc_STRVAR(bpy_bmlayercollection_values_doc,
255 ".. method:: items()\n"
257 " Return the identifiers of collection members\n"
258 " (matching pythons dict.items() functionality).\n"
260 " :return: (key, value) pairs for each member of this collection.\n"
261 " :rtype: list of tuples\n"
263 static PyObject *bpy_bmlayercollection_values(BPy_BMLayerCollection *self)
270 BPY_BM_CHECK_OBJ(self);
272 data = bpy_bm_customdata_get(self->bm, self->htype);
273 index = CustomData_get_layer_index(data, self->type);
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);
291 PyDoc_STRVAR(bpy_bmlayercollection_items_doc,
292 ".. method:: values()\n"
294 " Return the values of collection\n"
295 " (matching pythons dict.values() functionality).\n"
297 " :return: the members of this collection.\n"
300 static PyObject *bpy_bmlayercollection_items(BPy_BMLayerCollection *self)
307 BPY_BM_CHECK_OBJ(self);
309 data = bpy_bm_customdata_get(self->bm, self->htype);
310 index = CustomData_get_layer_index(data, self->type);
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);
326 PyDoc_STRVAR(bpy_bmlayercollection_get_doc,
327 ".. method:: get(key, default=None)\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"
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"
338 static PyObject *bpy_bmlayercollection_get(BPy_BMLayerCollection *self, PyObject *args)
341 PyObject *def = Py_None;
343 BPY_BM_CHECK_OBJ(self);
345 if (!PyArg_ParseTuple(args, "s|O:get", &key, &def)) {
352 data = bpy_bm_customdata_get(self->bm, self->htype);
353 index = CustomData_get_named_layer_index(data, self->type, key);
356 return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
360 return Py_INCREF(def), def;
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},
372 {"new", (PyCFunction)bpy_bmlayercollection_new, METH_O, bpy_bmlayercollection_new_doc},
373 {"remove", (PyCFunction)bpy_bmlayercollection_new, METH_O, bpy_bmlayercollection_remove_doc},
375 {NULL, NULL, 0, NULL}
383 static Py_ssize_t bpy_bmlayercollection_length(BPy_BMLayerCollection *self)
387 BPY_BM_CHECK_INT(self);
389 data = bpy_bm_customdata_get(self->bm, self->htype);
391 return CustomData_number_of_layers(data, self->type);
394 static PyObject *bpy_bmlayercollection_subscript_str(BPy_BMLayerCollection *self, const char *keyname)
399 BPY_BM_CHECK_OBJ(self);
401 data = bpy_bm_customdata_get(self->bm, self->htype);
402 index = CustomData_get_named_layer_index(data, self->type, keyname);
405 return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, index);
408 PyErr_Format(PyExc_KeyError,
409 "BMLayerCollection[key]: key \"%.200s\" not found", keyname);
414 static PyObject *bpy_bmlayercollection_subscript_int(BPy_BMLayerCollection *self, int keynum)
417 BPY_BM_CHECK_OBJ(self);
419 len = bpy_bmlayercollection_length(self);
421 if (keynum < 0) keynum += len;
424 return BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, keynum);
428 PyErr_Format(PyExc_IndexError,
429 "BMLayerCollection[index]: index %d out of range", keynum);
433 static PyObject *bpy_bmlayercollection_subscript_slice(BPy_BMLayerCollection *self, Py_ssize_t start, Py_ssize_t stop)
435 Py_ssize_t len = bpy_bmlayercollection_length(self);
440 BPY_BM_CHECK_OBJ(self);
442 if (start >= start) start = len - 1;
443 if (stop >= stop) stop = len - 1;
445 tuple = PyTuple_New(stop - start);
447 for (count = start; count < stop; count++) {
448 PyTuple_SET_ITEM(tuple, count - start, BPy_BMLayerItem_CreatePyObject(self->bm, self->htype, self->type, count));
454 static PyObject *bpy_bmlayercollection_subscript(BPy_BMLayerCollection *self, PyObject *key)
456 /* don't need error check here */
457 if (PyUnicode_Check(key)) {
458 return bpy_bmlayercollection_subscript_str(self, _PyUnicode_AsString(key));
460 else if (PyIndex_Check(key)) {
461 Py_ssize_t i = PyNumber_AsSsize_t(key, PyExc_IndexError);
462 if (i == -1 && PyErr_Occurred())
464 return bpy_bmlayercollection_subscript_int(self, i);
466 else if (PySlice_Check(key)) {
467 PySliceObject *key_slice = (PySliceObject *)key;
470 if (key_slice->step != Py_None && !_PyEval_SliceIndex(key, &step)) {
473 else if (step != 1) {
474 PyErr_SetString(PyExc_TypeError,
475 "BMLayerCollection[slice]: slice steps not supported");
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);
482 Py_ssize_t start = 0, stop = PY_SSIZE_T_MAX;
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;
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;
495 if (stop - start <= 0) {
496 return PyTuple_New(0);
499 return bpy_bmlayercollection_subscript_slice(self, start, stop);
504 PyErr_SetString(PyExc_AttributeError,
505 "BMLayerCollection[key]: invalid key, key must be an int");
510 static int bpy_bmlayercollection_contains(BPy_BMLayerCollection *self, PyObject *value)
512 const char *keyname = _PyUnicode_AsString(value);
516 BPY_BM_CHECK_INT(self);
518 if (keyname == NULL) {
519 PyErr_SetString(PyExc_TypeError,
520 "BMLayerCollection.__contains__: expected a string");
524 data = bpy_bm_customdata_get(self->bm, self->htype);
525 index = CustomData_get_named_layer_index(data, self->type, keyname);
527 return (index != -1) ? 1 : 0;
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 */
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 */
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 */
552 static PyObject *bpy_bmlayercollection_iter(BPy_BMLayerCollection *self)
554 /* fake it with a list iterator */
556 PyObject *iter = NULL;
558 BPY_BM_CHECK_OBJ(self);
560 ret = bpy_bmlayercollection_subscript_slice(self, 0, PY_SSIZE_T_MIN);
563 iter = PyObject_GetIter(ret);
570 PyDoc_STRVAR(bpy_bmlayeraccess_type_doc,
571 "Exposes custom-data layer attributes."
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."
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."
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"] */
593 PyObject *BPy_BMLayerAccess_CreatePyObject(BMesh *bm, const char htype)
595 BPy_BMLayerAccess *self;
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;
611 self = PyObject_New(BPy_BMLayerAccess, type);
614 return (PyObject *)self;
617 PyObject *BPy_BMLayerCollection_CreatePyObject(BMesh *bm, const char htype, int type)
619 BPy_BMLayerCollection *self = PyObject_New(BPy_BMLayerCollection, &BPy_BMLayerCollection_Type);
623 return (PyObject *)self;
626 PyObject *BPy_BMLayerItem_CreatePyObject(BMesh *bm, const char htype, int type, int index)
628 BPy_BMLayerItem *self = PyObject_New(BPy_BMLayerItem, &BPy_BMLayerItem_Type);
633 return (PyObject *)self;
637 void BPy_BM_init_types_customdata(void)
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);
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";
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;
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;
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;
676 // BPy_BMLayerAccess_Type.tp_methods = bpy_bmeditselseq_methods;
677 BPy_BMLayerCollection_Type.tp_methods = bpy_bmelemseq_methods;
679 BPy_BMLayerCollection_Type.tp_as_sequence = &bpy_bmlayercollection_as_sequence;
681 BPy_BMLayerCollection_Type.tp_as_mapping = &bpy_bmlayercollection_as_mapping;
683 BPy_BMLayerCollection_Type.tp_iter = (getiterfunc)bpy_bmlayercollection_iter;
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;
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;
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);
710 /* Per Element Get/Set
711 * ******************* */
714 * helper function for get/set, NULL return means the error is set
716 static void *bpy_bmlayeritem_ptr_get(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
719 BMElem *ele = py_ele->ele;
723 if (UNLIKELY(!BPy_BMLayerItem_Check(py_layer))) {
724 PyErr_SetString(PyExc_AttributeError,
725 "BMElem[key]: invalid key, must be a BMLayerItem");
728 else if (UNLIKELY(py_ele->bm != py_layer->bm)) {
729 PyErr_SetString(PyExc_ValueError,
730 "BMElem[layer]: layer is from another mesh");
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));
742 data = bpy_bm_customdata_get(py_layer->bm, py_layer->htype);
744 value = CustomData_bmesh_get_n(data, ele->head.data, py_layer->type, py_layer->index);
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");
759 *\brief BMElem.__getitem__()
761 * assume all error checks are done, eg:
763 * uv = vert[uv_layer]
765 PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
767 void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer);
770 if (UNLIKELY(value == NULL)) {
774 switch (py_layer->type) {
777 ret = BPy_BMDeformVert_CreatePyObject(value);
782 ret = PyFloat_FromDouble(*(float *)value);
787 ret = PyLong_FromSsize_t((Py_ssize_t)(*(int *)value));
792 MStringProperty *mstring = value;
793 ret = PyBytes_FromStringAndSize(mstring->s, BLI_strnlen(mstring->s, sizeof(mstring->s)));
798 ret = Py_NotImplemented; /* TODO */
804 ret = BPy_BMLoopUV_CreatePyObject(value);
809 ret = BPy_BMLoopColor_CreatePyObject(value);
814 ret = Vector_CreatePyObject((float *)value, 3, Py_WRAP, NULL);
819 ret = PyFloat_FromDouble(*(float *)value);
824 ret = PyFloat_FromDouble(*(float *)value);
829 ret = Py_NotImplemented; /* TODO */
838 int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObject *py_value)
841 void *value = bpy_bmlayeritem_ptr_get(py_ele, py_layer);
843 if (UNLIKELY(value == NULL)) {
847 switch (py_layer->type) {
850 ret = BPy_BMDeformVert_AssignPyObject(value, py_value);
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);
861 *(float *)value = tmp_val;
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);
873 *(int *)value = tmp_val;
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);
886 BLI_strncpy(mstring->s, tmp_val, sizeof(mstring->s));
892 PyErr_SetString(PyExc_AttributeError, "readonly"); /* could make this writeable later */
898 ret = BPy_BMLoopUV_AssignPyObject(value, py_value);
903 ret = BPy_BMLoopColor_AssignPyObject(value, py_value);
909 if (UNLIKELY(mathutils_array_parse(tmp_val, 3, 3, py_value, "BMVert[shape] = value") == -1)) {
913 copy_v3_v3((float *)value, tmp_val);
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);
925 *(float *)value = CLAMPIS(tmp_val, 0.0f, 1.0f);
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);
937 *(float *)value = CLAMPIS(tmp_val, 0.0f, 1.0f);
943 PyErr_SetString(PyExc_AttributeError, "readonly / unsupported type");