diff options
author | Willian Padovani Germano <wpgermano@gmail.com> | 2003-05-17 08:29:49 +0400 |
---|---|---|
committer | Willian Padovani Germano <wpgermano@gmail.com> | 2003-05-17 08:29:49 +0400 |
commit | ed78dcc96cde26c56207aeb1fbd91488ca3a7f12 (patch) | |
tree | bbfb74104e4a37662a4ee84f2adcf73674ecb913 /source/blender/python/api2_2x/NMesh.c | |
parent | 7c48bec8999d536e1b0f2316e28cb6f6a36a6bbb (diff) |
* Added submodule NMesh:
Partially implemented. Most of it comes from opy_nmesh.c, plus needed
changes to integrate in into exppython.
* Added helper submodule vector, needed by NMesh.
* Minor changes in other files.
Diffstat (limited to 'source/blender/python/api2_2x/NMesh.c')
-rw-r--r-- | source/blender/python/api2_2x/NMesh.c | 1584 |
1 files changed, 1584 insertions, 0 deletions
diff --git a/source/blender/python/api2_2x/NMesh.c b/source/blender/python/api2_2x/NMesh.c new file mode 100644 index 00000000000..8f1fadfd813 --- /dev/null +++ b/source/blender/python/api2_2x/NMesh.c @@ -0,0 +1,1584 @@ +/* + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * This is a new part of Blender. + * + * Contributor(s): Willian P. Germano + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* This file is opy_nmesh.c from bpython modified to work with the new + * implementation of the Blender Python API */ + +#include "NMesh.h" + +void mesh_update(Mesh *mesh) +{ + edge_drawflags_mesh(mesh); + tex_space_mesh(mesh); +} + +/*****************************/ +/* Mesh Color Object */ +/*****************************/ + +static void NMCol_dealloc(PyObject *self) +{ + PyMem_DEL(self); +} + +static C_NMCol *newcol (char r, char g, char b, char a) +{ + C_NMCol *mc = (C_NMCol *) PyObject_NEW (C_NMCol, &NMCol_Type); + + mc->r= r; + mc->g= g; + mc->b= b; + mc->a= a; + + return mc; +} + +static PyObject *M_NMesh_Col(PyObject *self, PyObject *args) +{ + short r = 255, g = 255, b = 255, a = 255; + + if(PyArg_ParseTuple(args, "|hhhh", &r, &g, &b, &a)) + return (PyObject *) newcol(r, g, b, a); + + return NULL; +} + +static PyObject *NMCol_getattr(PyObject *self, char *name) +{ + C_NMCol *mc = (C_NMCol *)self; + + if (strcmp(name, "r") == 0) return Py_BuildValue("i", mc->r); + else if (strcmp(name, "g") == 0) return Py_BuildValue("i", mc->g); + else if (strcmp(name, "b") == 0) return Py_BuildValue("i", mc->b); + else if (strcmp(name, "a") == 0) return Py_BuildValue("i", mc->a); + + return EXPP_ReturnPyObjError(PyExc_AttributeError, name); +} + +static int NMCol_setattr(PyObject *self, char *name, PyObject *v) +{ + C_NMCol *mc = (C_NMCol *)self; + short ival; + + if(!PyArg_Parse(v, "h", &ival)) return -1; + + ival = (short)EXPP_ClampInt(ival, 0, 255); + + if (strcmp(name, "r") == 0) mc->r = ival; + else if (strcmp(name, "g") == 0) mc->g = ival; + else if (strcmp(name, "b") == 0) mc->b = ival; + else if (strcmp(name, "a")==0) mc->a = ival; + else return -1; + + return 0; +} + +PyObject *NMCol_repr(C_NMCol *self) +{ + static char s[256]; + sprintf (s, "[NMCol - <%d, %d, %d, %d>]", self->r, self->g, self->b, self->a); + return Py_BuildValue("s", s); +} + +PyTypeObject NMCol_Type = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, /* ob_size */ + "NMCol", /* tp_name */ + sizeof(C_NMCol), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor) NMCol_dealloc, /* tp_dealloc */ + (printfunc) 0, /* tp_print */ + (getattrfunc) NMCol_getattr, /* tp_getattr */ + (setattrfunc) NMCol_setattr, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc) NMCol_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ +}; + +/*****************************/ +/* NMesh Python Object */ +/*****************************/ +static void NMFace_dealloc (PyObject *self) +{ + C_NMFace *mf = (C_NMFace *)self; + + Py_DECREF(mf->v); + Py_DECREF(mf->uv); + Py_DECREF(mf->col); + + PyMem_DEL(self); +} + +static C_NMFace *new_NMFace(PyObject *vertexlist) +{ + C_NMFace *mf = PyObject_NEW (C_NMFace, &NMFace_Type); + + mf->v = vertexlist; + mf->uv = PyList_New(0); + mf->image = NULL; + mf->mode = TF_DYNAMIC + TF_TEX; + mf->flag = TF_SELECT; + mf->transp = TF_SOLID; + mf->col = PyList_New(0); + + mf->smooth= 0; + mf->mat_nr= 0; + + return mf; +} + +static PyObject *M_NMesh_Face(PyObject *self, PyObject *args) +{ + PyObject *vertlist = NULL; + + if (!PyArg_ParseTuple(args, "|O!", &PyList_Type, &vertlist)) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected a list of vertices or nothing as argument"); + + if (!vertlist) vertlist = PyList_New(0); + + return (PyObject *)new_NMFace(vertlist); +} + +static PyObject *NMFace_append(PyObject *self, PyObject *args) +{ + PyObject *vert; + C_NMFace *f = (C_NMFace *)self; + + if (!PyArg_ParseTuple(args, "O!", &NMVert_Type, &vert)) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected an NMVert object"); + + PyList_Append(f->v, vert); + + return EXPP_incr_ret(Py_None); +} + +#undef MethodDef +#define MethodDef(func) {#func, NMFace_##func, METH_VARARGS, NMFace_##func##_doc} + +static struct PyMethodDef NMFace_methods[] = +{ + MethodDef(append), + {NULL, NULL} +}; + +static PyObject *NMFace_getattr(PyObject *self, char *name) +{ + C_NMFace *mf = (C_NMFace *)self; + + if(strcmp(name, "v") == 0) + return Py_BuildValue("O", mf->v); + else if (strcmp(name, "col") == 0) + return Py_BuildValue("O", mf->col); + else if (strcmp(name, "mat") == 0) // emulation XXX + return Py_BuildValue("i", mf->mat_nr); + else if (strcmp(name, "materialIndex") == 0) + return Py_BuildValue("i", mf->mat_nr); + else if (strcmp(name, "smooth") == 0) + return Py_BuildValue("i", mf->smooth); + + else if (strcmp(name, "image") == 0) { + if (mf->image) + return Py_BuildValue("O", (PyObject *)mf->image); + else + return EXPP_incr_ret(Py_None); + } + + else if (strcmp(name, "mode") == 0) + return Py_BuildValue("i", mf->mode); + else if (strcmp(name, "flag") == 0) + return Py_BuildValue("i", mf->flag); + else if (strcmp(name, "transp") == 0) + return Py_BuildValue("i", mf->transp); + else if (strcmp(name, "uv") == 0) + return Py_BuildValue("O", mf->uv); + + return Py_FindMethod(NMFace_methods, (PyObject*)self, name); +} + +static int NMFace_setattr(PyObject *self, char *name, PyObject *v) +{ + C_NMFace *mf = (C_NMFace *) self; + short ival; + + if (strcmp(name, "v") == 0) { + + if(PySequence_Check(v)) { + Py_DECREF(mf->v); + mf->v = EXPP_incr_ret(v); + + return 0; + } + } + else if (strcmp(name, "col") == 0) { + + if(PySequence_Check(v)) { + Py_DECREF(mf->col); + mf->col = EXPP_incr_ret(v); + + return 0; + } + } + else if (!strcmp(name, "mat") || !strcmp(name, "materialIndex")) { + PyArg_Parse(v, "h", &ival); + + mf->mat_nr= ival; + + return 0; + } + else if (strcmp(name, "smooth") == 0) { + PyArg_Parse(v, "h", &ival); + + mf->smooth = ival?1:0; + + return 0; + } + else if (strcmp(name, "uv") == 0) { + + if(PySequence_Check(v)) { + Py_DECREF(mf->uv); + mf->uv= EXPP_incr_ret(v); + + return 0; + } + } + else if (strcmp(name, "flag") == 0) { + PyArg_Parse(v, "h", &ival); + mf->flag = ival; + + return 0; + } + else if (strcmp(name, "mode") == 0) { + PyArg_Parse(v, "h", &ival); + mf->mode = ival; + + return 0; + } + else if (strcmp(name, "transp") == 0) { + PyArg_Parse(v, "h", &ival); + mf->transp = ival; + + return 0; + } + else if (strcmp(name, "image") == 0) { + PyObject *img; + PyArg_Parse(v, "O", &img); + + if (img == Py_None) { + mf->image = NULL; + + return 0; + } + + // XXX if PyType ... XXXXXXX + + mf->image = img; + + return 0; + } + + return EXPP_ReturnIntError (PyExc_AttributeError, name); +} + +static PyObject *NMFace_repr (PyObject *self) +{ + return PyString_FromString("[NMFace]"); +} + +static int NMFace_len(C_NMFace *self) +{ + return PySequence_Length(self->v); +} + +static PyObject *NMFace_item(C_NMFace *self, int i) +{ + return PySequence_GetItem(self->v, i); // new ref +} + +static PyObject *NMFace_slice(C_NMFace *self, int begin, int end) +{ + return PyList_GetSlice(self->v, begin, end); // new ref +} + +static PySequenceMethods NMFace_SeqMethods = +{ + (inquiry) NMFace_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) NMFace_item, /* sq_item */ + (intintargfunc) NMFace_slice, /* sq_slice */ + (intobjargproc) 0, /* sq_ass_item */ + (intintobjargproc) 0, /* sq_ass_slice */ +}; + +PyTypeObject NMFace_Type = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "NMFace", /*tp_name*/ + sizeof(C_NMFace), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor) NMFace_dealloc, /*tp_dealloc*/ + (printfunc) 0, /*tp_print*/ + (getattrfunc) NMFace_getattr, /*tp_getattr*/ + (setattrfunc) NMFace_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) NMFace_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + &NMFace_SeqMethods, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +static C_NMVert *newvert(float *co) +{ + C_NMVert *mv= PyObject_NEW(C_NMVert, &NMVert_Type); + + mv->co[0] = co[0]; mv->co[1] = co[1]; mv->co[2] = co[2]; + + mv->no[0] = mv->no[1] = mv->no[2] = 0.0; + mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0; + + return mv; +} + +static PyObject *M_NMesh_Vert(PyObject *self, PyObject *args) +{ + float co[3]= {0.0, 0.0, 0.0}; + + if (!PyArg_ParseTuple(args, "|fff", &co[0], &co[1], &co[2])) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected three floats (or nothing) as arguments"); + + return (PyObject *)newvert(co); +} + +static void NMVert_dealloc(PyObject *self) +{ + PyMem_DEL(self); +} + +static PyObject *NMVert_getattr(PyObject *self, char *name) +{ + C_NMVert *mv = (C_NMVert *)self; + + if (!strcmp(name, "co") || !strcmp(name, "loc")) + return newVectorObject(mv->co, 3); + + else if (strcmp(name, "no") == 0) return newVectorObject(mv->no, 3); + else if (strcmp(name, "uvco") == 0) return newVectorObject(mv->uvco, 3); + else if (strcmp(name, "index") == 0) return PyInt_FromLong(mv->index); + + return EXPP_ReturnPyObjError (PyExc_AttributeError, name); +} + +static int NMVert_setattr(PyObject *self, char *name, PyObject *v) +{ + C_NMVert *mv = (C_NMVert *)self; + int i; + + if (strcmp(name,"index") == 0) { + PyArg_Parse(v, "i", &i); + mv->index = i; + return 0; + } else if (strcmp(name, "uvco") == 0) { + + if (!PyArg_ParseTuple(v, "ff|f", + &(mv->uvco[0]), &(mv->uvco[1]), &(mv->uvco[2]))) + return EXPP_ReturnIntError (PyExc_AttributeError, + "Vector tuple or triple expected"); + + return 0; + } + + return EXPP_ReturnIntError (PyExc_AttributeError, name); +} + +static int NMVert_len(C_NMVert *self) +{ + return 3; +} + +static PyObject *NMVert_item(C_NMVert *self, int i) +{ + if (i < 0 || i >= 3) + return EXPP_ReturnPyObjError (PyExc_IndexError, + "array index out of range"); + + return Py_BuildValue("f", self->co[i]); +} + +static PyObject *NMVert_slice(C_NMVert *self, int begin, int end) +{ + PyObject *list; + int count; + + if (begin < 0) begin = 0; + if (end > 3) end = 3; + if (begin > end) begin = end; + + list = PyList_New(end-begin); + + for (count = begin; count < end; count++) + PyList_SetItem(list, count - begin, PyFloat_FromDouble(self->co[count])); + + return list; +} + +static int NMVert_ass_item(C_NMVert *self, int i, PyObject *ob) +{ + if (i < 0 || i >= 3) + return EXPP_ReturnIntError (PyExc_IndexError, + "array assignment index out of range"); + + if (!PyNumber_Check(ob)) + return EXPP_ReturnIntError (PyExc_IndexError, + "NMVert member must be a number"); + + self->co[i]= PyFloat_AsDouble(ob); + + return 0; +} + +static int NMVert_ass_slice(C_NMVert *self, int begin, int end, PyObject *seq) +{ + int count; + + if (begin < 0) begin = 0; + if (end > 3) end = 3; + if (begin > end) begin = end; + + if (!PySequence_Check(seq)) + EXPP_ReturnIntError (PyExc_TypeError, + "illegal argument type for built-in operation"); + + if (PySequence_Length(seq)!=(end-begin)) + EXPP_ReturnIntError (PyExc_TypeError, + "size mismatch in slice assignment"); + + for (count = begin; count < end; count++) { + PyObject *ob = PySequence_GetItem(seq, count); + + if (!PyArg_Parse(ob, "f", &self->co[count])) { + Py_DECREF(ob); + return -1; + } + + Py_DECREF(ob); + } + + return 0; +} + +static PySequenceMethods NMVert_SeqMethods = +{ + (inquiry) NMVert_len, /* sq_length */ + (binaryfunc) 0, /* sq_concat */ + (intargfunc) 0, /* sq_repeat */ + (intargfunc) NMVert_item, /* sq_item */ + (intintargfunc) NMVert_slice, /* sq_slice */ + (intobjargproc) NMVert_ass_item, /* sq_ass_item */ + (intintobjargproc) NMVert_ass_slice, /* sq_ass_slice */ +}; + +PyTypeObject NMVert_Type = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "NMVert", /*tp_name*/ + sizeof(C_NMVert), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor) NMVert_dealloc, /*tp_dealloc*/ + (printfunc) 0, /*tp_print*/ + (getattrfunc) NMVert_getattr, /*tp_getattr*/ + (setattrfunc) NMVert_setattr, /*tp_setattr*/ + 0, /*tp_compare*/ + (reprfunc) 0, /*tp_repr*/ + 0, /*tp_as_number*/ + &NMVert_SeqMethods, /*tp_as_sequence*/ +}; + +static void NMesh_dealloc(PyObject *self) +{ + C_NMesh *me= (C_NMesh *) self; + + Py_DECREF(me->name); + Py_DECREF(me->verts); + Py_DECREF(me->faces); + + PyMem_DEL(self); +} + +static PyObject *NMesh_getSelectedFaces(PyObject *self, PyObject *args) +{ + C_NMesh *nm= (C_NMesh *) self; + Mesh *me = nm->mesh; + int flag = 0; + + TFace *tf; + int i; + PyObject *l= PyList_New(0); + + if (me == NULL) return NULL; + + tf = me->tface; + if (tf == 0) return l; + + if (!PyArg_ParseTuple(args, "|i", &flag)) + return NULL; + if (flag) { + for (i =0 ; i < me->totface; i++) { + if (tf[i].flag & TF_SELECT ) { + PyList_Append(l, PyInt_FromLong(i)); + } + } + } else { + for (i =0 ; i < me->totface; i++) { + if (tf[i].flag & TF_SELECT ) { + PyList_Append(l, PyList_GetItem(nm->faces, i)); + } + } + } + return l; +} + +static PyObject *NMesh_getActiveFace(PyObject *self, PyObject *args) +{ + if (((C_NMesh *)self)->sel_face < 0) + return EXPP_incr_ret(Py_None); + + return Py_BuildValue("i", ((C_NMesh *)self)->sel_face); +} + +static PyObject *NMesh_hasVertexUV(PyObject *self, PyObject *args) +{ + C_NMesh *me = (C_NMesh *)self; + int flag; + + if (args) { + if (PyArg_ParseTuple(args, "i", &flag)) { + if(flag) me->flags |= NMESH_HASVERTUV; + else me->flags &= ~NMESH_HASVERTUV; + } + } + PyErr_Clear(); + if (me->flags & NMESH_HASVERTUV) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} + +static PyObject *NMesh_hasFaceUV(PyObject *self, PyObject *args) +{ + C_NMesh *me= (C_NMesh *) self; + int flag = -1; + + if (!PyArg_ParseTuple(args, "|i", &flag)) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected int argument (or nothing)"); + + switch (flag) { + case 0: + me->flags |= NMESH_HASFACEUV; + break; + case 1: + me->flags &= ~NMESH_HASFACEUV; + break; + default: + break; + } + + if (me->flags & NMESH_HASFACEUV) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} + +static PyObject *NMesh_hasVertexColours(PyObject *self, PyObject *args) +{ + C_NMesh *me= (C_NMesh *)self; + int flag = -1; + + if (!PyArg_ParseTuple(args, "|i", &flag)) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected int argument (or nothing)"); + + switch (flag) { + case 0: + me->flags &= ~NMESH_HASMCOL; + break; + case 1: + me->flags |= NMESH_HASMCOL; + break; + default: + break; + } + + if (me->flags & NMESH_HASMCOL) + return EXPP_incr_ret(Py_True); + else + return EXPP_incr_ret(Py_False); +} + +static PyObject *NMesh_update(PyObject *self, PyObject *args) +{ + C_NMesh *nmesh = (C_NMesh *)self; + Mesh *mesh = nmesh->mesh; + + if (mesh) { + unlink_existingMeshData(mesh); + convert_NMeshToMesh(mesh, nmesh); + mesh_update(mesh); + } else { + nmesh->mesh = Mesh_fromNMesh(nmesh); + } + + nmesh_updateMaterials(nmesh); +/**@ This is another ugly fix due to the weird material handling of blender. + * it makes sure that object material lists get updated (by their length) + * according to their data material lists, otherwise blender crashes. + * It just stupidly runs through all objects...BAD BAD BAD. + */ + test_object_materials((ID *)mesh); + + if (!during_script()) + allqueue(REDRAWVIEW3D, 0); + + return PyInt_FromLong(1); +} + +Mesh *Mesh_fromNMesh(C_NMesh *nmesh) +{ + Mesh *mesh = NULL; + mesh = add_mesh(); /* us == 1, should we zero it for all added objs ? */ + + if (!mesh) { + EXPP_ReturnPyObjError(PyExc_RuntimeError, + "FATAL: could not create mesh object"); + return NULL; + } + + convert_NMeshToMesh(mesh, nmesh); + mesh_update(mesh); + + return mesh; +} + +PyObject * NMesh_link(PyObject *self, PyObject *args) +{ +// XXX return DataBlock_link(self, args); + return EXPP_incr_ret(Py_None); +} + +#undef MethodDef +#define MethodDef(func) {#func, NMesh_##func, METH_VARARGS, NMesh_##func##_doc} + +static struct PyMethodDef NMesh_methods[] = +{ + MethodDef(hasVertexColours), + MethodDef(hasFaceUV), + MethodDef(hasVertexUV), + MethodDef(getActiveFace), + MethodDef(getSelectedFaces), + MethodDef(update), + {NULL, NULL} +}; + +static PyObject *NMesh_getattr(PyObject *self, char *name) +{ + C_NMesh *me = (C_NMesh *)self; + + if (strcmp(name, "name") == 0) + return EXPP_incr_ret(me->name); + + else if (strcmp(name, "block_type") == 0) + return PyString_FromString("NMesh"); + + else if (strcmp(name, "materials") == 0) + return EXPP_incr_ret(me->materials); + + else if (strcmp(name, "verts") == 0) + return EXPP_incr_ret(me->verts); + + else if (strcmp(name, "users") == 0) { + if (me->mesh) { + return PyInt_FromLong(me->mesh->id.us); + } + else { // it's a free mesh: + return Py_BuildValue("i", 0); + } + } + + else if (strcmp(name, "faces") == 0) + return EXPP_incr_ret(me->faces); + + return Py_FindMethod(NMesh_methods, (PyObject*)self, name); +} + +static int NMesh_setattr(PyObject *self, char *name, PyObject *v) +{ + C_NMesh *me = (C_NMesh *)self; + + if (!strcmp(name, "verts") || !strcmp(name, "faces") || + !strcmp(name, "materials")) { + + if(PySequence_Check(v)) { + + if(strcmp(name, "materials") == 0) { + Py_DECREF(me->materials); + me->materials = EXPP_incr_ret(v); + } + else if (strcmp(name, "verts") == 0) { + Py_DECREF(me->verts); + me->verts = EXPP_incr_ret(v); + } + else { + Py_DECREF(me->faces); + me->faces = EXPP_incr_ret(v); + } + } + + else + return EXPP_ReturnIntError (PyExc_AttributeError, "expected a sequence"); + } + + else + return EXPP_ReturnIntError (PyExc_AttributeError, name); + + return 0; +} + +PyTypeObject NMesh_Type = +{ + PyObject_HEAD_INIT(&PyType_Type) + 0, /*ob_size*/ + "NMesh", /*tp_name*/ + sizeof(C_NMesh), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor) NMesh_dealloc, /*tp_dealloc*/ + (printfunc) 0, /*tp_print*/ + (getattrfunc) NMesh_getattr, /*tp_getattr*/ + (setattrfunc) NMesh_setattr, /*tp_setattr*/ +}; + +static C_NMFace *nmface_from_data(C_NMesh *mesh, int vidxs[4], + char mat_nr, char flag, TFace *tface, MCol *col) +{ + C_NMFace *newf = PyObject_NEW (C_NMFace, &NMFace_Type); + int i, len; + + if(vidxs[3]) len = 4; + else if(vidxs[2]) len = 3; + else len = 2; + + newf->v = PyList_New(len); + + for (i = 0; i < len; i++) + PyList_SetItem(newf->v, i, + EXPP_incr_ret(PyList_GetItem(mesh->verts, vidxs[i]))); + + if (tface) { + newf->uv = PyList_New(len); // per-face UV coordinates + + for (i = 0; i < len; i++) { + PyList_SetItem(newf->uv, i, + Py_BuildValue("(ff)", tface->uv[i][0], tface->uv[i][1])); + } + + if (tface->tpage) /* pointer to image per face: */ + newf->image = NULL;// XXX Image_Get(tface->tpage); + else + newf->image = NULL; + + newf->mode = tface->mode; /* draw mode */ + newf->flag = tface->flag; /* select flag */ + newf->transp = tface->transp; /* transparency flag */ + col = (MCol *) (tface->col); + } + else { + newf->image = NULL; + newf->uv = PyList_New(0); + } + + newf->mat_nr = mat_nr; + newf->smooth = flag & ME_SMOOTH; + + if (col) { + newf->col = PyList_New(4); + for(i = 0; i < 4; i++, col++) + PyList_SetItem(newf->col, i, + (PyObject *)newcol(col->b, col->g, col->r, col->a)); + } + else newf->col = PyList_New(0); + + return newf; +} + +static C_NMFace *nmface_from_shortdata(C_NMesh *mesh, + MFace *face, TFace *tface, MCol *col) +{ + int vidxs[4]; + vidxs[0] = face->v1; + vidxs[1] = face->v2; + vidxs[2] = face->v3; + vidxs[3] = face->v4; + + return nmface_from_data(mesh, vidxs, face->mat_nr, face->flag, tface, col); +} + +static C_NMFace *nmface_from_intdata(C_NMesh *mesh, + MFaceInt *face, TFace *tface, MCol *col) +{ + int vidxs[4]; + vidxs[0] = face->v1; + vidxs[1] = face->v2; + vidxs[2] = face->v3; + vidxs[3] = face->v4; + + return nmface_from_data(mesh, vidxs, face->mat_nr, face->flag, tface, col); +} + +static C_NMVert *nmvert_from_data(C_NMesh *me, + MVert *vert, MSticky *st, float *co, int idx) +{ + C_NMVert *mv = PyObject_NEW(C_NMVert, &NMVert_Type); + + mv->co[0] = co[0]; mv->co[1] = co[1]; mv->co[2] = co[2]; + + mv->no[0] = vert->no[0]/32767.0; + mv->no[1] = vert->no[1]/32767.0; + mv->no[2] = vert->no[2]/32767.0; + + if (st) { + mv->uvco[0] = st->co[0]; + mv->uvco[1] = st->co[1]; + mv->uvco[2] = 0.0; + + } else mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0; + + mv->index = idx; + + return mv; +} + +static int get_active_faceindex(Mesh *me) +{ + TFace *tf; + int i; + + if (me == NULL) return -1; + + tf = me->tface; + if (tf == 0) return -1; + + for (i = 0 ; i < me->totface; i++) + if (tf[i].flag & TF_ACTIVE ) return i; + + return -1; +} + +static PyObject *new_NMesh_internal(Mesh *oldmesh, + DispListMesh *dlm, float *extverts) +{ + C_NMesh *me = PyObject_NEW(C_NMesh, &NMesh_Type); + me->flags = 0; + + if (!oldmesh) { + me->name = EXPP_incr_ret(Py_None); + me->materials = PyList_New(0); + me->verts = PyList_New(0); + me->faces = PyList_New(0); + me->mesh = 0; + } + else { + MVert *mverts; + MSticky *msticky; + MFaceInt *mfaceints; + MFace *mfaces; + TFace *tfaces; + MCol *mcols; + int i, totvert, totface; + + if (dlm) { + me->name = EXPP_incr_ret(Py_None); + me->mesh = 0; + + msticky = NULL; + mfaces = NULL; + mverts = dlm->mvert; + mfaceints = dlm->mface; + tfaces = dlm->tface; + mcols = dlm->mcol; + + totvert = dlm->totvert; + totface = dlm->totface; + } + else { + me->name = PyString_FromString(oldmesh->id.name+2); + me->mesh = oldmesh; + + mfaceints = NULL; + msticky = oldmesh->msticky; + mverts = oldmesh->mvert; + mfaces = oldmesh->mface; + tfaces = oldmesh->tface; + mcols = oldmesh->mcol; + + totvert = oldmesh->totvert; + totface = oldmesh->totface; + + me->sel_face = get_active_faceindex(oldmesh); + } + + if (msticky) me->flags |= NMESH_HASVERTUV; + if (tfaces) me->flags |= NMESH_HASFACEUV; + if (mcols) me->flags |= NMESH_HASMCOL; + + me->verts = PyList_New(totvert); + + for (i = 0; i < totvert; i++) { + MVert *oldmv = &mverts[i]; + MSticky *oldst = msticky?&msticky[i]:NULL; + float *vco = extverts?&extverts[i*3]:oldmv->co; + + PyList_SetItem(me->verts, i, + (PyObject *)nmvert_from_data(me, oldmv, oldst, vco, i)); + } + + me->faces = PyList_New(totface); + for (i = 0; i < totface; i++) { + TFace *oldtf = tfaces?&tfaces[i]:NULL; + MCol *oldmc = mcols?&mcols[i*4]:NULL; + + if (mfaceints) { + MFaceInt *oldmf = &mfaceints[i]; + PyList_SetItem (me->faces, i, + (PyObject *)nmface_from_intdata(me, oldmf, oldtf, oldmc)); + } + else { + MFace *oldmf = &mfaces[i]; + PyList_SetItem (me->faces, i, + (PyObject *)nmface_from_shortdata(me, oldmf, oldtf, oldmc)); + } + } + me->materials = NULL;// XXX PyList_fromMaterialList(oldmesh->mat, oldmesh->totcol); + } + + return (PyObject *)me; +} + +PyObject *new_NMesh(Mesh *oldmesh) +{ + return new_NMesh_internal (oldmesh, NULL, NULL); +} + +static PyObject *M_NMesh_New(PyObject *self, PyObject *args) +{ + return new_NMesh(NULL); +} + +static PyObject *M_NMesh_GetRaw(PyObject *self, PyObject *args) +{ + char *name = NULL; + Mesh *oldmesh = NULL; + + if (!PyArg_ParseTuple(args, "|s", &name)) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected string argument (or nothing)"); + + if (name) { + oldmesh = (Mesh *)GetIdFromList(&(G.main->mesh), name); + + if (!oldmesh) return EXPP_incr_ret(Py_None); + } + + return new_NMesh(oldmesh); +} + +static PyObject *M_NMesh_GetRawFromObject(PyObject *self, PyObject *args) +{ + char *name; + Object *ob; + PyObject *nmesh; + + if (!PyArg_ParseTuple(args, "s", &name)) + return EXPP_ReturnPyObjError (PyExc_TypeError, + "expected string argument"); + + ob = (Object*)GetIdFromList(&(G.main->object), name); + + if (!ob) + return EXPP_ReturnPyObjError (PyExc_AttributeError, name); + else if (ob->type != OB_MESH) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "Object does not have Mesh data"); + else { + Mesh *me = (Mesh*)ob->data; + DispList *dl; + + if (mesh_uses_displist(me) && (dl = find_displist(&me->disp, DL_MESH))) + nmesh = new_NMesh_internal(me, dl->mesh, NULL); + else if ((dl= find_displist(&ob->disp, DL_VERTS))) + nmesh = new_NMesh_internal(me, NULL, dl->verts); + else + nmesh = new_NMesh(me); + } + ((C_NMesh *) nmesh)->mesh = 0; // hack: to mark that (deformed) mesh is readonly, + // so the update function will not try to write it. + return nmesh; +} + +static void mvert_from_data(MVert *mv, MSticky *st, C_NMVert *from) +{ + mv->co[0] = from->co[0]; mv->co[1] = from->co[1]; mv->co[2] = from->co[2]; + + mv->no[0] = from->no[0]*32767.0; + mv->no[1] = from->no[1]*32767.0; + mv->no[2] = from->no[2]*32767.0; + + mv->flag = 0; + mv->mat_nr = 0; + + if (st) { + st->co[0] = from->uvco[0]; + st->co[1] = from->uvco[1]; + } +} + +/*@ TODO: this function is just a added hack. Don't look at the + * RGBA/BRGA confusion, it just works, but will never work with + * a restructured Blender */ + +static void assign_perFaceColors(TFace *tf, C_NMFace *from) +{ + MCol *col; + int i; + + col = (MCol *)(tf->col); + + if (col) { + int len = PySequence_Length(from->col); + + if(len > 4) len = 4; + + for (i = 0; i < len; i++, col++) { + C_NMCol *mc = (C_NMCol *)PySequence_GetItem(from->col, i); + if(!C_NMCol_Check(mc)) { + Py_DECREF(mc); + continue; + } + + col->r = mc->b; + col->b = mc->r; + col->g = mc->g; + col->a = mc->a; + + Py_DECREF(mc); + } + } +} + +static int assignFaceUV(TFace *tf, C_NMFace *nmface) +{ + PyObject *fuv, *tmp; + int i; + + fuv = nmface->uv; + if (PySequence_Length(fuv) == 0) + return 0; + /* fuv = [(u_1, v_1), ... (u_n, v_n)] */ + for (i = 0; i < PySequence_Length(fuv); i++) { + tmp = PyList_GetItem(fuv, i); /* stolen reference ! */ + if (!PyArg_ParseTuple(tmp, "ff", &(tf->uv[i][0]), &(tf->uv[i][1]))) + return 0; + } + if (nmface->image) /* image assigned ? */ + { + tf->tpage = nmface->image; + } + else + tf->tpage = 0; + + tf->mode = nmface->mode; /* copy mode */ + tf->flag = nmface->flag; /* copy flag */ + tf->transp = nmface->transp; /* copy transp flag */ + + /* assign vertex colours */ + assign_perFaceColors(tf, nmface); + return 1; +} + +static void mface_from_data(MFace *mf, TFace *tf, MCol *col, C_NMFace *from) +{ + C_NMVert *nmv; + + int i = PyList_Size(from->v); + if(i >= 1) { + nmv = (C_NMVert *)PyList_GetItem(from->v, 0); + if (C_NMVert_Check(nmv) && nmv->index != -1) mf->v1 = nmv->index; + else mf->v1 = 0; + } + if(i >= 2) { + nmv = (C_NMVert *)PyList_GetItem(from->v, 1); + if (C_NMVert_Check(nmv) && nmv->index != -1) mf->v2 = nmv->index; + else mf->v2 = 0; + } + if(i >= 3) { + nmv = (C_NMVert *)PyList_GetItem(from->v, 2); + if (C_NMVert_Check(nmv) && nmv->index != -1) mf->v3 = nmv->index; + else mf->v3= 0; + } + if(i >= 4) { + nmv = (C_NMVert *)PyList_GetItem(from->v, 3); + if (C_NMVert_Check(nmv) && nmv->index != -1) mf->v4 = nmv->index; + else mf->v4= 0; + } + + if (tf) { + assignFaceUV(tf, from); + if (PyErr_Occurred()) + { + PyErr_Print(); + return; + } + + test_index_face(mf, tf, i); + } + else { + test_index_mface(mf, i); + } + + mf->puno = 0; + mf->mat_nr = from->mat_nr; + mf->edcode = 0; + if (from->smooth) + mf->flag = ME_SMOOTH; + else + mf->flag = 0; + + if (col) { + int len = PySequence_Length(from->col); + + if(len > 4) len = 4; + + for (i = 0; i < len; i++, col++) { + C_NMCol *mc = (C_NMCol *) PySequence_GetItem(from->col, i); + if(!C_NMCol_Check(mc)) { + Py_DECREF(mc); + continue; + } + + col->b = mc->r; + col->g = mc->g; + col->r = mc->b; + col->a = mc->a; + + Py_DECREF(mc); + } + } +} + +/* check for a valid UV sequence */ +static int check_validFaceUV(C_NMesh *nmesh) +{ + PyObject *faces; + C_NMFace *nmface; + int i, n; + + faces = nmesh->faces; + for (i = 0; i < PySequence_Length(faces); i++) { + nmface = (C_NMFace *)PyList_GetItem(faces, i); + n = PySequence_Length(nmface->uv); + if (n != PySequence_Length(nmface->v)) + { + if (n > 0) + printf("Warning: different length of vertex and UV coordinate " + "list in face!\n"); + return 0; + } + } + return 1; +} + +static int unlink_existingMeshData(Mesh *mesh) +{ + freedisplist(&mesh->disp); + unlink_mesh(mesh); + if(mesh->mvert) MEM_freeN(mesh->mvert); + if(mesh->mface) MEM_freeN(mesh->mface); + if(mesh->mcol) MEM_freeN(mesh->mcol); + if(mesh->msticky) MEM_freeN(mesh->msticky); + if(mesh->mat) MEM_freeN(mesh->mat); + if(mesh->tface) MEM_freeN(mesh->tface); + return 1; +} + +Material **nmesh_updateMaterials(C_NMesh *nmesh) +{ + Material **matlist; + Mesh *mesh = nmesh->mesh; + int len = PySequence_Length(nmesh->materials); + + if (!mesh) { + printf("FATAL INTERNAL ERROR: illegal call to updateMaterials()\n"); + return 0; + } + + if (len > 0) { + matlist = newMaterialList_fromPyList(nmesh->materials); + if (mesh->mat) + MEM_freeN(mesh->mat); + mesh->mat = matlist; + } else { + matlist = 0; + } + mesh->totcol = len; + return matlist; +} + +PyObject *NMesh_assignMaterials_toObject(C_NMesh *nmesh, Object *ob) +{ +// DataBlock *block; +// Material *ma; +// int i; +// short old_matmask; + + //old_matmask = ob->colbits; // HACK: save previous colbits + //ob->colbits = 0; // make assign_material work on mesh linked material + +// for (i = 0; i < PySequence_Length(nmesh->materials); i++) { +// block= (DataBlock *) PySequence_GetItem(nmesh->materials, i); + + // if (DataBlock_isType(block, ID_MA)) { + // ma = (Material *) block->data; + // assign_material(ob, ma, i+1); // XXX don't use this function anymore +// } else { + // PyErr_SetString(PyExc_TypeError, + // "Material type in attribute list 'materials' expected!"); + //Py_DECREF(block); + // return NULL; +// } + + //Py_DECREF(block); + //} + //ob->colbits = old_matmask; // HACK + +// ob->actcol = 1; + return EXPP_incr_ret(Py_None); +} + +static int convert_NMeshToMesh(Mesh *mesh, C_NMesh *nmesh) +{ + MFace *newmf; + TFace *newtf; + MVert *newmv; + MSticky *newst; + MCol *newmc; + + int i, j; + + mesh->mvert = NULL; + mesh->mface = NULL; + mesh->mcol = NULL; + mesh->msticky = NULL; + mesh->tface = NULL; + mesh->mat = NULL; + + // material assignment moved to PutRaw + mesh->totvert = PySequence_Length(nmesh->verts); + if (mesh->totvert) { + if (nmesh->flags&NMESH_HASVERTUV) + mesh->msticky = MEM_callocN(sizeof(MSticky)*mesh->totvert, "msticky"); + + mesh->mvert = MEM_callocN(sizeof(MVert)*mesh->totvert, "mverts"); + } + + if (mesh->totvert) + mesh->totface = PySequence_Length(nmesh->faces); + else + mesh->totface = 0; + + if (mesh->totface) { +/*@ only create vertcol array if mesh has no texture faces */ + +/*@ TODO: get rid of double storage of vertex colours. In a mesh, + * vertex colors can be stored the following ways: + * - per (TFace*)->col + * - per (Mesh*)->mcol + * This is stupid, but will reside for the time being -- at least until + * a redesign of the internal Mesh structure */ + + if (!(nmesh->flags & NMESH_HASFACEUV) && (nmesh->flags&NMESH_HASMCOL)) + mesh->mcol = MEM_callocN(4*sizeof(MCol)*mesh->totface, "mcol"); + + mesh->mface = MEM_callocN(sizeof(MFace)*mesh->totface, "mfaces"); + } + + /*@ This stuff here is to tag all the vertices referenced + * by faces, then untag the vertices which are actually + * in the vert list. Any vertices untagged will be ignored + * by the mface_from_data function. It comes from my + * screwed up decision to not make faces only store the + * index. - Zr + */ + for (i = 0; i < mesh->totface; i++) { + C_NMFace *mf= (C_NMFace *) PySequence_GetItem(nmesh->faces, i); + + j= PySequence_Length(mf->v); + while (j--) { + C_NMVert *mv = (C_NMVert *)PySequence_GetItem(mf->v, j); + if (C_NMVert_Check(mv)) mv->index= -1; + Py_DECREF(mv); + } + + Py_DECREF(mf); + } + + for (i = 0; i < mesh->totvert; i++) { + C_NMVert *mv = (C_NMVert *)PySequence_GetItem(nmesh->verts, i); + mv->index = i; + Py_DECREF(mv); + } + + newmv = mesh->mvert; + newst = mesh->msticky; + for (i = 0; i < mesh->totvert; i++) { + PyObject *mv = PySequence_GetItem (nmesh->verts, i); + mvert_from_data(newmv, newst, (C_NMVert *)mv); + Py_DECREF(mv); + + newmv++; + if (newst) newst++; + } + +/* assign per face texture UVs */ + + /* check face UV flag, then check whether there was one + * UV coordinate assigned, if yes, make tfaces */ + if ((nmesh->flags & NMESH_HASFACEUV) || (check_validFaceUV(nmesh))) { + make_tfaces(mesh); /* initialize TFaces */ + + newmc = mesh->mcol; + newmf = mesh->mface; + newtf = mesh->tface; + for (i = 0; i<mesh->totface; i++) { + PyObject *mf = PySequence_GetItem(nmesh->faces, i); + mface_from_data(newmf, newtf, newmc, (C_NMFace *) mf); + Py_DECREF(mf); + + newtf++; + newmf++; + if (newmc) newmc++; + } + + nmesh->flags |= NMESH_HASFACEUV; + } + else { + newmc = mesh->mcol; + newmf = mesh->mface; + + for (i = 0; i < mesh->totface; i++) { + PyObject *mf = PySequence_GetItem(nmesh->faces, i); + mface_from_data(newmf, 0, newmc, (C_NMFace *) mf); + Py_DECREF(mf); + + newmf++; + if (newmc) newmc++; + } + } + return 1; +} + +static PyObject *M_NMesh_PutRaw(PyObject *self, PyObject *args) +{ + char *name = NULL; + Mesh *mesh = NULL; + Object *ob = NULL; + C_NMesh *nmesh; + int recalc_normals = 1; + + if (!PyArg_ParseTuple(args, "O!|si", + &NMesh_Type, &nmesh, &name, &recalc_normals)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "expected an NMesh object and optionally also a string and an int"); + + if (!PySequence_Check(nmesh->verts)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "nmesh vertices are not a sequence"); + if (!PySequence_Check(nmesh->faces)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "nmesh faces are not a sequence"); + if (!PySequence_Check(nmesh->materials)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "nmesh materials are not a sequence"); + + if (!EXPP_check_sequence_consistency(nmesh->verts, &NMVert_Type)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "nmesh vertices must be NMVerts"); + if (!EXPP_check_sequence_consistency(nmesh->faces, &NMFace_Type)) + return EXPP_ReturnPyObjError (PyExc_AttributeError, + "nmesh faces must be NMFaces"); + + if (name) + mesh = (Mesh *)GetIdFromList(&(G.main->mesh), name); + + if(!mesh || mesh->id.us == 0) { + ob = add_object(OB_MESH); + if (!ob) { + PyErr_SetString(PyExc_RuntimeError, "Fatal: could not create mesh object"); + return 0; + } + if (mesh) + set_mesh(ob, mesh); + else + mesh = (Mesh *)ob->data; + } + if (name) new_id(&(G.main->mesh), &mesh->id, name); + + unlink_existingMeshData(mesh); + convert_NMeshToMesh(mesh, nmesh); + nmesh->mesh = mesh; + + if(recalc_normals) + vertexnormals_mesh(mesh, 0); + + mesh_update(mesh); + + if (!during_script()) + allqueue(REDRAWVIEW3D, 0); + + // OK...this requires some explanation: + // Materials can be assigned two ways: + // a) to the object data (in this case, the mesh) + // b) to the Object + // + // Case a) is wanted, if Mesh data should be shared among objects, + // as well as its materials (up to 16) + // Case b) is wanted, when Mesh data should be shared, but not the + // materials. For example, you want several checker boards sharing their + // mesh data, but having different colors. So you would assign material + // index 0 to all even, index 1 to all odd faces and bind the materials + // to the Object instead (MaterialButtons: [OB] button "link materials to object") + // + // This feature implies that pointers to materials can be stored in + // an object or a mesh. The number of total materials MUST be + // synchronized (ob->totcol <-> mesh->totcol). We avoid the dangerous + // direct access by calling blenderkernel/material.c:assign_material(). + + // The flags setting the material binding is found in ob->colbits, where + // each bit indicates the binding PER MATERIAL + + if (ob) { // we created a new object + NMesh_assignMaterials_toObject(nmesh, ob); + //return DataBlock_fromData(ob); /* XXX fix this */ + return EXPP_incr_ret (Py_None); + } + else + return EXPP_incr_ret (Py_None); +} + +#undef MethodDef +#define MethodDef(func) {#func, M_NMesh_##func, METH_VARARGS, M_NMesh_##func##_doc} + +static struct PyMethodDef M_NMesh_methods[] = { +// These should be: Mesh.Col, Mesh.Vert, Mesh.Face in fure +// -- for ownership reasons + MethodDef(Col), + MethodDef(Vert), + MethodDef(Face), + MethodDef(New), + MethodDef(GetRaw), + MethodDef(GetRawFromObject), + MethodDef(PutRaw), + {NULL, NULL} +}; + +#undef EXPP_ADDCONST +#define EXPP_ADDCONST(dict, name) \ + constant_insert(dict, #name, PyInt_FromLong(TF_##name)) + +/*@ set constants for face drawing mode -- see drawmesh.c */ + +static void init_NMeshConst(C_constant *d) +{ + constant_insert(d, "BILLBOARD", PyInt_FromLong(TF_BILLBOARD2)); + constant_insert(d, "ALL", PyInt_FromLong(0xffff)); + constant_insert(d, "HALO", PyInt_FromLong(TF_BILLBOARD)); + EXPP_ADDCONST(d, DYNAMIC); + EXPP_ADDCONST(d, INVISIBLE); + EXPP_ADDCONST(d, LIGHT); + EXPP_ADDCONST(d, OBCOL); + EXPP_ADDCONST(d, SHADOW); + EXPP_ADDCONST(d, SHAREDVERT); + EXPP_ADDCONST(d, SHAREDCOL); + EXPP_ADDCONST(d, TEX); + EXPP_ADDCONST(d, TILES); + EXPP_ADDCONST(d, TWOSIDE); +/* transparent modes */ + EXPP_ADDCONST(d, SOLID); + EXPP_ADDCONST(d, ADD); + EXPP_ADDCONST(d, ALPHA); + EXPP_ADDCONST(d, SUB); +/* TFACE flags */ + EXPP_ADDCONST(d, SELECT); + EXPP_ADDCONST(d, HIDE); + EXPP_ADDCONST(d, ACTIVE); +} + +PyObject *M_NMesh_Init (void) +{ + PyObject *mod = Py_InitModule("Blender.NMesh", M_NMesh_methods); + PyObject *dict = PyModule_GetDict(mod); + PyObject *d = M_constant_New(); + + PyDict_SetItemString(dict, "Const" , d); + init_NMeshConst((C_constant *)d); + + g_nmeshmodule = mod; + return mod; +} + +/* Unimplemented stuff: */ + +Material **newMaterialList_fromPyList (PyObject *list) { return NULL; } |