This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/python/api2_2x/NMesh.c

1582 lines
40 KiB
C
Raw Normal View History

/*
*
* ***** 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); /* XXX PyObject_Del ?*/
}
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; }