/** * $Id:$ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * The contents of this file may be used under the terms of either the GNU * General Public License Version 2 or later (the "GPL", see * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or * later (the "BL", see http://www.blender.org/BL/ ) which has to be * bought from the Blender Foundation to become active, in which case the * above mentioned GPL option does not apply. * * The Original Code is Copyright (C) 2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ /* python.c MIXED MODEL * * june 99 * Version: $Id: py_nmesh.c,v 1.6 2000/08/09 00:32:08 jan Exp $ */ #include "blender.h" #include "py_blender.h" #include "screen.h" PyTypeObject NMesh_Type; PyTypeObject NMFace_Type; PyTypeObject NMVert_Type; PyTypeObject NMCol_Type; #define NMesh_Check(v) ((v)->ob_type == &NMesh_Type) #define NMFace_Check(v) ((v)->ob_type == &NMFace_Type) #define NMVert_Check(v) ((v)->ob_type == &NMVert_Type) #define NMCol_Check(v) ((v)->ob_type == &NMCol_Type) /*****************************/ /* Mesh Color Object */ /*****************************/ typedef struct _NMCol { PyObject_VAR_HEAD unsigned char r, g, b, a; } NMCol; static void NMCol_dealloc(PyObject *self) { PyMem_DEL(self); } static NMCol *newcol (char r, char g, char b, char a) { NMCol *mc= (NMCol *) PyObject_NEW(NMCol, &NMCol_Type); mc->r= r; mc->g= g; mc->b= b; mc->a= a; return mc; } static char Method_Col_doc[]= "([r, g, b, a]) - Get a new mesh color\n\ \n\ [r=255, g=255, b=255, a=255] Specify the color components"; static PyObject *Method_Col(PyObject *self, PyObject *args) { NMCol *mc; int r=255, g=255, b=255, a=255; Py_Try(PyArg_ParseTuple(args, "|iiii", &r, &g, &b, &a)); return (PyObject *) newcol(r, g, b, a); } static PyObject *NMCol_getattr(PyObject *self, char *name) { NMCol *mc= (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); PyErr_SetString(PyExc_AttributeError, name); return NULL; } static int NMCol_setattr(PyObject *self, char *name, PyObject *v) { NMCol *mc= (NMCol *) self; int ival; if(!PyArg_Parse(v, "i", &ival)) return -1; CLAMP(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; } static int NMCol_print (PyObject *self, FILE *fp, int flags) { NMCol *mc= (NMCol *) self; fprintf (fp, "[NMCol - <%d, %d, %d, %d>]", mc->r, mc->g, mc->b, mc->a); return 0; } PyTypeObject NMCol_Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "NMCol", /*tp_name*/ sizeof(NMCol), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor) NMCol_dealloc, /*tp_dealloc*/ (printfunc) NMCol_print, /*tp_print*/ (getattrfunc) NMCol_getattr, /*tp_getattr*/ (setattrfunc) NMCol_setattr, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; /*****************************/ /* NMesh Python Object */ /*****************************/ typedef struct _NMFace { PyObject_VAR_HEAD PyObject *v; PyObject *col; char mat_nr, smooth; } NMFace; static void NMFace_dealloc(PyObject *self) { NMFace *mf= (NMFace *) self; Py_DECREF(mf->v); Py_DECREF(mf->col); PyMem_DEL(self); } static NMFace *newface(void) { NMFace *mf= PyObject_NEW(NMFace, &NMFace_Type); mf->v= PyList_New(0); mf->col= PyList_New(0); mf->smooth= 0; mf->mat_nr= 0; return mf; } static char Method_Face_doc[]= "() - Get a new face"; static PyObject *Method_Face(PyObject *self, PyObject *args) { Py_Try(PyArg_ParseTuple(args, "")); return (PyObject *) newface(); } static PyObject *NMFace_getattr(PyObject *self, char *name) { PyObject *list; NMFace *mf= (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) return Py_BuildValue("i", mf->mat_nr); else if (strcmp(name, "smooth")==0) return Py_BuildValue("i", mf->smooth); PyErr_SetString(PyExc_AttributeError, name); return NULL; } static int NMFace_setattr(PyObject *self, char *name, PyObject *v) { NMFace *mf= (NMFace *) self; int ival; if (STREQ(name, "v")) { if(PySequence_Check(v)) { Py_DECREF(mf->v); mf->v= py_incr_ret(v); return 0; } } else if (STREQ(name, "col")) { if(PySequence_Check(v)) { Py_DECREF(mf->col); mf->col= py_incr_ret(v); return 0; } } else if (STREQ(name, "mat")) { PyArg_Parse(v, "i", &ival); mf->mat_nr= ival; return 0; } else if (STREQ(name, "smooth")) { PyArg_Parse(v, "i", &ival); mf->smooth= ival?1:0; return 0; } PyErr_SetString(PyExc_AttributeError, name); return -1; } static int NMFace_print (PyObject *self, FILE *fp, int flags) { NMFace *mf= (NMFace *) self; fprintf (fp, "[NMFace]"); return 0; } PyTypeObject NMFace_Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "NMFace", /*tp_name*/ sizeof(NMFace), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor) NMFace_dealloc, /*tp_dealloc*/ (printfunc) NMFace_print, /*tp_print*/ (getattrfunc) NMFace_getattr, /*tp_getattr*/ (setattrfunc) NMFace_setattr,/*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; typedef struct _NMVert { PyObject_VAR_HEAD float co[3]; float no[3]; float uvco[3]; int index; } NMVert; static void NMVert_dealloc(PyObject *self) { PyMem_DEL(self); } static NMVert *newvert(float *co) { NMVert *mv= PyObject_NEW(NMVert, &NMVert_Type); VECCOPY(mv->co, co); 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 char Method_Vert_doc[]= "([x, y, z]) - Get a new vertice\n\ \n\ [x, y, z] Specify new coordinates"; static PyObject *Method_Vert(PyObject *self, PyObject *args) { float co[3]= {0.0, 0.0, 0.0}; Py_Try(PyArg_ParseTuple(args, "|fff", &co[0], &co[1], &co[2])); return (PyObject *) newvert(co); } static PyObject *NMVert_getattr(PyObject *self, char *name) { PyObject *list; NMVert *mv= (NMVert *) self; if (STREQ(name, "co")) return newVectorObject(mv->co, 3); else if (STREQ(name, "no")) return newVectorObject(mv->no, 3); else if (STREQ(name, "uvco")) return newVectorObject(mv->uvco, 3); else if (STREQ(name, "index")) return PyInt_FromLong(mv->index); PyErr_SetString(PyExc_AttributeError, name); return NULL; } static int NMVert_setattr(PyObject *self, char *name, PyObject *v) { NMVert *mv= (NMVert *) self; int i; if (STREQ(name,"index")) { PyArg_Parse(v, "i", &i); mv->index= i; return 0; } PyErr_SetString(PyExc_AttributeError, name); return -1; } static int NMVert_print (PyObject *self, FILE *fp, int flags) { NMVert *mv= (NMVert *) self; fprintf (fp, "[NMVert]"); return 0; } PyTypeObject NMVert_Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "NMVert", /*tp_name*/ sizeof(NMVert), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor) NMVert_dealloc, /*tp_dealloc*/ (printfunc) NMVert_print, /*tp_print*/ (getattrfunc) NMVert_getattr, /*tp_getattr*/ (setattrfunc) NMVert_setattr,/*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; typedef struct _NMesh { PyObject_VAR_HEAD PyObject *name; PyObject *mats; PyObject *verts; PyObject *faces; char flags; #define NMESH_HASMCOL 1<<0 #define NMESH_HASUVCO 1<<1 } NMesh; static void NMesh_dealloc(PyObject *self) { NMesh *me= (NMesh *) self; Py_DECREF(me->name); Py_DECREF(me->verts); Py_DECREF(me->faces); PyMem_DEL(self); } static PyObject *NMesh_getattr(PyObject *self, char *name) { NMesh *me= (NMesh *) self; if (STREQ(name, "name")) return py_incr_ret(me->name); else if (STREQ(name, "block_type")) return PyString_FromString("NMesh"); else if (STREQ(name, "mats")) return py_incr_ret(me->mats); else if (STREQ(name, "verts")) return py_incr_ret(me->verts); else if (STREQ(name, "faces")) return py_incr_ret(me->faces); else if (STREQ(name, "has_col")) { if (me->flags & NMESH_HASMCOL) return py_incr_ret(Py_True); else return py_incr_ret(Py_False); } else if (STREQ(name, "has_uvco")) { if (me->flags & NMESH_HASUVCO) return py_incr_ret(Py_True); else return py_incr_ret(Py_False); } PyErr_SetString(PyExc_AttributeError, name); return NULL; } static int NMesh_setattr(PyObject *self, char *name, PyObject *v) { NMesh *me= (NMesh *) self; PyObject *ob; if (STREQ2(name, "has_col", "has_uvco")) { int flag, ival; if(STREQ(name, "has_col")) flag= NMESH_HASMCOL; else flag= NMESH_HASUVCO; PyArg_Parse(v, "i", &ival); if(ival) me->flags |= flag; else me->flags &= ~flag; } else if (STREQ3(name, "verts", "faces", "mats")) { if(PySequence_Check(v)) { if(STREQ(name, "mats")) { Py_DECREF(me->mats); me->mats= py_incr_ret(v); } else if (STREQ(name, "verts")) { Py_DECREF(me->verts); me->verts= py_incr_ret(v); } else { Py_DECREF(me->faces); me->faces= py_incr_ret(v); } } else { PyErr_SetString(PyExc_AttributeError, "expected a sequence"); return -1; } } else { PyErr_SetString(PyExc_AttributeError, name); return -1; } return 0; } static int NMesh_print (PyObject *self, FILE *fp, int flags) { fprintf (fp, "[NMesh]"); return 0; } PyTypeObject NMesh_Type = { PyObject_HEAD_INIT(NULL) 0, /*ob_size*/ "NMesh", /*tp_name*/ sizeof(NMesh), /*tp_basicsize*/ 0, /*tp_itemsize*/ /* methods */ (destructor) NMesh_dealloc, /*tp_dealloc*/ (printfunc) NMesh_print, /*tp_print*/ (getattrfunc) NMesh_getattr, /*tp_getattr*/ (setattrfunc) NMesh_setattr, /*tp_setattr*/ 0, /*tp_compare*/ 0, /*tp_repr*/ 0, /*tp_as_number*/ 0, /*tp_as_sequence*/ 0, /*tp_as_mapping*/ 0, /*tp_hash*/ }; static NMFace *nmface_from_data(NMesh *mesh, MFace *face, MCol *col, int idx) { NMFace *mf= PyObject_NEW(NMFace, &NMFace_Type); int len; if(face->v4) len= 4; else if(face->v3) len= 3; else len= 2; mf->v= PyList_New(len); if (len>0) { PyList_SetItem(mf->v, 0, py_incr_ret(PyList_GetItem(mesh->verts, face->v1))); if (len>1) { PyList_SetItem(mf->v, 1, py_incr_ret(PyList_GetItem(mesh->verts, face->v2))); if (len>2) { PyList_SetItem(mf->v, 2, py_incr_ret(PyList_GetItem(mesh->verts, face->v3))); if (len>3) { PyList_SetItem(mf->v, 3, py_incr_ret(PyList_GetItem(mesh->verts, face->v4))); } } } } mf->mat_nr= face->mat_nr; mf->smooth= face->flag&ME_SMOOTH; if (col) { int i; mf->col= PyList_New(4); for(i=0; i<4; i++, col++) PyList_SetItem(mf->col, i, (PyObject *) newcol(col->b, col->g, col->r, col->a)); } else mf->col= PyList_New(0); return mf; } static NMVert *nmvert_from_data(NMesh *me, MVert *vert, MSticky *st, int idx) { NMVert *mv= PyObject_NEW(NMVert, &NMVert_Type); VECCOPY (mv->co, vert->co); 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; } PyObject *newNMeshObject(Mesh *oldmesh) { NMesh *me; NMVert *mv; NMCol *mc; MFace *oldmf; MVert *oldmv; MSticky *oldst; MCol *oldmc; int i; me= PyObject_NEW(NMesh, &NMesh_Type); me->flags= 0; if (!oldmesh) { me->name= py_incr_ret(Py_None); me->mats= PyList_New(0); me->verts= PyList_New(0); me->faces= PyList_New(0); } else { me->name= PyString_FromString(oldmesh->id.name+2); oldmv= oldmesh->mvert; oldst= oldmesh->msticky; if (oldst) me->flags |= NMESH_HASUVCO; me->verts= PyList_New(oldmesh->totvert); for (i=0; itotvert; i++) { PyList_SetItem(me->verts, i, (PyObject *) nmvert_from_data(me, oldmv, oldst, i)); oldmv++; if (oldst) oldst++; } oldmf= oldmesh->mface; oldmc= oldmesh->mcol; if (oldmc) me->flags |= NMESH_HASMCOL; me->faces= PyList_New(oldmesh->totface); for (i=0; itotface; i++) { PyList_SetItem(me->faces, i, (PyObject *) nmface_from_data(me, oldmf, oldmc, i)); oldmf++; if (oldmc) oldmc+= 4; } me->mats= PyList_New(oldmesh->totcol); for (i=0; itotcol; i++) { Material *mat= oldmesh->mat[i]; PyObject *ob; if (mat) ob= PyString_FromString(mat->id.name+2); else ob= py_incr_ret(Py_None); PyList_SetItem(me->mats, i, ob); } } return (PyObject *) me; } static char Method_GetRaw_doc[]= "([name]) - Get a raw mesh from Blender\n\ \n\ [name] Name of the mesh to be returned\n\ \n\ If name is not specified a new empty mesh is\n\ returned, otherwise Blender returns an existing\n\ mesh."; static PyObject *Method_GetRaw(PyObject *self, PyObject *args) { char *name=NULL; Mesh *oldmesh=NULL; Py_Try(PyArg_ParseTuple(args, "|s", &name)); if(name) { oldmesh= (Mesh *) find_datablock_from_list((ID *) G.main->mesh.first, name); if (!oldmesh) return py_incr_ret(Py_None); } return newNMeshObject(oldmesh); } static void mvert_from_data(MVert *mv, MSticky *st, NMVert *from) { VECCOPY (mv->co, from->co); 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]; } } static void mface_from_data(MFace *mf, MCol *col, NMFace *from) { NMVert *nmv; int i= PyList_Size(from->v); if(i>=1) { nmv= (NMVert *) PyList_GetItem(from->v, 0); if (NMVert_Check(nmv) && nmv->index!=-1) mf->v1= nmv->index; else mf->v1= 0; } if(i>=2) { nmv= (NMVert *) PyList_GetItem(from->v, 1); if (NMVert_Check(nmv) && nmv->index!=-1) mf->v2= nmv->index; else mf->v2= 0; } if(i>=3) { nmv= (NMVert *) PyList_GetItem(from->v, 2); if (NMVert_Check(nmv) && nmv->index!=-1) mf->v3= nmv->index; else mf->v3= 0; } if(i>=4) { nmv= (NMVert *) PyList_GetItem(from->v, 3); if (NMVert_Check(nmv) && nmv->index!=-1) mf->v4= nmv->index; else mf->v4= 0; } 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; icol, i); if(!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); } } } static char Method_PutRaw_doc[]= "(mesh, [name, renormal]) - Return a raw mesh to Blender\n\ \n\ (mesh) The NMesh object to store\n\ [name] The mesh to replace\n\ [renormal=1] Flag to control vertex normal recalculation\n\ \n\ If the name of a mesh to replace is not given a new\n\ object is created and returned."; static PyObject *Method_PutRaw(PyObject *self, PyObject *args) { char *name= NULL; Mesh *nmesh= NULL; Object *ob= NULL; NMesh *me; NMCol *mc; MFace *newmf; MVert *newmv; MSticky *newst; MCol *newmc; int i, j, len; int recalc_normals= 1; Py_Try(PyArg_ParseTuple(args, "O!|si", &NMesh_Type, &me, &name, &recalc_normals)); if (!PySequence_Check(me->verts)) return py_err_ret_ob(PyExc_AttributeError, "nmesh vertices are not a sequence"); if (!PySequence_Check(me->faces)) return py_err_ret_ob(PyExc_AttributeError, "nmesh faces are not a sequence"); if (!PySequence_Check(me->mats)) return py_err_ret_ob(PyExc_AttributeError, "nmesh materials are not a sequence"); if (!py_check_sequence_consistency(me->verts, &NMVert_Type)) return py_err_ret_ob(PyExc_AttributeError, "nmesh vertices must be NMVerts"); if (!py_check_sequence_consistency(me->faces, &NMFace_Type)) return py_err_ret_ob(PyExc_AttributeError, "nmesh faces must be NMFaces"); if (name) nmesh= (Mesh *) find_datablock_from_list((ID *) G.main->mesh.first, name); if(!nmesh || nmesh->id.us==0) { ob= add_object(OB_MESH); if (nmesh) set_mesh(ob, nmesh); else nmesh= (Mesh *) ob->data; ob->loc[0]= ob->loc[1]= ob->loc[2]= 0.0; ob->rot[0]= ob->rot[1]= ob->rot[2]= 0.0; ob->size[0]= ob->size[1]= ob->size[2]= 1.0; } if(name) new_id(&G.main->mesh, &nmesh->id, name); freedisplist(&nmesh->disp); unlink_mesh(nmesh); if(nmesh->mvert) freeN(nmesh->mvert); if(nmesh->mface) freeN(nmesh->mface); if(nmesh->mcol) freeN(nmesh->mcol); if(nmesh->msticky) freeN(nmesh->msticky); if(nmesh->mat) freeN(nmesh->mat); nmesh->mvert= NULL; nmesh->mface= NULL; nmesh->mcol= NULL; nmesh->msticky= NULL; nmesh->mat= NULL; nmesh->totcol= PySequence_Length(me->mats); if (nmesh->totcol) { nmesh->mat= callocN(sizeof(Material*)*nmesh->totcol, "mesh mats"); for (i= 0; itotcol; i++) { PyObject *ob= PySequence_GetItem(me->mats, i); if (PyString_Check(ob)) { Material *ma= (Material *) find_datablock_from_list((ID *) G.main->mat.first, PyString_AsString(ob)); if (ma) ma->id.us++; nmesh->mat[i]= ma; } Py_DECREF(ob); } } nmesh->totvert= PySequence_Length(me->verts); if (nmesh->totvert) { if (me->flags&NMESH_HASUVCO) nmesh->msticky= callocN(sizeof(MSticky)*nmesh->totvert, "msticky"); nmesh->mvert= callocN(sizeof(MVert)*nmesh->totvert, "mverts"); } if (nmesh->totvert) nmesh->totface= PySequence_Length(me->faces); else nmesh->totface= 0; if (nmesh->totface) { if (me->flags&NMESH_HASMCOL) nmesh->mcol= callocN(4*sizeof(MCol)*nmesh->totface, "mcol"); nmesh->mface= callocN(sizeof(MFace)*nmesh->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; itotface; i++) { NMFace *mf= (NMFace *) PySequence_GetItem(me->faces, i); j= PySequence_Length(mf->v); while (j--) { NMVert *mv= (NMVert *) PySequence_GetItem(mf->v, j); if (NMVert_Check(mv)) mv->index= -1; Py_DECREF(mv); } Py_DECREF(mf); } for (i=0; itotvert; i++) { NMVert *mv= (NMVert *) PySequence_GetItem(me->verts, i); mv->index= i; Py_DECREF(mv); } newmv= nmesh->mvert; newst= nmesh->msticky; for (i=0; itotvert; i++) { PyObject *mv= PySequence_GetItem(me->verts, i); mvert_from_data(newmv, newst, (NMVert *)mv); Py_DECREF(mv); newmv++; if (newst) newst++; } newmc= nmesh->mcol; newmf= nmesh->mface; for (i=0; itotface; i++) { PyObject *mf= PySequence_GetItem(me->faces, i); mface_from_data(newmf, newmc, (NMFace *) mf); Py_DECREF(mf); newmf++; if (newmc) newmc++; } if(recalc_normals) vertexnormals_mesh(nmesh, 0); edge_drawflags_mesh(nmesh); tex_space_mesh(nmesh); if (!during_script()) allqueue(REDRAWVIEW3D, 0); if (ob) return add_pyblock(ob); else return py_incr_ret(Py_None); } static struct PyMethodDef NMeshM_methods[] = { MethodDef(Col), MethodDef(Vert), MethodDef(Face), MethodDef(GetRaw), MethodDef(PutRaw), {NULL, NULL} }; PyObject *init_py_nmesh(void) { NMesh_Type.ob_type= &PyType_Type; NMVert_Type.ob_type= &PyType_Type; NMFace_Type.ob_type= &PyType_Type; NMCol_Type.ob_type= &PyType_Type; return Py_InitModule("Blender.NMesh", NMeshM_methods); }