Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBastien Montagne <montagne29@wanadoo.fr>2016-06-08 18:23:40 +0300
committerBastien Montagne <montagne29@wanadoo.fr>2016-06-08 18:23:40 +0300
commitae440c84fd4ed50988c7665bc118daee6f4c47ba (patch)
tree40d7695eca94235010e04cf0cc74f21a81371d78
parent399b56aacc0e227defc494ed67cdc8cf5c5c85a3 (diff)
BMesh clnor: Change py API.
After some talking with Campbell, this is now accessible through BMesh's CustomData system: - clnor data is now exposed in BMesh (same way as for UVs etc.). - You can now get/set **raw** values (pair of factors) of each loop independently. This is not so useful in itself (though it allows nice 'relative' normal edition, given what those two factors represent), getting/setting 'real' normals there is for later. - You can now set all custom normals at once using the new 'from_array' method of BMLayerItem. This is supposed to be generic setter, but for now it's only implemented for clnor data. Some notes/reflections, also for future developments: - About from_array: * Do we accept that rather 'flexible' way of handling given array of data? think we do not have much choice if we want to keep generic BMLayerItem (else we'll have to define sub-classes of this for every type of data :/ ). * Currently clnor's from_array returns values actually set as a new array, not sure we want to keep this, or instead add another 'to_array' method (in this case, how do we control type of returned data?). - About clnors in BMesh in general: * Think ultimately we'll want to have own struct of clnors in BMesh, caching clnor spaces, encoded normal, real normal, etc. * We'll then need to add lots of stuff to handle edition, in particular a system to rebuild clnor spaces of affected loops each time we add/remove/modify geometry... Latest point is important, since it means current BMesh py API will **not** be stable for now, and will most certainly break when full support of custom normals is added to BMesh.
-rw-r--r--source/blender/blenkernel/intern/mesh_evaluate.c11
-rw-r--r--source/blender/blenlib/BLI_math_base.h4
-rw-r--r--source/blender/blenlib/intern/math_base_inline.c12
-rw-r--r--source/blender/python/bmesh/bmesh_py_types_customdata.c287
-rw-r--r--source/blender/python/bmesh/bmesh_py_utils.c123
5 files changed, 302 insertions, 135 deletions
diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c
index 2c448aaa109..899eaf6a759 100644
--- a/source/blender/blenkernel/intern/mesh_evaluate.c
+++ b/source/blender/blenkernel/intern/mesh_evaluate.c
@@ -510,17 +510,6 @@ void BKE_lnor_space_add_loop(MLoopNorSpaceArray *lnors_spacearr, MLoopNorSpace *
}
}
-MINLINE float unit_short_to_float(const short val)
-{
- return (float)val / (float)SHRT_MAX;
-}
-
-MINLINE short unit_float_to_short(const float val)
-{
- /* Rounding... */
- return (short)floorf(val * (float)SHRT_MAX + 0.5f);
-}
-
void BKE_lnor_space_custom_data_to_normal(MLoopNorSpace *lnor_space, const short clnor_data[2], float r_custom_lnor[3])
{
/* NOP custom normal data or invalid lnor space, return. */
diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h
index e97a250cd24..e6c98cb7173 100644
--- a/source/blender/blenlib/BLI_math_base.h
+++ b/source/blender/blenlib/BLI_math_base.h
@@ -210,6 +210,10 @@ MINLINE int mod_i(int i, int n);
int pow_i(int base, int exp);
double double_round(double x, int ndigits);
+MINLINE float unit_short_to_float(const short val);
+MINLINE short unit_float_to_short(const float val);
+
+
#ifdef BLI_MATH_GCC_WARN_PRAGMA
# pragma GCC diagnostic pop
#endif
diff --git a/source/blender/blenlib/intern/math_base_inline.c b/source/blender/blenlib/intern/math_base_inline.c
index 8d2d80c2a35..f8cde6e5c4c 100644
--- a/source/blender/blenlib/intern/math_base_inline.c
+++ b/source/blender/blenlib/intern/math_base_inline.c
@@ -33,6 +33,7 @@
#include <float.h>
#include <stdio.h>
#include <stdlib.h>
+#include <limits.h>
#ifdef __SSE2__
# include <emmintrin.h>
@@ -314,6 +315,17 @@ MINLINE int signum_i(float a)
else return 0;
}
+MINLINE float unit_short_to_float(const short val)
+{
+ return (float)val / (float)SHRT_MAX;
+}
+
+MINLINE short unit_float_to_short(const float val)
+{
+ /* Rounding... */
+ return (short)floorf(val * (float)SHRT_MAX + 0.5f);
+}
+
/* Internal helpers for SSE2 implementation.
*
* NOTE: Are to be called ONLY from inside `#ifdef __SSE2__` !!!
diff --git a/source/blender/python/bmesh/bmesh_py_types_customdata.c b/source/blender/python/bmesh/bmesh_py_types_customdata.c
index 908f6b5a734..27707d9e95c 100644
--- a/source/blender/python/bmesh/bmesh_py_types_customdata.c
+++ b/source/blender/python/bmesh/bmesh_py_types_customdata.c
@@ -44,6 +44,8 @@
#include "../mathutils/mathutils.h"
#include "../generic/python_utildefines.h"
+#include "MEM_guardedalloc.h"
+
#include "BKE_customdata.h"
#include "DNA_meshdata_types.h"
@@ -113,6 +115,9 @@ PyDoc_STRVAR(bpy_bmlayeraccess_collection__uv_doc,
PyDoc_STRVAR(bpy_bmlayeraccess_collection__color_doc,
"Accessor for vertex color layer.\n\ntype: :class:`BMLayerCollection`"
);
+PyDoc_STRVAR(bpy_bmlayeraccess_collection__clnor_doc,
+"Accessor for custom loop normal layer.\n\ntype: :class:`BMLayerCollection`"
+);
PyDoc_STRVAR(bpy_bmlayeraccess_collection__skin_doc,
"Accessor for skin layer.\n\ntype: :class:`BMLayerCollection`"
);
@@ -239,6 +244,8 @@ static PyGetSetDef bpy_bmlayeraccess_loop_getseters[] = {
{(char *)"uv", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__uv_doc, (void *)CD_MLOOPUV},
{(char *)"color", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__color_doc, (void *)CD_MLOOPCOL},
+ {(char *)"clnor", (getter)bpy_bmlayeraccess_collection_get, (setter)NULL, (char *)bpy_bmlayeraccess_collection__clnor_doc, (void *)CD_CUSTOMLOOPNORMAL},
+
{NULL, NULL, NULL, NULL, NULL} /* Sentinel */
};
@@ -311,6 +318,256 @@ static PyObject *bpy_bmlayeritem_copy_from(BPy_BMLayerItem *self, BPy_BMLayerIte
Py_RETURN_NONE;
}
+#define bpy_bmlayeritem_from_array__clnors_doc \
+" clnor layer: Array may be either:\n" \
+" - A sequence of num_loop tuples (float, float):\n" \
+" Raw storage of custom normals, as (alpha, beta) factors in [-1.0, 1.0] range.\n" \
+" - A sequence of num_loop vectors (float, float, float):\n" \
+" Custom normals per loop, as (x, y, z) components (normalization is ensured internaly).\n" \
+" - A sequence of num_vert vectors (float, float, float):\n" \
+" Custom normals per vertex, as (x, y, z) components (normalization is ensured internaly).\n" \
+" In all cases, items which are None or null vectors will use default auto-computed normal.\n" \
+"\n" \
+" Returns an array of the same type as given one, with None/null-vector values replaced by actual ones.\n"
+static PyObject *bpy_bmlayeritem_from_array__clnors(BPy_BMLayerItem *self, PyObject *value)
+{
+ PyObject *ret;
+
+ float (*nors)[3] = NULL;
+ float (*clnors)[2] = NULL;
+ Py_ssize_t nbr_val;
+ Py_ssize_t vec_size;
+ int cd_loop_clnors_offset;
+
+ BMesh *bm = self->bm;
+
+ if ((cd_loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL)) == -1) {
+ /* Should never ever happen! */
+ PyErr_Format(PyExc_SystemError,
+ "clnor's from_array(): No custom normal data layer in the bmesh");
+ return NULL;
+ }
+
+ value = PySequence_Fast(value, "normals must be an iterable");
+ if (!value) {
+ return NULL;
+ }
+
+ nbr_val = PySequence_Fast_GET_SIZE(value);
+
+ if (!ELEM(nbr_val, bm->totloop, bm->totvert)) {
+ PyErr_Format(PyExc_TypeError, "clnor's from_array(): There must be either one data per vertex or one per loop");
+ Py_DECREF(value);
+ return NULL;
+ }
+
+ vec_size = 3; /* In case value is an array of None's only. */
+ for (Py_ssize_t i = 0; i < nbr_val; i++) {
+ PyObject *py_vec = PySequence_Fast_GET_ITEM(value, i);
+
+ if (py_vec == Py_None) {
+ continue;
+ }
+ py_vec = PySequence_Fast(py_vec, "");
+ if (py_vec) {
+ vec_size = PySequence_Fast_GET_SIZE(py_vec);
+ }
+ if (!py_vec || (vec_size == 2 && nbr_val != bm->totloop) || vec_size != 3) {
+ PyErr_Format(PyExc_TypeError,
+ "clnor's from_array(): array items must be either triplets of floats, "
+ "or pair of floats factors for raw clnor data, first item is neither "
+ "(or total number of items does match expected one, %d verts/%d loops)",
+ bm->totvert, bm->totloop);
+ MEM_freeN(nors);
+ Py_DECREF(value);
+ Py_XDECREF(py_vec);
+ return NULL;
+ }
+ break;
+ }
+
+ if (vec_size == 2) {
+ clnors = MEM_mallocN(sizeof(*clnors) * nbr_val, __func__);
+ for (Py_ssize_t i = 0; i < nbr_val; i++) {
+ PyObject *py_vec = PySequence_Fast_GET_ITEM(value, i);
+
+ if (py_vec == Py_None) {
+ clnors[i][0] = clnors[i][1] = 0.0f;
+ }
+ else {
+ py_vec = PySequence_Fast(py_vec, "");
+ if (!py_vec || PySequence_Fast_GET_SIZE(py_vec) != 2) {
+ PyErr_Format(PyExc_TypeError,
+ "clnor's from_array(): clnors are expected to be pairs of floats "
+ "in [-1.0, 1.0] range, clnor %d is not", i);
+ MEM_freeN(clnors);
+ Py_DECREF(value);
+ Py_XDECREF(py_vec);
+ return NULL;
+ }
+
+ for (int j = 0; j < 2; j++) {
+ PyObject *py_float = PyNumber_Float(PySequence_Fast_GET_ITEM(py_vec, j));
+
+ if (!py_float || !PyFloat_Check(py_float)) {
+ PyErr_Format(PyExc_TypeError,
+ "clnor's from_array(): clnors are expected to be pairs of floats "
+ "in [-1.0, 1.0] range, clnor %d is not", i);
+ MEM_freeN(clnors);
+ Py_DECREF(value);
+ Py_DECREF(py_vec);
+ Py_XDECREF(py_float);
+ return NULL;
+ }
+
+ clnors[i][j] = (float)PyFloat_AS_DOUBLE(py_float);
+ if (clnors[i][j] < -1.0f || clnors[i][j] > 1.0f) {
+ PyErr_Format(PyExc_TypeError,
+ "clnor's from_array(): clnors are expected to be pairs of floats "
+ "in [-1.0, 1.0] range, clnor %d is not", i);
+ MEM_freeN(clnors);
+ Py_DECREF(value);
+ Py_DECREF(py_vec);
+ Py_DECREF(py_float);
+ return NULL;
+ }
+ Py_DECREF(py_float);
+ }
+ }
+ Py_DECREF(py_vec);
+ }
+ }
+ else {
+ nors = MEM_mallocN(sizeof(*nors) * nbr_val, __func__);
+ for (Py_ssize_t i = 0; i < nbr_val; i++) {
+ PyObject *py_vec = PySequence_Fast_GET_ITEM(value, i);
+
+ if (py_vec == Py_None) {
+ zero_v3(nors[i]);
+ }
+ else {
+ py_vec = PySequence_Fast(py_vec, "");
+ if (!py_vec || PySequence_Fast_GET_SIZE(py_vec) != 3) {
+ PyErr_Format(PyExc_TypeError,
+ "clnor's from_array(): normals are expected to be triplets of floats, normal %d is not", i);
+ MEM_freeN(nors);
+ Py_DECREF(value);
+ Py_XDECREF(py_vec);
+ return NULL;
+ }
+
+ for (int j = 0; j < 3; j++) {
+ PyObject *py_float = PyNumber_Float(PySequence_Fast_GET_ITEM(py_vec, j));
+
+ if (!py_float || !PyFloat_Check(py_float)) {
+ PyErr_Format(PyExc_TypeError,
+ "clnor's from_array(): normals are expected to be triplets of floats, normal %d is not", i);
+ MEM_freeN(nors);
+ Py_DECREF(value);
+ Py_DECREF(py_vec);
+ Py_XDECREF(py_float);
+ return NULL;
+ }
+
+ nors[i][j] = (float)PyFloat_AS_DOUBLE(py_float);
+ Py_DECREF(py_float);
+ }
+ normalize_v3(nors[i]); /* Just in case... */
+ }
+ Py_DECREF(py_vec);
+ }
+ }
+
+ Py_DECREF(value);
+ ret = PyTuple_New(nbr_val);
+
+ if (vec_size == 2) {
+ BMIter fiter;
+ BMIter liter;
+ BMFace *f;
+ BMLoop *l;
+
+ BM_mesh_elem_index_ensure(bm, BM_LOOP);
+
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ const int lidx = BM_elem_index_get(l);
+ short *clnor = BM_ELEM_CD_GET_VOID_P(l, cd_loop_clnors_offset);
+ clnor[0] = unit_float_to_short(clnors[lidx][0]);
+ clnor[1] = unit_float_to_short(clnors[lidx][1]);
+
+ PyObject *py_vec = PyTuple_Pack(2,
+ PyFloat_FromDouble((double)clnors[lidx][0]),
+ PyFloat_FromDouble((double)clnors[lidx][1]));
+
+ PyTuple_SET_ITEM(ret, lidx, py_vec);
+ }
+ }
+ }
+ else {
+ if (nbr_val == bm->totloop) {
+ BM_loops_normal_custom_set(bm, nors, NULL, cd_loop_clnors_offset);
+ }
+ else {
+ BM_loops_normal_custom_set_from_vertices(bm, nors, NULL, cd_loop_clnors_offset);
+ }
+
+ for (Py_ssize_t i = 0; i < nbr_val; i++) {
+ PyObject *py_vec = PyTuple_Pack(3,
+ PyFloat_FromDouble((double)nors[i][0]),
+ PyFloat_FromDouble((double)nors[i][1]),
+ PyFloat_FromDouble((double)nors[i][2]));
+
+ PyTuple_SET_ITEM(ret, i, py_vec);
+ }
+
+ MEM_freeN(nors);
+ }
+
+ return ret;
+}
+
+PyDoc_STRVAR(bpy_bmlayeritem_from_array_doc,
+".. method:: from_array(array)\n"
+"\n"
+" Set whole layer data from values in given array (or any type of iterable).\n"
+"\n"
+"\n"
+bpy_bmlayeritem_from_array__clnors_doc
+"\n"
+"\n"
+" :arg array: Iterable of data to set from.\n"
+);
+static PyObject *bpy_bmlayeritem_from_array(BPy_BMLayerItem *self, PyObject *value)
+{
+ PyObject *ret;
+
+ BPY_BM_CHECK_OBJ(self);
+
+ switch (self->htype) {
+ case BM_LOOP:
+ switch (self->type) {
+ case CD_CUSTOMLOOPNORMAL:
+ ret = bpy_bmlayeritem_from_array__clnors(self, value);
+ break;
+ default:
+ ret = Py_NotImplemented; /* TODO */
+ Py_INCREF(ret);
+ }
+ break;
+ case BM_VERT:
+ case BM_EDGE:
+ case BM_FACE:
+ ret = Py_NotImplemented; /* TODO */
+ Py_INCREF(ret);
+ break;
+ default:
+ ret = NULL;
+ }
+
+ return ret;
+}
+
/* similar to new(), but no name arg. */
PyDoc_STRVAR(bpy_bmlayercollection_verify_doc,
".. method:: verify()\n"
@@ -564,7 +821,10 @@ static PyObject *bpy_bmlayercollection_get(BPy_BMLayerCollection *self, PyObject
}
static struct PyMethodDef bpy_bmlayeritem_methods[] = {
- {"copy_from", (PyCFunction)bpy_bmlayeritem_copy_from, METH_O, bpy_bmlayeritem_copy_from_doc},
+ {"copy_from", (PyCFunction)bpy_bmlayeritem_copy_from, METH_O, bpy_bmlayeritem_copy_from_doc},
+
+ {"from_array", (PyCFunction)bpy_bmlayeritem_from_array, METH_O, bpy_bmlayeritem_from_array_doc},
+
{NULL, NULL, 0, NULL}
};
@@ -1013,6 +1273,14 @@ PyObject *BPy_BMLayerItem_GetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer)
ret = BPy_BMLoopColor_CreatePyObject(value);
break;
}
+ case CD_CUSTOMLOOPNORMAL:
+ {
+ float vec[2];
+ vec[0] = unit_short_to_float(((short *)value)[0]);
+ vec[1] = unit_short_to_float(((short *)value)[1]);
+ ret = Vector_CreatePyObject(vec, 2, NULL);
+ break;
+ }
case CD_SHAPEKEY:
{
ret = Vector_CreatePyObject_wrap((float *)value, 3, NULL);
@@ -1116,6 +1384,23 @@ int BPy_BMLayerItem_SetItem(BPy_BMElem *py_ele, BPy_BMLayerItem *py_layer, PyObj
ret = BPy_BMLoopColor_AssignPyObject(value, py_value);
break;
}
+ case CD_CUSTOMLOOPNORMAL:
+ {
+ float vec[2];
+ if (UNLIKELY(mathutils_array_parse(vec, 2, 2, py_value, "BMLoop[clnor] = value") == -1)) {
+ ret = -1;
+ break;
+ }
+ if (vec[0] < -1.0f || vec[0] > 1.0f || vec[1] < -1.0f || vec[1] > 1.0f) {
+ PyErr_Format(PyExc_ValueError, "expected float values between -1.0 and 1.0, not (%f, %f)",
+ vec[0], vec[1]);
+ ret = -1;
+ break;
+ }
+ ((short *)value)[0] = unit_float_to_short(vec[0]);
+ ((short *)value)[1] = unit_float_to_short(vec[1]);
+ break;
+ }
case CD_SHAPEKEY:
{
float tmp_val[3];
diff --git a/source/blender/python/bmesh/bmesh_py_utils.c b/source/blender/python/bmesh/bmesh_py_utils.c
index 266a9250dc1..df3bfb1f545 100644
--- a/source/blender/python/bmesh/bmesh_py_utils.c
+++ b/source/blender/python/bmesh/bmesh_py_utils.c
@@ -802,128 +802,6 @@ static PyObject *bpy_bm_utils_loop_separate(PyObject *UNUSED(self), BPy_BMLoop *
}
-PyDoc_STRVAR(bpy_bm_utils_custom_normals_set_doc,
-".. method:: custom_normals_set(bm, normals)\n"
-"\n"
-" Set given normals into bmesh (can be per-loop or per-vertex normals).\n"
-"\n"
-" :arg bm: The bmesh to set custom normals.\n"
-" :type bm: :class:`bmesh.types.BMesh`\n"
-" :arg normals: Normals to set (for each loop or each vertex, use null vectors or None to use default normal).\n"
-" :type normals: sequence of None and/or float triplets, either one per loop or one per vertex\n"
-" :return: The normals (with 'auto' ones set to their actual values).\n"
-" :rtype: sequence of float triplets, either one per loop or one per vertex\n"
-);
-static PyObject *bpy_bm_utils_custom_normals_set(PyObject *UNUSED(self), PyObject *args, PyObject *kw)
-{
- static const char *kwlist[] = {"bm", "normals", NULL};
-
- BPy_BMesh *py_bm;
- PyObject *py_nors = NULL;
-
- float (*nors)[3];
- Py_ssize_t nbr_nors;
- int loop_clnors_offset;
-
- BMesh *bm;
-
- if (!PyArg_ParseTupleAndKeywords(
- args, kw,
- "O!O:custom_normals_set", (char **)kwlist,
- &BPy_BMesh_Type, &py_bm,
- &py_nors))
- {
- return NULL;
- }
-
- bm = py_bm->bm;
-
- py_nors = PySequence_Fast(py_nors, "normals must be an iterable");
- if (!py_nors) {
- return NULL;
- }
-
- nbr_nors = PySequence_Fast_GET_SIZE(py_nors);
-
- if (!ELEM(nbr_nors, bm->totloop, bm->totvert)) {
- PyErr_Format(PyExc_TypeError, "custom_normals_set: There must be either one normal per vertex or one per loop");
- Py_DECREF(py_nors);
- return NULL;
- }
-
- nors = MEM_mallocN(sizeof(*nors) * nbr_nors, __func__);
- for (Py_ssize_t i = 0; i < nbr_nors; i++) {
- PyObject *py_vec = PySequence_Fast_GET_ITEM(py_nors, i);
-
- if (py_vec == Py_None) {
- zero_v3(nors[i]);
- }
- else {
- py_vec = PySequence_Fast(py_vec, "");
- if (!py_vec || PySequence_Fast_GET_SIZE(py_vec) != 3) {
- PyErr_Format(PyExc_TypeError,
- "custom_normals_set: normals are expected to be triplets of floats, normal %d is not", i);
- MEM_freeN(nors);
- Py_DECREF(py_nors);
- Py_XDECREF(py_vec);
- return NULL;
- }
-
- for (int j = 0; j < 3; j++) {
- PyObject *py_float = PyNumber_Float(PySequence_Fast_GET_ITEM(py_vec, j));
-
- if (!py_float || !PyFloat_Check(py_float)) {
- PyErr_Format(PyExc_TypeError,
- "custom_normals_set: normals are expected to be triplets of floats, normal %d is not", i);
- MEM_freeN(nors);
- Py_DECREF(py_nors);
- Py_DECREF(py_vec);
- Py_XDECREF(py_float);
- return NULL;
- }
-
- nors[i][j] = (float)PyFloat_AS_DOUBLE(py_float);
- Py_DECREF(py_float);
- }
- normalize_v3(nors[i]); /* Just in case... */
- }
- Py_DECREF(py_vec);
- }
- Py_DECREF(py_nors);
-
- if ((loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL)) == -1) {
- BM_data_layer_add(bm, &bm->ldata, CD_CUSTOMLOOPNORMAL);
- loop_clnors_offset = CustomData_get_offset(&bm->ldata, CD_CUSTOMLOOPNORMAL);
-
- if (loop_clnors_offset == -1) {
- PyErr_Format(PyExc_TypeError,
- "custom_normals_set: Impossible to add a custom normal data layer to the bmesh");
- MEM_freeN(nors);
- return NULL;
- }
- }
-
- if (nbr_nors == bm->totloop) {
- BM_loops_normal_custom_set(bm, nors, NULL, loop_clnors_offset);
- }
- else {
- BM_loops_normal_custom_set_from_vertices(bm, nors, NULL, loop_clnors_offset);
- }
-
- py_nors = PyTuple_New(nbr_nors);
- for (Py_ssize_t i = 0; i < nbr_nors; i++) {
- PyObject *py_vec = PyTuple_Pack(3,
- PyFloat_FromDouble((double)nors[i][0]),
- PyFloat_FromDouble((double)nors[i][1]),
- PyFloat_FromDouble((double)nors[i][2]));
-
- PyTuple_SET_ITEM(py_nors, i, py_vec);
- }
-
- MEM_freeN(nors);
- return py_nors;
-}
-
static struct PyMethodDef BPy_BM_utils_methods[] = {
{"vert_collapse_edge", (PyCFunction)bpy_bm_utils_vert_collapse_edge, METH_VARARGS, bpy_bm_utils_vert_collapse_edge_doc},
{"vert_collapse_faces", (PyCFunction)bpy_bm_utils_vert_collapse_faces, METH_VARARGS, bpy_bm_utils_vert_collapse_faces_doc},
@@ -938,7 +816,6 @@ static struct PyMethodDef BPy_BM_utils_methods[] = {
{"face_vert_separate", (PyCFunction)bpy_bm_utils_face_vert_separate, METH_VARARGS, bpy_bm_utils_face_vert_separate_doc},
{"face_flip", (PyCFunction)bpy_bm_utils_face_flip, METH_O, bpy_bm_utils_face_flip_doc},
{"loop_separate", (PyCFunction)bpy_bm_utils_loop_separate, METH_O, bpy_bm_utils_loop_separate_doc},
- {"custom_normals_set", (PyCFunction)bpy_bm_utils_custom_normals_set, METH_VARARGS | METH_KEYWORDS, bpy_bm_utils_custom_normals_set_doc},
{NULL, NULL, 0, NULL}
};