Initial revision
[blender.git] / source / blender / bpython / intern / opy_nmesh.c
1 /*  python.c      MIXED MODEL
2  * 
3  *  june 99
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include "Python.h"
36 #include "BPY_macros.h"
37 #include "b_interface.h"
38 #include "BPY_tools.h"
39 #include "BPY_main.h"
40
41 #include "opy_datablock.h"
42 #include "opy_nmesh.h"
43
44 #include "MEM_guardedalloc.h"
45 #include "BIF_editmesh.h" /* vertexnormals_mesh() */
46 #include "BDR_editface.h" /* make_tfaces */
47
48 #include "BKE_mesh.h"
49 #include "BKE_main.h"
50 #include "BKE_global.h"
51 #include "BKE_library.h"
52 #include "BKE_displist.h"
53 #include "BKE_screen.h"
54 #include "BKE_object.h"
55 #include "BPY_objtypes.h"
56 #include "BLI_blenlib.h"
57 #include "BIF_space.h"
58
59 #include "opy_vector.h"
60
61 #include "b_interface.h"
62 /* PROTOS */
63
64 static int convert_NMeshToMesh(Mesh *mesh, NMesh *nmesh);
65 static int unlink_existingMeshdata(Mesh *mesh);
66 void initNMesh(void);
67 PyObject *init_py_nmesh(void);
68 int BPY_check_sequence_consistency(PyObject *seq, PyTypeObject *against);
69
70 /* TYPE OBJECTS */
71
72 PyTypeObject NMesh_Type;
73 PyTypeObject NMFace_Type;
74 PyTypeObject NMVert_Type;
75 PyTypeObject NMCol_Type;
76
77 /* DEFINES */
78
79
80 #define COL_R (b)
81 #define COL_G (g)
82 #define COL_B (r)
83 #define COL_A (a)
84
85 #define COLOR_CONVERT(col,comp) (col##->COL_##)
86
87 /* GLOBALS */
88
89 static PyObject *g_nmeshmodule = NULL;
90
91 /*****************************/
92 /*          Mesh Color Object    */
93 /*****************************/
94
95 static void NMCol_dealloc(PyObject *self) {
96         PyMem_DEL(self);
97 }
98
99 static NMCol *newcol (char r, char g, char b, char a) {
100         NMCol *mc= (NMCol *) PyObject_NEW(NMCol, &NMCol_Type);
101         
102         mc->r= r;
103         mc->g= g;
104         mc->b= b;
105         mc->a= a;
106
107         return mc;      
108 }
109
110 static char NMeshmodule_Col_doc[]=
111 "([r, g, b, a]) - Get a new mesh color\n\
112 \n\
113 [r=255, g=255, b=255, a=255] Specify the color components";
114
115 static PyObject *NMeshmodule_Col(PyObject *self, PyObject *args) {
116         int r=255, g=255, b=255, a=255;
117         
118 /*
119 if(PyArg_ParseTuple(args, "fff|f", &fr, &fg, &fb, &fa))
120                 return (PyObject *) newcol(255.0 * fr, 255.0 * fg, 255.0 * fb, 255.0 * fa);
121                 */
122         if(PyArg_ParseTuple(args, "|iiii", &r, &g, &b, &a))
123                 return (PyObject *) newcol(r, g, b, a);
124         return NULL;            
125 }
126
127 static PyObject *NMCol_getattr(PyObject *self, char *name) {
128         NMCol *mc= (NMCol *) self;
129                 
130         if (strcmp(name, "r")==0) return Py_BuildValue("i", mc->r);
131         else if (strcmp(name, "g")==0) return Py_BuildValue("i", mc->g);
132         else if (strcmp(name, "b")==0) return Py_BuildValue("i", mc->b);
133         else if (strcmp(name, "a")==0) return Py_BuildValue("i", mc->a);
134
135         PyErr_SetString(PyExc_AttributeError, name);
136         return NULL;
137 }
138
139 static int NMCol_setattr(PyObject *self, char *name, PyObject *v) {
140         NMCol *mc= (NMCol *) self;
141         int ival;
142         
143         if(!PyArg_Parse(v, "i", &ival)) return -1;
144         
145         CLAMP(ival, 0, 255);
146         
147         if (strcmp(name, "r")==0) mc->r= ival;
148         else if (strcmp(name, "g")==0) mc->g= ival;
149         else if (strcmp(name, "b")==0) mc->b= ival;
150         else if (strcmp(name, "a")==0) mc->a= ival;
151         else return -1;
152         
153         return 0;
154 }
155
156 PyObject *NMCol_repr(NMCol *self) 
157 {
158         static char s[256];
159         sprintf (s, "[NMCol - <%d, %d, %d, %d>]", self->r, self->g, self->b, self->a);
160         return Py_BuildValue("s", s);
161 }
162
163 PyTypeObject NMCol_Type = {
164         PyObject_HEAD_INIT(NULL)
165         0,                                                              /*ob_size*/
166         "NMCol",                                                /*tp_name*/
167         sizeof(NMCol),                                  /*tp_basicsize*/
168         0,                                                              /*tp_itemsize*/
169         /* methods */
170         (destructor) NMCol_dealloc,             /*tp_dealloc*/
171         (printfunc) 0,          /*tp_print*/
172         (getattrfunc) NMCol_getattr,    /*tp_getattr*/
173         (setattrfunc) NMCol_setattr,    /*tp_setattr*/
174         0,                                                              /*tp_compare*/
175         (reprfunc) NMCol_repr,                                                          /*tp_repr*/
176         0,                                                              /*tp_as_number*/
177         0,                                                              /*tp_as_sequence*/
178         0,                                                              /*tp_as_mapping*/
179         0,                                                              /*tp_hash*/
180         0,                                                              /*tp_as_number*/
181         0,                                                              /*tp_as_sequence*/
182         0,                                                              /*tp_as_mapping*/
183         0,                                                              /*tp_hash*/
184 };
185
186
187 /*****************************/
188 /*    NMesh Python Object    */
189 /*****************************/
190
191
192 static void NMFace_dealloc(PyObject *self) {
193         NMFace *mf= (NMFace *) self;
194         
195         Py_DECREF(mf->v);
196         Py_DECREF(mf->uv);
197         Py_DECREF(mf->col);
198         
199         PyMem_DEL(self);
200
201 }
202
203 static NMFace *newNMFace(PyObject *vertexlist) {
204         NMFace *mf= PyObject_NEW(NMFace, &NMFace_Type);
205
206         mf->v= vertexlist;
207         mf->uv= PyList_New(0);
208         mf->tpage= NULL;
209         mf->mode = TF_DYNAMIC + TF_TEX;
210         mf->flag= TF_SELECT;
211         mf->transp= TF_SOLID;
212         mf->col= PyList_New(0);
213         
214         mf->smooth= 0;
215         mf->mat_nr= 0;
216         
217         return mf;
218 }
219
220 static char NMeshmodule_Face_doc[]=
221 "(vertexlist = None) - Get a new face, and pass optional vertex list";
222 static PyObject *NMeshmodule_Face(PyObject *self, PyObject *args) {
223         PyObject *vertlist = NULL;
224         BPY_TRY(PyArg_ParseTuple(args, "|O!", &PyList_Type, &vertlist));        
225
226         if (!vertlist) {
227                 vertlist = PyList_New(0);
228         }
229         return (PyObject *) newNMFace(vertlist);
230 }
231
232 /* XXX this code will be used later...
233 static PyObject *Method_getmode(PyObject *self, PyObject *args) {
234         PyObject *dict, *list;
235         PyObject *constants, *values, *c;
236         int flag;
237         int i, n;
238
239         list = PyList_New(0);
240         dict = PyObject_GetAttrString(g_nmeshmodule, "Const");
241
242         if (!dict) return 0;
243
244         constants = PyDict_Keys(dict);
245         values = PyDict_Values(dict);
246         
247         n = PySequence_Length(constants);
248         for (i = 0; i < n; i++)
249         {
250                 flag = PyInt_AsLong(PySequence_GetItem(values, i));
251                 if (flag & ((NMFace*) self)->mode)
252                 {
253                         c = PySequence_GetItem(constants, i);
254                         PyList_Append(list, c) 
255                 }       
256         }
257         return list;
258 }
259 */
260
261 static char NMFace_append_doc[]= "(vert) - appends Vertex 'vert' to face vertex list";
262
263 static PyObject *NMFace_append(PyObject *self, PyObject *args)
264 {
265         PyObject *vert;
266         NMFace *f= (NMFace *) self;
267
268         BPY_TRY(PyArg_ParseTuple(args, "O!", &NMVert_Type, &vert));
269         PyList_Append(f->v, vert);
270         RETURN_INC(Py_None);
271 }
272
273
274 #undef MethodDef
275 #define MethodDef(func) {#func, NMFace_##func, METH_VARARGS, NMFace_##func##_doc}
276
277 static struct PyMethodDef NMFace_methods[] = {
278         MethodDef(append),
279         {NULL, NULL}
280 };
281
282 static PyObject *NMFace_getattr(PyObject *self, char *name) {
283         NMFace *mf= (NMFace *) self;
284                 
285         if(strcmp(name, "v")==0) 
286                 return Py_BuildValue("O", mf->v);
287         else if (strcmp(name, "col")==0) 
288                 return Py_BuildValue("O", mf->col);
289         else if (strcmp(name, "mat")==0) // emulation XXX
290                 return Py_BuildValue("i", mf->mat_nr);
291         else if (strcmp(name, "materialIndex")==0) 
292                 return Py_BuildValue("i", mf->mat_nr);
293         else if (strcmp(name, "smooth")==0)
294                 return Py_BuildValue("i", mf->smooth);
295         else if (strcmp(name, "image")==0) {
296                 if (mf->tpage)
297                         return Py_BuildValue("O", (PyObject *) mf->tpage);
298                 else 
299                         RETURN_INC(Py_None);
300         }
301         else if (strcmp(name, "mode")==0) 
302                 return Py_BuildValue("i", mf->mode);
303         else if (strcmp(name, "flag")==0) 
304                 return Py_BuildValue("i", mf->flag);
305         else if (strcmp(name, "transp")==0)
306                 return Py_BuildValue("i", mf->transp);
307         else if (strcmp(name, "uv")==0)
308                 return Py_BuildValue("O", mf->uv);
309                 
310         return Py_FindMethod(NMFace_methods, (PyObject*)self, name);
311 /*
312         PyErr_SetString(PyExc_AttributeError, name);
313         return NULL;
314 */
315 }
316
317 static int NMFace_setattr(PyObject *self, char *name, PyObject *v) {
318         NMFace *mf= (NMFace *) self;
319         int ival;
320         PyObject *tmp;
321         
322         if (STREQ(name, "v")) {
323                 if(PySequence_Check(v)) {
324                         Py_DECREF(mf->v);
325                         mf->v= BPY_incr_ret(v);
326
327                         return 0;
328                 }
329         } else if (STREQ(name, "col")) {
330                 if(PySequence_Check(v)) {
331                         Py_DECREF(mf->col);
332                         mf->col= BPY_incr_ret(v);
333
334                         return 0;
335                 }
336         } else if (STREQ(name, "mat") || STREQ(name, "materialIndex")) {
337                 PyArg_Parse(v, "i", &ival);
338
339                 mf->mat_nr= ival;
340                 
341                 return 0;
342         } else if (STREQ(name, "smooth")) {
343                 PyArg_Parse(v, "i", &ival);
344
345                 mf->smooth= ival?1:0;
346                 
347                 return 0;
348         } else if (STREQ(name, "uv")) {
349                 if(PySequence_Check(v)) {
350                         Py_DECREF(mf->uv);
351                         mf->uv= BPY_incr_ret(v);
352                         return 0;
353                 }       
354         } else if (STREQ(name, "flag")) {
355                         PyArg_Parse(v, "i", &ival);
356                         mf->flag = ival;
357                         return 0;
358         } else if (STREQ(name, "mode")) {
359                         PyArg_Parse(v, "i", &ival);
360                         mf->mode = ival;
361                         return 0;
362         } else if (STREQ(name, "transp")) {
363                         PyArg_Parse(v, "i", &ival);
364                         mf->transp = ival;
365                         return 0;
366         } else if (STREQ(name, "image")) {
367                 PyArg_Parse(v, "O", &tmp);
368                 if (tmp == Py_None) {
369                         mf->tpage = 0;
370                         return 0;
371                 }
372                 if (!DataBlock_isType((DataBlock *) tmp, ID_IM))
373                 {
374                         PyErr_SetString(PyExc_TypeError, "expects Image Datablock type");
375                         return -1;
376                 }
377                 mf->tpage = (DataBlock *) tmp;
378                 return 0;
379         }
380         
381         PyErr_SetString(PyExc_AttributeError, name);
382         return -1;
383 }
384
385 static PyObject *NMFace_repr (PyObject *self)
386 {
387         return PyString_FromString("[NMFace]");
388 }
389
390 static int NMFace_len(NMFace *self) 
391 {
392         return PySequence_Length(self->v);
393 }
394
395 static PyObject *NMFace_item(NMFace *self, int i)
396 {
397         return PySequence_GetItem(self->v, i); // new ref
398 }
399
400 static PyObject *NMFace_slice(NMFace *self, int begin, int end)
401 {
402         return PyList_GetSlice(self->v, begin, end); // new ref
403 }
404
405 static PySequenceMethods NMFace_SeqMethods = {
406         (inquiry)                       NMFace_len,                     /* sq_length    */
407         (binaryfunc)            0,                                      /* sq_concat    */
408         (intargfunc)            0,                                      /* sq_repeat    */
409         (intargfunc)            NMFace_item,            /* sq_item              */
410         (intintargfunc)         NMFace_slice,           /* sq_slice             */
411         (intobjargproc)         0,      /* sq_ass_item  */
412         (intintobjargproc)      0,      /* sq_ass_slice */
413 };
414
415
416 PyTypeObject NMFace_Type = {
417         PyObject_HEAD_INIT(NULL)
418         0,                                                      /*ob_size*/
419         "NMFace",                                               /*tp_name*/
420         sizeof(NMFace),                 /*tp_basicsize*/
421         0,                                                      /*tp_itemsize*/
422         /* methods */
423         (destructor) NMFace_dealloc,    /*tp_dealloc*/
424         (printfunc) 0,          /*tp_print*/
425         (getattrfunc) NMFace_getattr,   /*tp_getattr*/
426         (setattrfunc) NMFace_setattr,/*tp_setattr*/
427         0,                                                      /*tp_compare*/
428         (reprfunc) NMFace_repr,         /*tp_repr*/
429         0,                                                      /*tp_as_number*/
430         &NMFace_SeqMethods,                                                     /*tp_as_sequence*/
431         0,                                                      /*tp_as_mapping*/
432         0,                                                      /*tp_hash*/
433 };
434
435
436 static NMVert *newvert(float *co) {
437         NMVert *mv= PyObject_NEW(NMVert, &NMVert_Type);
438
439         VECCOPY(mv->co, co);
440         mv->no[0]= mv->no[1]= mv->no[2]= 0.0;
441         mv->uvco[0]= mv->uvco[1]= mv->uvco[2]= 0.0;
442         
443         return mv;
444 }
445
446 static char NMeshmodule_Vert_doc[]=
447 "([x, y, z]) - Get a new vertice\n\
448 \n\
449 [x, y, z] Specify new coordinates";
450
451 static PyObject *NMeshmodule_Vert(PyObject *self, PyObject *args) {
452         float co[3]= {0.0, 0.0, 0.0};
453         
454         BPY_TRY(PyArg_ParseTuple(args, "|fff", &co[0], &co[1], &co[2]));
455         
456         return (PyObject *) newvert(co);
457 }
458
459 static void NMVert_dealloc(PyObject *self) {
460         PyMem_DEL(self);
461 }
462
463 static PyObject *NMVert_getattr(PyObject *self, char *name) {
464         NMVert *mv= (NMVert *) self;
465
466         if (STREQ(name, "co") || STREQ(name, "loc")) return newVectorObject(mv->co, 3);
467         else if (STREQ(name, "no")) return newVectorObject(mv->no, 3);          
468         else if (STREQ(name, "uvco")) return newVectorObject(mv->uvco, 3);              
469         else if (STREQ(name, "index")) return PyInt_FromLong(mv->index);                
470         
471         PyErr_SetString(PyExc_AttributeError, name);
472         return NULL;
473 }
474
475 static int NMVert_setattr(PyObject *self, char *name, PyObject *v) {
476         NMVert *mv= (NMVert *) self;
477         int i;
478         
479         if (STREQ(name,"index")) {
480                 PyArg_Parse(v, "i", &i);
481                 mv->index= i;
482                 return 0;
483         } else if (STREQ(name, "uvco")) {
484                 if (!PyArg_ParseTuple(v, "ff|f", &(mv->uvco[0]), &(mv->uvco[1]), &(mv->uvco[2]))) {
485                         PyErr_SetString(PyExc_AttributeError, "Vector tuple or triple expected");
486                         return -1;
487                 }       
488                 return 0;
489 /*
490 PyErr_SetString(PyExc_AttributeError, "Use slice assignment: uvco[i]");
491                 return -1;
492                 */
493         }       
494         
495         PyErr_SetString(PyExc_AttributeError, name);
496         return -1;
497 }
498
499
500 static int NMVert_len(NMVert *self) {
501         return 3;
502 }
503
504 static PyObject *NMVert_item(NMVert *self, int i)
505 {
506         if (i < 0 || i >= 3) {
507                 PyErr_SetString(PyExc_IndexError, "array index out of range");
508                 return NULL;
509         }
510         return Py_BuildValue("f", self->co[i]);
511 }
512
513 static PyObject *NMVert_slice(NMVert *self, int begin, int end)
514 {
515         PyObject *list;
516         int count;
517         
518         if (begin<0) begin= 0;
519         if (end>3) end= 3;
520         if (begin>end) begin= end;
521                 
522         list= PyList_New(end-begin);
523
524         for (count= begin; count<end; count++)
525                 PyList_SetItem(list, count-begin, PyFloat_FromDouble(self->co[count]));
526         
527         return list;
528 }
529
530 static int NMVert_ass_item(NMVert *self, int i, PyObject *ob)
531 {
532         if (i < 0 || i >= 3) {
533                 PyErr_SetString(PyExc_IndexError, "array assignment index out of range");
534                 return -1;
535         }
536
537         if (!PyNumber_Check(ob)) {
538                 PyErr_SetString(PyExc_IndexError, "NMVert member must be a number");
539                 return -1;
540         }
541         
542         self->co[i]= PyFloat_AsDouble(ob);
543 /*      if(!PyArg_Parse(ob, "f", &)) return -1; */
544         
545         return 0;
546 }
547
548 /** I guess this hurts...
549   * sorry, couldn't resist (strubi) */
550
551 static int NMVert_ass_slice(NMVert *self, int begin, int end, PyObject *seq)
552 {
553         int count;
554         
555         if (begin<0) begin= 0;
556         if (end>3) end= 3;
557         if (begin>end) begin= end;
558
559         if (!PySequence_Check(seq)) {
560                 PyErr_SetString(PyExc_TypeError, "illegal argument type for built-in operation");
561                 return -1;              
562         }
563
564         if (PySequence_Length(seq)!=(end-begin)) {
565                 PyErr_SetString(PyExc_TypeError, "size mismatch in slice assignment");
566                 return -1;
567         }
568         
569         for (count= begin; count<end; count++) {
570                 PyObject *ob= PySequence_GetItem(seq, count);
571                 if (!PyArg_Parse(ob, "f", &self->co[count])) {
572                         Py_DECREF(ob);
573                         return -1;
574                 }
575                 Py_DECREF(ob);
576         }
577                 
578         return 0;
579 }
580
581 static PySequenceMethods NMVert_SeqMethods = {
582         (inquiry)                       NMVert_len,                     /* sq_length    */
583         (binaryfunc)            0,                                      /* sq_concat    */
584         (intargfunc)            0,                                      /* sq_repeat    */
585         (intargfunc)            NMVert_item,            /* sq_item              */
586         (intintargfunc)         NMVert_slice,           /* sq_slice             */
587         (intobjargproc)         NMVert_ass_item,        /* sq_ass_item  */
588         (intintobjargproc)      NMVert_ass_slice,       /* sq_ass_slice */
589 };
590
591 PyTypeObject NMVert_Type = {
592         PyObject_HEAD_INIT(NULL)
593         0,                             /*ob_size*/
594         "NMVert",                      /*tp_name*/
595         sizeof(NMVert),                /*tp_basicsize*/
596         0,                             /*tp_itemsize*/
597         /* methods */
598         (destructor) NMVert_dealloc,   /*tp_dealloc*/
599         (printfunc) 0,                 /*tp_print*/
600         (getattrfunc) NMVert_getattr,  /*tp_getattr*/
601         (setattrfunc) NMVert_setattr,  /*tp_setattr*/
602         0,                             /*tp_compare*/
603         (reprfunc) 0,                  /*tp_repr*/
604         0,                             /*tp_as_number*/
605         &NMVert_SeqMethods,            /*tp_as_sequence*/
606 };
607
608
609 static void NMesh_dealloc(PyObject *self) {
610         NMesh *me= (NMesh *) self;
611
612         Py_DECREF(me->name);
613         Py_DECREF(me->verts);
614         Py_DECREF(me->faces);
615         
616         PyMem_DEL(self);
617 }
618
619
620 static char NMesh_getSelectedFaces_doc[] = "(flag = None) - returns list of selected Faces\n\
621 If flag = 1, return indices instead";
622 static PyObject *NMesh_getSelectedFaces(PyObject *self, PyObject *args)
623 {
624         NMesh *nm= (NMesh *) self;
625         Mesh *me = nm->mesh;
626         int flag = 0;
627
628         TFace *tf;
629         int i;
630         PyObject *l= PyList_New(0);
631
632         if (me == NULL) return NULL;
633
634         tf = me->tface;
635         if (tf == 0) {
636                 return l;
637         }
638
639         if (!PyArg_ParseTuple(args, "|i", &flag)) 
640                 return NULL;
641         if (flag) {
642                 for (i =0 ; i < me->totface; i++) {
643                         if (tf[i].flag & TF_SELECT ) {
644                                 PyList_Append(l, PyInt_FromLong(i));
645                         }
646                 }               
647         } else {
648                 for (i =0 ; i < me->totface; i++) {
649                         if (tf[i].flag & TF_SELECT ) {
650                                 PyList_Append(l, PyList_GetItem(nm->faces, i));
651                         }
652                 }               
653         }
654         return l;
655 }
656
657
658 static char NMesh_getActiveFace_doc[] = "returns the index of the active face ";
659 static PyObject *NMesh_getActiveFace(PyObject *self, PyObject *args)
660 {
661         if (((NMesh *)self)->sel_face < 0)
662                 RETURN_INC(Py_None);
663         return Py_BuildValue("i", ((NMesh *)self)->sel_face);
664 }
665
666 static char NMesh_hasVertexUV_doc[] = "(flag = None) - returns 1 if Mesh has per vertex UVs ('Sticky')\n\
667 The optional argument sets the Sticky flag";
668
669 static PyObject *NMesh_hasVertexUV(PyObject *self, PyObject *args)
670 {
671         NMesh *me= (NMesh *) self;
672         int flag;
673
674         if (args) {
675                 if (PyArg_ParseTuple(args, "i", &flag)) {
676                         if(flag) me->flags |= NMESH_HASVERTUV;
677                         else me->flags &= ~NMESH_HASVERTUV;
678                 }
679         }
680         PyErr_Clear();
681         if (me->flags & NMESH_HASVERTUV)
682                 return BPY_incr_ret(Py_True);
683         else
684                 return BPY_incr_ret(Py_False);
685 }
686
687 static char NMesh_hasFaceUV_doc[] = "(flag = None) - returns 1 if Mesh has textured faces\n\
688 The optional argument sets the textured faces flag";
689
690 static PyObject *NMesh_hasFaceUV(PyObject *self, PyObject *args)
691 {
692         NMesh *me= (NMesh *) self;
693         int flag = -1;
694
695         BPY_TRY(PyArg_ParseTuple(args, "|i", &flag));
696
697         switch (flag) {
698         case 0:
699                 me->flags |= NMESH_HASFACEUV;
700                 break;
701         case 1: 
702                 me->flags &= ~NMESH_HASFACEUV;
703                 break;
704         default:
705                 break;
706         }
707
708         if (me->flags & NMESH_HASFACEUV)
709                 return BPY_incr_ret(Py_True);
710         else
711                 return BPY_incr_ret(Py_False);
712 }
713
714
715 static char NMesh_hasVertexColours_doc[] = "(flag = None) - returns 1 if Mesh has vertex colours.\n\
716 The optional argument sets the vertex colour flag";
717
718 static PyObject *NMesh_hasVertexColours(PyObject *self, PyObject *args)
719 {
720         NMesh *me= (NMesh *) self;
721         int flag = -1;
722
723         BPY_TRY(PyArg_ParseTuple(args, "|i", &flag));
724
725         switch (flag) {
726         case 0:
727                 me->flags &= ~NMESH_HASMCOL;
728                 break;
729         case 1: 
730                 me->flags |= NMESH_HASMCOL;
731                 break;
732         default:
733                 break;
734         }
735
736         if (me->flags & NMESH_HASMCOL)
737                 return BPY_incr_ret(Py_True);
738         else
739                 return BPY_incr_ret(Py_False);
740
741 }
742
743
744 static char NMesh_update_doc[] = "updates the Mesh";
745 static PyObject *NMesh_update(PyObject *self, PyObject *args)
746 {
747         NMesh *nmesh= (NMesh *) self;
748         Mesh *mesh = nmesh->mesh;
749         
750         if (mesh) {
751                 unlink_existingMeshdata(mesh);
752                 convert_NMeshToMesh(mesh, nmesh);
753                 mesh_update(mesh);
754         } else {  
755                 nmesh->mesh = Mesh_fromNMesh(nmesh);
756         }
757
758         nmesh_updateMaterials(nmesh);
759 /** This is another ugly fix due to the weird material handling of blender.
760   * it makes sure that object material lists get updated (by their length)
761   * according to their data material lists, otherwise blender crashes.
762   * It just stupidly runs through all objects...BAD BAD BAD.
763   */
764         test_object_materials((ID *)mesh);
765
766         if (!during_script())
767                 allqueue(REDRAWVIEW3D, 0);
768         return PyInt_FromLong(1);
769
770 }
771
772
773 Mesh *Mesh_fromNMesh(NMesh *nmesh)
774 {
775         Mesh *mesh= NULL;
776         mesh = mesh_new(); // new empty mesh Bobject
777         if (!mesh) {
778                 PyErr_SetString(PyExc_RuntimeError, "FATAL: could not create mesh object");
779                 return NULL;
780         }
781         
782         convert_NMeshToMesh(mesh, nmesh);
783         mesh_update(mesh);
784         return mesh;
785 }
786
787 #ifdef EXPERIMENTAL
788
789 static char NMesh_asMesh_doc[] = "returns free Mesh datablock object from NMesh";
790 static PyObject *NMesh_asMesh(PyObject *self, PyObject *args)
791 {
792         char *name= NULL;
793         Mesh *mesh= NULL;
794         NMesh *nmesh;
795         int recalc_normals= 1;
796
797         nmesh = (NMesh *) self;
798         
799         BPY_TRY(PyArg_ParseTuple(args, "|si", &name, &recalc_normals));
800         
801         if (!PySequence_Check(nmesh->verts))
802                 return BPY_err_ret_ob(PyExc_AttributeError, 
803                         "nmesh vertices are not a sequence");
804         if (!PySequence_Check(nmesh->faces))
805                 return BPY_err_ret_ob(PyExc_AttributeError, 
806                         "nmesh faces are not a sequence");
807         if (!PySequence_Check(nmesh->materials))
808                 return BPY_err_ret_ob(PyExc_AttributeError, 
809                         "nmesh materials are not a sequence");
810         if (!BPY_check_sequence_consistency(nmesh->verts, &NMVert_Type))
811                 return BPY_err_ret_ob(PyExc_AttributeError, 
812                         "nmesh vertices must be NMVerts");
813         if (!BPY_check_sequence_consistency(nmesh->faces, &NMFace_Type))
814                 return BPY_err_ret_ob(PyExc_AttributeError, 
815                         "nmesh faces must be NMFaces");
816
817         mesh = Mesh_fromNMesh(nmesh);
818         return DataBlock_fromData(mesh);
819 }
820
821 #endif
822 static char NMesh_link_doc[] = "(object) - Links NMesh data with Object 'object'";
823
824 PyObject * NMesh_link(PyObject *self, PyObject *args) 
825 {
826         return DataBlock_link(self, args);
827 }
828
829 #undef MethodDef
830 #define MethodDef(func) {#func, NMesh_##func, METH_VARARGS, NMesh_##func##_doc}
831
832 static struct PyMethodDef NMesh_methods[] = {
833         MethodDef(hasVertexColours),
834         MethodDef(hasFaceUV),
835         MethodDef(hasVertexUV),
836         MethodDef(getActiveFace),
837         MethodDef(getSelectedFaces),
838         MethodDef(update),
839 #ifdef EXPERIMENTAL     
840         MethodDef(asMesh),
841 #endif  
842         {NULL, NULL}
843 };
844
845 static PyObject *NMesh_getattr(PyObject *self, char *name) {
846         NMesh *me= (NMesh *) self;
847         
848         if (STREQ(name, "name")) 
849                 return BPY_incr_ret(me->name);
850         
851         else if (STREQ(name, "block_type"))
852           return PyString_FromString("NMesh");
853
854         else if (STREQ(name, "materials"))
855                 return BPY_incr_ret(me->materials);
856
857         else if (STREQ(name, "verts"))
858                 return BPY_incr_ret(me->verts);
859                 
860         else if (STREQ(name, "users")) {
861                 if (me->mesh) {
862                         return PyInt_FromLong(me->mesh->id.us); 
863                 } else { // it's a free mesh:
864                         return Py_BuildValue("i", 0); 
865                 }
866         }
867
868         else if (STREQ(name, "faces"))
869                 return BPY_incr_ret(me->faces);
870
871         return Py_FindMethod(NMesh_methods, (PyObject*)self, name);
872         
873         PyErr_SetString(PyExc_AttributeError, name);
874         return NULL;
875 }
876
877 static int NMesh_setattr(PyObject *self, char *name, PyObject *v) {
878         NMesh *me= (NMesh *) self;
879
880         if (STREQ3(name, "verts", "faces", "materials")) {
881                 if(PySequence_Check(v)) {
882                         if(STREQ(name, "materials")) {
883                                 Py_DECREF(me->materials);
884                                 me->materials= BPY_incr_ret(v);
885                         } else if (STREQ(name, "verts")) {
886                                 Py_DECREF(me->verts);
887                                 me->verts= BPY_incr_ret(v);
888                         } else {
889                                 Py_DECREF(me->faces);
890                                 me->faces= BPY_incr_ret(v);                             
891                         }
892                 } else {
893                         PyErr_SetString(PyExc_AttributeError, "expected a sequence");
894                         return -1;
895                 }
896         } else {
897                 PyErr_SetString(PyExc_AttributeError, name);
898                 return -1;
899         }
900
901         return 0;
902 }
903
904 PyTypeObject NMesh_Type = {
905         PyObject_HEAD_INIT(NULL)
906         0,                                                              /*ob_size*/
907         "NMesh",                                                /*tp_name*/
908         sizeof(NMesh),                                  /*tp_basicsize*/
909         0,                                                              /*tp_itemsize*/
910         /* methods */
911         (destructor)    NMesh_dealloc,  /*tp_dealloc*/
912         (printfunc)             0,      /*tp_print*/
913         (getattrfunc)   NMesh_getattr,  /*tp_getattr*/
914         (setattrfunc)   NMesh_setattr,  /*tp_setattr*/
915 };
916
917 static NMFace *nmface_from_data(NMesh *mesh, int vidxs[4], char mat_nr, char flag, TFace *tface, MCol *col) 
918 {
919         NMFace *newf= PyObject_NEW(NMFace, &NMFace_Type);
920         int i, len;
921
922         if(vidxs[3]) len= 4;
923         else if(vidxs[2]) len= 3;
924         else len= 2;
925
926         newf->v= PyList_New(len);
927
928         for (i=0; i<len; i++)   
929                 PyList_SetItem(newf->v, i, BPY_incr_ret(PyList_GetItem(mesh->verts, vidxs[i])));
930
931         if (tface) {
932                 newf->uv = PyList_New(len); // per-face UV coordinates
933                 for (i = 0; i < len; i++)
934                 {
935                         PyList_SetItem(newf->uv, i, Py_BuildValue("(ff)", tface->uv[i][0], tface->uv[i][1]));
936                 }
937                 if (tface->tpage)
938                         newf->tpage = (DataBlock *) DataBlock_fromData((void *) tface->tpage); /* pointer to image per face */
939                 else
940                         newf->tpage = 0;
941                 newf->mode = tface->mode;     /* draw mode */
942                 newf->flag = tface->flag;               /* select flag */
943                 newf->transp = tface->transp;  /* transparency flag */
944                 col = (MCol *) (tface->col);
945         } else {
946                 newf->tpage = 0;
947                 newf->uv = PyList_New(0); 
948         }       
949         
950         newf->mat_nr= mat_nr;
951         newf->smooth= flag&ME_SMOOTH;
952
953         if (col) {
954                 newf->col= PyList_New(4);
955                 for(i=0; i<4; i++, col++)
956                         PyList_SetItem(newf->col, i, 
957                                 (PyObject *) newcol(col->b, col->g, col->r, col->a));
958         } else {
959                 newf->col= PyList_New(0);
960         }
961         return newf;
962 }
963
964 static NMFace *nmface_from_shortdata(NMesh *mesh, MFace *face, TFace *tface, MCol *col) 
965 {
966         int vidxs[4];
967         vidxs[0]= face->v1;
968         vidxs[1]= face->v2;
969         vidxs[2]= face->v3;
970         vidxs[3]= face->v4;
971                 
972         return nmface_from_data(mesh, vidxs, face->mat_nr, face->flag, tface, col);
973 }
974
975 static NMFace *nmface_from_intdata(NMesh *mesh, MFaceInt *face, TFace *tface, MCol *col) 
976 {
977         int vidxs[4];
978         vidxs[0]= face->v1;
979         vidxs[1]= face->v2;
980         vidxs[2]= face->v3;
981         vidxs[3]= face->v4;
982                 
983         return nmface_from_data(mesh, vidxs, face->mat_nr, face->flag, tface, col);
984 }
985
986 static NMVert *nmvert_from_data(NMesh *me, MVert *vert, MSticky *st, float *co, int idx)
987 {                       
988         NMVert *mv= PyObject_NEW(NMVert, &NMVert_Type);
989                         
990         VECCOPY (mv->co, co);
991                 
992         mv->no[0]= vert->no[0]/32767.0;
993         mv->no[1]= vert->no[1]/32767.0;
994         mv->no[2]= vert->no[2]/32767.0;
995         
996         if (st) {
997                 mv->uvco[0]= st->co[0];
998                 mv->uvco[1]= st->co[1];
999                 mv->uvco[2]= 0.0;
1000                 
1001         } else mv->uvco[0]= mv->uvco[1]= mv->uvco[2]= 0.0;
1002
1003         mv->index= idx;
1004                         
1005         return mv;
1006 }
1007
1008 static int get_active_faceindex(Mesh *me)
1009 {
1010         TFace *tf;
1011         int i;
1012
1013         if (me == NULL) return -1;
1014
1015         tf = me->tface;
1016         if (tf == 0) return -1;
1017         
1018         for (i =0 ; i < me->totface; i++) {
1019                 if (tf[i].flag & TF_ACTIVE ) {
1020                         return i;
1021                 }
1022         }               
1023         return -1;
1024 }
1025
1026 static PyObject *newNMesh_internal(Mesh *oldmesh, DispListMesh *dlm, float *extverts) 
1027 {
1028         NMesh *me= PyObject_NEW(NMesh, &NMesh_Type);
1029         me->flags= 0;
1030
1031         if (!oldmesh) {
1032                 me->name= BPY_incr_ret(Py_None);
1033                 me->materials= PyList_New(0);
1034                 me->verts= PyList_New(0);
1035                 me->faces= PyList_New(0);
1036                 me->mesh= 0;
1037         } else {
1038                 MVert *mverts;
1039                 MSticky *msticky;
1040                 MFaceInt *mfaceints;
1041                 MFace *mfaces;
1042                 TFace *tfaces;
1043                 MCol *mcols;
1044                 int i, totvert, totface;
1045                 
1046                 if (dlm) {
1047                         me->name= BPY_incr_ret(Py_None);
1048                         me->mesh= 0;
1049
1050                         msticky= NULL;
1051                         mfaces= NULL;
1052                         mverts= dlm->mvert;
1053                         mfaceints= dlm->mface;
1054                         tfaces= dlm->tface;
1055                         mcols= dlm->mcol;
1056                         
1057                         totvert= dlm->totvert;
1058                         totface= dlm->totface;
1059                 } else {
1060                         me->name= PyString_FromString(oldmesh->id.name+2);
1061                         me->mesh= oldmesh;
1062                         
1063                         mfaceints= NULL;
1064                         msticky= oldmesh->msticky;
1065                         mverts= oldmesh->mvert;
1066                         mfaces= oldmesh->mface;
1067                         tfaces= oldmesh->tface;
1068                         mcols= oldmesh->mcol;
1069
1070                         totvert= oldmesh->totvert;
1071                         totface= oldmesh->totface;
1072
1073                         me->sel_face= get_active_faceindex(oldmesh);
1074                 }
1075
1076                 if (msticky) me->flags |= NMESH_HASVERTUV;
1077                 if (tfaces) me->flags |= NMESH_HASFACEUV;
1078                 if (mcols) me->flags |= NMESH_HASMCOL;
1079
1080                 me->verts= PyList_New(totvert);
1081                 for (i=0; i<totvert; i++) {
1082                         MVert *oldmv= &mverts[i];
1083                         MSticky *oldst= msticky?&msticky[i]:NULL;
1084                         float *vco= extverts?&extverts[i*3]:oldmv->co;
1085                         
1086                         PyList_SetItem(me->verts, i, (PyObject *) nmvert_from_data(me, oldmv, oldst, vco, i));  
1087                 }
1088
1089                 me->faces= PyList_New(totface);
1090                 for (i=0; i<totface; i++) {
1091                         TFace *oldtf= tfaces?&tfaces[i]:NULL;
1092                         MCol *oldmc= mcols?&mcols[i*4]:NULL;
1093
1094                         if (mfaceints) {                        
1095                                 MFaceInt *oldmf= &mfaceints[i];
1096                                 PyList_SetItem(me->faces, i, (PyObject *) nmface_from_intdata(me, oldmf, oldtf, oldmc));
1097                         } else {
1098                                 MFace *oldmf= &mfaces[i];
1099                                 PyList_SetItem(me->faces, i, (PyObject *) nmface_from_shortdata(me, oldmf, oldtf, oldmc));
1100                         }
1101                 }
1102                 me->materials = PyList_fromMaterialList(oldmesh->mat, oldmesh->totcol);
1103         }
1104         
1105         return (PyObject *) me; 
1106 }
1107
1108 PyObject *newNMesh(Mesh *oldmesh) 
1109 {
1110         return newNMesh_internal(oldmesh, NULL, NULL);
1111 }
1112
1113 static char NMeshmodule_New_doc[]=
1114 "() - returns a new, empty NMesh mesh object\n";
1115
1116 static PyObject *NMeshmodule_New(PyObject *self, PyObject *args) 
1117 {
1118         return newNMesh(NULL);
1119 }
1120
1121 static char NMeshmodule_GetRaw_doc[]=
1122 "([name]) - Get a raw mesh from Blender\n\
1123 \n\
1124 [name] Name of the mesh to be returned\n\
1125 \n\
1126 If name is not specified a new empty mesh is\n\
1127 returned, otherwise Blender returns an existing\n\
1128 mesh.";
1129
1130 static PyObject *NMeshmodule_GetRaw(PyObject *self, PyObject *args) 
1131 {
1132         char *name=NULL;
1133         Mesh *oldmesh=NULL;
1134         
1135         BPY_TRY(PyArg_ParseTuple(args, "|s", &name));   
1136
1137         if(name) {
1138                 oldmesh = (Mesh *) getFromList(getMeshList(), name);
1139
1140                 if (!oldmesh) return BPY_incr_ret(Py_None);
1141         }
1142         return newNMesh(oldmesh);
1143 }
1144
1145 static char NMeshmodule_GetRawFromObject_doc[]=
1146 "(name) - Get the raw mesh used by a Blender object\n"
1147 "\n"
1148 "(name) Name of the object to get the mesh from\n"
1149 "\n"
1150 "This returns the mesh as used by the object, which\n"
1151 "means it contains all deformations and modifications.";
1152
1153 static PyObject *NMeshmodule_GetRawFromObject(PyObject *self, PyObject *args) 
1154 {
1155         char *name;
1156         Object *ob;
1157         PyObject *nmesh;
1158         
1159         BPY_TRY(PyArg_ParseTuple(args, "s", &name));
1160         
1161         ob= (Object*) getFromList(getObjectList(), name);
1162         if (!ob)
1163                 return BPY_err_ret_ob(PyExc_AttributeError, name);
1164         else if (ob->type!=OB_MESH)
1165                 return BPY_err_ret_ob(PyExc_AttributeError, "Object does not have Mesh data");
1166         else {
1167                 Mesh *me= (Mesh*) ob->data;
1168                 DispList *dl;
1169                 
1170                 if (mesh_uses_displist(me) && (dl= find_displist(&me->disp, DL_MESH)))
1171                         nmesh = newNMesh_internal(me, dl->mesh, NULL);
1172                 else if ((dl= find_displist(&ob->disp, DL_VERTS)))
1173                         nmesh = newNMesh_internal(me, NULL, dl->verts);
1174                 else
1175                         nmesh = newNMesh(me);
1176         }
1177         ((NMesh *) nmesh)->mesh = 0; // hack: to mark that (deformed) mesh is readonly,
1178                                  // so the update function will not try to write it.
1179         return nmesh;
1180 }
1181
1182 static void mvert_from_data(MVert *mv, MSticky *st, NMVert *from) 
1183 {
1184         VECCOPY (mv->co, from->co);
1185         mv->no[0]= from->no[0]*32767.0;
1186         mv->no[1]= from->no[1]*32767.0;
1187         mv->no[2]= from->no[2]*32767.0;
1188                 
1189         mv->flag= 0;
1190         mv->mat_nr= 0;
1191
1192         if (st) {
1193                 st->co[0]= from->uvco[0];
1194                 st->co[1]= from->uvco[1];
1195         }
1196 }
1197
1198 /* TODO: this function is just a added hack. Don't look at the
1199  * RGBA/BRGA confusion, it just works, but will never work with
1200  * a restructured Blender */
1201
1202 static void assign_perFaceColors(TFace *tf, NMFace *from)
1203 {
1204         MCol *col;
1205         int i;
1206
1207         col = (MCol *) (tf->col);
1208
1209         if (col) {
1210                 int len= PySequence_Length(from->col);
1211                 
1212                 if(len>4) len= 4;
1213                 
1214                 for (i=0; i<len; i++, col++) {
1215                         NMCol *mc= (NMCol *) PySequence_GetItem(from->col, i);
1216                         if(!NMCol_Check(mc)) {
1217                                 Py_DECREF(mc);
1218                                 continue;
1219                         }
1220                         
1221                         col->r= mc->b;
1222                         col->b= mc->r;
1223                         col->g= mc->g;
1224                         col->a= mc->a;
1225
1226                         Py_DECREF(mc);
1227                 }
1228         }
1229 }
1230
1231 static int assignFaceUV(TFace *tf, NMFace *nmface)
1232 {
1233         PyObject *fuv, *tmp;
1234         int i;
1235
1236         fuv = nmface->uv;
1237         if (PySequence_Length(fuv) == 0)
1238                 return 0;
1239         /* fuv = [(u_1, v_1), ... (u_n, v_n)] */
1240         for (i = 0; i < PySequence_Length(fuv); i++) {
1241                 tmp = PyList_GetItem(fuv, i); /* stolen reference ! */
1242                 if (!PyArg_ParseTuple(tmp, "ff", &(tf->uv[i][0]), &(tf->uv[i][1])))
1243                         return 0;
1244         }
1245         if (nmface->tpage) /* image assigned ? */
1246         {
1247                 tf->tpage = nmface->tpage->data; 
1248         }
1249         else
1250                 tf->tpage = 0;
1251
1252         tf->mode = nmface->mode; /* copy mode */
1253         tf->flag = nmface->flag; /* copy flag */
1254         tf->transp = nmface->transp; /* copy transp flag */
1255
1256         /* assign vertex colours */
1257         assign_perFaceColors(tf, nmface);
1258         return 1;
1259 }
1260
1261 static void mface_from_data(MFace *mf, TFace *tf, MCol *col, NMFace *from)
1262 {
1263         NMVert *nmv;
1264
1265         int i= PyList_Size(from->v);
1266         if(i>=1) {
1267                 nmv= (NMVert *) PyList_GetItem(from->v, 0);
1268                 if (NMVert_Check(nmv) && nmv->index!=-1) mf->v1= nmv->index;
1269                 else mf->v1= 0;
1270         }
1271         if(i>=2) {
1272                 nmv= (NMVert *) PyList_GetItem(from->v, 1);
1273                 if (NMVert_Check(nmv) && nmv->index!=-1) mf->v2= nmv->index;
1274                 else mf->v2= 0;
1275         }
1276         if(i>=3) {
1277                 nmv= (NMVert *) PyList_GetItem(from->v, 2);
1278                 if (NMVert_Check(nmv) && nmv->index!=-1) mf->v3= nmv->index;
1279                 else mf->v3= 0;
1280         }
1281         if(i>=4) {
1282                 nmv= (NMVert *) PyList_GetItem(from->v, 3);
1283                 if (NMVert_Check(nmv) && nmv->index!=-1) mf->v4= nmv->index;
1284                 else mf->v4= 0;
1285         }
1286
1287         /*      this function is evil: 
1288
1289                         test_index_mface(mf, i);
1290
1291                 It rotates vertex indices, if there are illegal '0's (end marker)
1292                 in the vertex index list.
1293                 But it doesn't do that with vertex colours or texture coordinates...
1294         */
1295
1296         if (tf) {
1297                 assignFaceUV(tf, from);
1298                 if (PyErr_Occurred())
1299                 {
1300                         PyErr_Print();
1301                         return;
1302                 }
1303
1304                 test_index_face(mf, tf, i);
1305         } else {
1306                 test_index_mface(mf, i);
1307         }
1308
1309         mf->puno= 0;
1310         mf->mat_nr= from->mat_nr;
1311         mf->edcode= 0;
1312         if (from->smooth) 
1313                 mf->flag= ME_SMOOTH;
1314         else
1315                 mf->flag= 0;
1316         
1317         if (col) {
1318                 int len= PySequence_Length(from->col);
1319                 
1320                 if(len>4) len= 4;
1321                 
1322                 for (i=0; i<len; i++, col++) {
1323                         NMCol *mc= (NMCol *) PySequence_GetItem(from->col, i);
1324                         if(!NMCol_Check(mc)) {
1325                                 Py_DECREF(mc);
1326                                 continue;
1327                         }
1328                         
1329                         col->b= mc->r;
1330                         col->g= mc->g;
1331                         col->r= mc->b;
1332                         col->a= mc->a;
1333
1334                         Py_DECREF(mc);
1335                 }
1336         }
1337 }
1338
1339
1340 /* check for a valid UV sequence */
1341 static int check_validFaceUV(NMesh *nmesh)
1342 {
1343         PyObject *faces;
1344         NMFace *nmface;
1345         int i, n;
1346
1347         faces = nmesh->faces;
1348         for (i = 0; i < PySequence_Length(faces); i++) {
1349                 nmface = (NMFace *) PyList_GetItem(faces, i);
1350                 n = 
1351                 n = PySequence_Length(nmface->uv);
1352                 if (n != PySequence_Length(nmface->v))
1353                 {
1354                         if (n > 0) 
1355                                 printf("Warning: different length of vertex and UV coordinate "
1356                                        "list in face!\n");
1357                         return 0;
1358                 }       
1359         }
1360         return 1;
1361 }
1362
1363 static int unlink_existingMeshdata(Mesh *mesh)
1364 {
1365         freedisplist(&mesh->disp);
1366         unlink_mesh(mesh);
1367         if(mesh->mvert) MEM_freeN(mesh->mvert);
1368         if(mesh->mface) MEM_freeN(mesh->mface);
1369         if(mesh->mcol) MEM_freeN(mesh->mcol);
1370         if(mesh->msticky) MEM_freeN(mesh->msticky);
1371         if(mesh->mat) MEM_freeN(mesh->mat);
1372         if(mesh->tface) MEM_freeN(mesh->tface);
1373         return 1;
1374 }
1375
1376 Material **nmesh_updateMaterials(NMesh *nmesh)
1377 {
1378         Material **matlist;
1379         Mesh *mesh = nmesh->mesh;
1380         int len = PySequence_Length(nmesh->materials);
1381
1382         if (!mesh) {
1383                 printf("FATAL INTERNAL ERROR: illegal call to updateMaterials()\n");
1384                 return 0;
1385         }
1386
1387         if (len > 0) {
1388                 matlist = newMaterialList_fromPyList(nmesh->materials);
1389                 if (mesh->mat)
1390                         MEM_freeN(mesh->mat);
1391                 mesh->mat = matlist;
1392         } else {
1393                 matlist = 0;
1394         }
1395         mesh->totcol = len;
1396         return matlist;
1397 }
1398
1399 PyObject *NMesh_assignMaterials_toObject(NMesh *nmesh, Object *ob)
1400 {
1401         DataBlock *block;
1402         Material *ma;
1403         int i;
1404         short old_matmask;
1405
1406         old_matmask = ob->colbits; // HACK: save previous colbits
1407         ob->colbits = 0;           // make assign_material work on mesh linked material
1408
1409         for (i= 0; i < PySequence_Length(nmesh->materials); i++) {
1410                 block= (DataBlock *) PySequence_GetItem(nmesh->materials, i);
1411                 
1412                 if (DataBlock_isType(block, ID_MA)) {
1413                         ma = (Material *) block->data;
1414                         assign_material(ob, ma, i+1); // XXX don't use this function anymore
1415                 } else {
1416                         PyErr_SetString(PyExc_TypeError, 
1417                         "Material type in attribute list 'materials' expected!");
1418                         Py_DECREF(block);
1419                         return NULL;
1420                 }       
1421                 
1422                 Py_DECREF(block);
1423         }
1424         ob->colbits = old_matmask; // HACK
1425
1426         ob->actcol = 1;
1427         RETURN_INC(Py_None);
1428 }
1429
1430 static int convert_NMeshToMesh(Mesh *mesh, NMesh *nmesh)
1431 {
1432         MFace *newmf;
1433         TFace *newtf;
1434         MVert *newmv;
1435         MSticky *newst;
1436         MCol *newmc;
1437
1438         int i, j;
1439
1440         mesh->mvert= NULL;
1441         mesh->mface= NULL;
1442         mesh->mcol= NULL;
1443         mesh->msticky= NULL;
1444         mesh->tface = NULL;
1445         mesh->mat= NULL;
1446
1447         // material assignment moved to PutRaw
1448         mesh->totvert= PySequence_Length(nmesh->verts);
1449         if (mesh->totvert) {
1450                 if (nmesh->flags&NMESH_HASVERTUV)
1451                         mesh->msticky= MEM_callocN(sizeof(MSticky)*mesh->totvert, "msticky");
1452
1453                 mesh->mvert= MEM_callocN(sizeof(MVert)*mesh->totvert, "mverts");
1454         }
1455
1456         if (mesh->totvert)
1457                 mesh->totface= PySequence_Length(nmesh->faces);
1458         else
1459                 mesh->totface= 0;
1460
1461
1462         if (mesh->totface) {
1463
1464 /* only create vertcol array if mesh has no texture faces */
1465
1466 /* TODO: get rid of double storage of vertex colours. In a mesh,
1467  * vertex colors can be stored the following ways:
1468  * - per (TFace*)->col
1469  * - per (Mesh*)->mcol
1470  * This is stupid, but will reside for the time being -- at least until
1471  * a redesign of the internal Mesh structure */
1472
1473                 if (!(nmesh->flags & NMESH_HASFACEUV) && (nmesh->flags&NMESH_HASMCOL))
1474                         mesh->mcol= MEM_callocN(4*sizeof(MCol)*mesh->totface, "mcol");
1475                         
1476                 mesh->mface= MEM_callocN(sizeof(MFace)*mesh->totface, "mfaces");
1477         }
1478
1479         /* This stuff here is to tag all the vertices referenced
1480          * by faces, then untag the vertices which are actually
1481          * in the vert list. Any vertices untagged will be ignored
1482          * by the mface_from_data function. It comes from my
1483          * screwed up decision to not make faces only store the
1484          * index. - Zr
1485          */
1486         for (i=0; i<mesh->totface; i++) {
1487                 NMFace *mf= (NMFace *) PySequence_GetItem(nmesh->faces, i);
1488                         
1489                 j= PySequence_Length(mf->v);
1490                 while (j--) {
1491                         NMVert *mv= (NMVert *) PySequence_GetItem(mf->v, j);
1492                         if (NMVert_Check(mv)) mv->index= -1;
1493                         Py_DECREF(mv);
1494                 }
1495                 
1496                 Py_DECREF(mf);
1497         }
1498         
1499         for (i=0; i<mesh->totvert; i++) {
1500                 NMVert *mv= (NMVert *) PySequence_GetItem(nmesh->verts, i);
1501                 mv->index= i;
1502                 Py_DECREF(mv);
1503         }       
1504         
1505         newmv= mesh->mvert;
1506         newst= mesh->msticky;
1507         for (i=0; i<mesh->totvert; i++) {
1508                 PyObject *mv=  PySequence_GetItem(nmesh->verts, i);
1509                 mvert_from_data(newmv, newst, (NMVert *)mv);
1510                 Py_DECREF(mv);
1511                 
1512                 newmv++;
1513                 if (newst) newst++;
1514         }
1515
1516 /*  assign per face texture UVs */
1517
1518         /* check face UV flag, then check whether there was one 
1519          * UV coordinate assigned, if yes, make tfaces */
1520         if ((nmesh->flags & NMESH_HASFACEUV) || (check_validFaceUV(nmesh))) {
1521                 make_tfaces(mesh); /* initialize TFaces */
1522
1523                 newmc= mesh->mcol;
1524                 newmf= mesh->mface;
1525                 newtf= mesh->tface;
1526                 for (i=0; i<mesh->totface; i++) {
1527                         PyObject *mf= PySequence_GetItem(nmesh->faces, i);
1528                         mface_from_data(newmf, newtf, newmc, (NMFace *) mf);
1529                         Py_DECREF(mf);
1530                                 
1531                         newtf++;
1532                         newmf++;
1533                         if (newmc) newmc++;
1534                 }
1535
1536                 nmesh->flags |= NMESH_HASFACEUV;
1537         } else {
1538
1539                 newmc= mesh->mcol;
1540                 newmf= mesh->mface;
1541                 for (i=0; i<mesh->totface; i++) {
1542                         PyObject *mf= PySequence_GetItem(nmesh->faces, i);
1543                         mface_from_data(newmf, 0, newmc, (NMFace *) mf);
1544                         Py_DECREF(mf);
1545                                 
1546                         newmf++;
1547                         if (newmc) newmc++;
1548                 }
1549         }
1550         return 1;
1551 }
1552
1553
1554
1555 static char NMeshmodule_PutRaw_doc[]=
1556 "(mesh, [name, renormal]) - Return a raw mesh to Blender\n\
1557 \n\
1558 (mesh) The NMesh object to store\n\
1559 [name] The mesh to replace\n\
1560 [renormal=1] Flag to control vertex normal recalculation\n\
1561 \n\
1562 If the name of a mesh to replace is not given a new\n\
1563 object is created and returned.";
1564
1565 static PyObject *NMeshmodule_PutRaw(PyObject *self, PyObject *args) 
1566 {
1567         char *name= NULL;
1568         Mesh *mesh= NULL;
1569         Object *ob= NULL;
1570         NMesh *nmesh;
1571         int recalc_normals= 1;
1572         
1573         BPY_TRY(PyArg_ParseTuple(args, "O!|si", &NMesh_Type, &nmesh, &name, &recalc_normals));
1574         
1575         if (!PySequence_Check(nmesh->verts))
1576                 return BPY_err_ret_ob(PyExc_AttributeError, "nmesh vertices are not a sequence");
1577         if (!PySequence_Check(nmesh->faces))
1578                 return BPY_err_ret_ob(PyExc_AttributeError, "nmesh faces are not a sequence");
1579         if (!PySequence_Check(nmesh->materials))
1580                 return BPY_err_ret_ob(PyExc_AttributeError, "nmesh materials are not a sequence");
1581
1582         if (!BPY_check_sequence_consistency(nmesh->verts, &NMVert_Type))
1583                 return BPY_err_ret_ob(PyExc_AttributeError, "nmesh vertices must be NMVerts");
1584         if (!BPY_check_sequence_consistency(nmesh->faces, &NMFace_Type))
1585                 return BPY_err_ret_ob(PyExc_AttributeError, "nmesh faces must be NMFaces");
1586         
1587         if (name) 
1588                 mesh= (Mesh *) getFromList(getMeshList(), name);
1589         /* returns new mesh if not found */
1590         
1591         if(!mesh || mesh->id.us==0) {
1592                 ob= add_object(OB_MESH);
1593                 if (!ob) {
1594                         PyErr_SetString(PyExc_RuntimeError, "Fatal: could not create mesh object");
1595                         return 0;
1596                 }
1597                 if (mesh)
1598                         set_mesh(ob, mesh);
1599                 else
1600                         mesh= (Mesh *) ob->data;
1601         }
1602         if(name) new_id(getMeshList(), &mesh->id, name);
1603         
1604         unlink_existingMeshdata(mesh);
1605         convert_NMeshToMesh(mesh, nmesh);
1606         nmesh->mesh = mesh;
1607
1608         if(recalc_normals)
1609                 vertexnormals_mesh(mesh, 0);
1610
1611         mesh_update(mesh);
1612         
1613         if (!during_script())
1614                 allqueue(REDRAWVIEW3D, 0);
1615
1616         // OK...this requires some explanation:
1617         // Materials can be assigned two ways:
1618         // a) to the object data (in this case, the mesh)
1619         // b) to the Object
1620         //      
1621         // Case a) is wanted, if Mesh data should be shared among objects,
1622         // as well as its materials (up to 16)
1623         // Case b) is wanted, when Mesh data should be shared, but not the
1624         // materials. For example, you want several checker boards sharing their
1625         // mesh data, but having different colors. So you would assign material
1626         // index 0 to all even, index 1 to all odd faces and bind the materials
1627         // to the Object instead (MaterialButtons: [OB] button "link materials to object")
1628         //
1629         // This feature implies that pointers to materials can be stored in
1630         // an object or a mesh. The number of total materials MUST be
1631         // synchronized (ob->totcol <-> mesh->totcol). We avoid the dangerous
1632         // direct access by calling blenderkernel/material.c:assign_material().
1633
1634         // The flags setting the material binding is found in ob->colbits, where 
1635         // each bit indicates the binding PER MATERIAL 
1636
1637         if (ob) { // we created a new object
1638                 NMesh_assignMaterials_toObject(nmesh, ob);
1639                 return DataBlock_fromData(ob);
1640         } else {
1641                 RETURN_INC(Py_None);
1642         }       
1643 }
1644
1645 #undef MethodDef
1646 #define MethodDef(func) {#func, NMeshmodule_##func, METH_VARARGS, NMeshmodule_##func##_doc}
1647
1648 static struct PyMethodDef NMeshmodule_methods[] = {
1649 // These should be: Mesh.Col, Mesh.Vert, Mesh.Face in fure
1650 // -- for ownership reasons
1651         MethodDef(Col),
1652         MethodDef(Vert),
1653         MethodDef(Face),
1654         MethodDef(New),
1655         MethodDef(GetRaw),
1656         MethodDef(GetRawFromObject),
1657         MethodDef(PutRaw),
1658         {NULL, NULL}
1659 };
1660 #undef BPY_ADDCONST
1661 #define BPY_ADDCONST(dict, name) insertConst(dict, #name, PyInt_FromLong(TF_##name))
1662
1663 /* set constants for face drawing mode -- see drawmesh.c */
1664
1665 static void init_NMeshConst(PyObject *d)
1666 {
1667         insertConst(d, "BILLBOARD", PyInt_FromLong(TF_BILLBOARD2));
1668         //BPY_ADDCONST(d, BILLBOARD);
1669         insertConst(d, "ALL", PyInt_FromLong(0xffff));
1670         BPY_ADDCONST(d, DYNAMIC);
1671         BPY_ADDCONST(d, INVISIBLE);
1672         insertConst(d, "HALO", PyInt_FromLong(TF_BILLBOARD));
1673         BPY_ADDCONST(d, LIGHT);
1674         BPY_ADDCONST(d, OBCOL);
1675         BPY_ADDCONST(d, SHADOW);
1676         BPY_ADDCONST(d, SHAREDVERT);
1677         BPY_ADDCONST(d, SHAREDCOL);
1678         BPY_ADDCONST(d, TEX);
1679         BPY_ADDCONST(d, TILES);
1680         BPY_ADDCONST(d, TWOSIDE);
1681 /* transparent modes */
1682         BPY_ADDCONST(d, SOLID);
1683         BPY_ADDCONST(d, ADD);
1684         BPY_ADDCONST(d, ALPHA);
1685         BPY_ADDCONST(d, SUB);
1686 /* TFACE flags */
1687         BPY_ADDCONST(d, SELECT);
1688         BPY_ADDCONST(d, HIDE);
1689         BPY_ADDCONST(d, ACTIVE);
1690 }
1691
1692 PyObject *init_py_nmesh(void) 
1693 {
1694         PyObject *d;
1695         PyObject *mod= Py_InitModule(SUBMODULE(NMesh), NMeshmodule_methods);
1696         PyObject *dict= PyModule_GetDict(mod);
1697
1698         NMesh_Type.ob_type= &PyType_Type;       
1699         NMVert_Type.ob_type= &PyType_Type;      
1700         NMFace_Type.ob_type= &PyType_Type;      
1701         NMCol_Type.ob_type= &PyType_Type;       
1702         
1703         d = ConstObject_New();
1704         PyDict_SetItemString(dict, "Const" , d);
1705         init_NMeshConst(d);
1706
1707         g_nmeshmodule = mod;
1708         return mod;
1709 }
1710
1711 #ifdef SHAREDMODULE
1712 void initNMesh(void) 
1713 {
1714         init_py_nmesh();
1715 }
1716 #endif