- added Mesh->derived and Mesh->decimated DerivedMesh pointers
[blender.git] / source / blender / python / api2_2x / NMesh.c
1 /* 
2  * $Id$
3  *
4  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. The Blender
10  * Foundation also sells licenses for use in proprietary software under
11  * the Blender License.  See http://www.blender.org/BL/ for information
12  * about this.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * Inc., 59 Temple Place - Suite 330, Boston, MA        02111-1307, USA.
22  *
23  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
24  * All rights reserved.
25  *
26  * This is a new part of Blender.
27  *
28  * Contributor(s): Willian P. Germano, Jordi Rovira i Bonet, Joseph Gilbert,
29  * Bala Gi, Alexander Szakaly, Stephane Soppera, Campbell Barton
30  *
31  * ***** END GPL/BL DUAL LICENSE BLOCK *****
32  */
33
34 #include "NMesh.h"
35
36 #include "DNA_key_types.h"
37 #include "DNA_listBase.h"
38 #include "DNA_object_types.h"
39 #include "DNA_material_types.h"
40 #include "DNA_armature_types.h"
41 #include "DNA_scene_types.h"
42
43 #include "BDR_editface.h"       /* make_tfaces */
44 #include "BIF_editdeform.h"
45 #include "BIF_editkey.h"        /* insert_meshkey */
46 #include "BIF_editmesh.h"       /* vertexnormals_mesh() : still needed???*/
47 #include "BIF_meshtools.h"   /* current loc of vertexnormals_mesh() */
48 #include "BIF_space.h"
49 #include "BKE_deform.h"
50 #include "BKE_mesh.h"
51 #include "BKE_main.h"
52 #include "BKE_global.h"
53 #include "BKE_library.h"
54 #include "BKE_displist.h"
55 #include "BKE_DerivedMesh.h"
56 #include "BKE_screen.h"
57 #include "BKE_object.h"
58 #include "BLI_blenlib.h"
59 #include "BLI_arithb.h"
60 #include "MEM_guardedalloc.h"
61
62 #include "blendef.h"
63 #include "mydevice.h"
64
65 #include "Object.h"
66 #include "vector.h"
67 #include "constant.h"
68 #include "gen_utils.h"
69
70 /* only used for ob.oopsloc at the moment */
71 #include "DNA_oops_types.h"
72 #include "DNA_space_types.h"
73
74 /* EXPP Mesh defines */
75
76 #define EXPP_NMESH_MODE_NOPUNOFLIP              ME_NOPUNOFLIP
77 #define EXPP_NMESH_MODE_TWOSIDED                ME_TWOSIDED
78 #define EXPP_NMESH_MODE_AUTOSMOOTH              ME_AUTOSMOOTH
79 #define EXPP_NMESH_MODE_SUBSURF                 ME_SUBSURF
80 #define EXPP_NMESH_MODE_OPTIMAL                 ME_OPT_EDGES
81
82 #define NMESH_FRAME_MAX                         18000
83 #define NMESH_SMOOTHRESH                        30
84 #define NMESH_SMOOTHRESH_MIN                    1
85 #define NMESH_SMOOTHRESH_MAX                    80
86 #define NMESH_SUBDIV                            1
87 #define NMESH_SUBDIV_MIN                        0
88 #define NMESH_SUBDIV_MAX                        6
89
90 /* Globals */
91 static PyObject *g_nmeshmodule = NULL;
92
93 static int unlink_existingMeshData( Mesh * mesh );
94 static int convert_NMeshToMesh( Mesh *mesh, BPy_NMesh *nmesh, int store_edges );
95 static PyObject *NMesh_printDebug( PyObject * self );
96 static PyObject *NMesh_addEdge( PyObject * self, PyObject * args );
97 static PyObject *NMesh_findEdge( PyObject * self, PyObject * args );
98 static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args );
99 static PyObject *NMesh_addEdgesData( PyObject * self );
100 static PyObject *NMesh_addFace( PyObject * self, PyObject * args );
101 static PyObject *NMesh_removeFace( PyObject * self, PyObject * args );
102 static PyObject *NMesh_addVertGroup( PyObject * self, PyObject * args );
103 static PyObject *NMesh_removeVertGroup( PyObject * self, PyObject * args );
104 static PyObject *NMesh_assignVertsToGroup( PyObject * self, PyObject * args );
105 static PyObject *NMesh_removeVertsFromGroup( PyObject * self,PyObject * args );
106 static PyObject *NMesh_getVertsFromGroup( PyObject * self, PyObject * args );
107 static PyObject *NMesh_renameVertGroup( PyObject * self, PyObject * args );
108 static PyObject *NMesh_getVertGroupNames( PyObject * self );
109 static PyObject *NMesh_transform (PyObject *self, PyObject *args);
110
111 static char NMesh_printDebug_doc[] =
112   "print debug info about the mesh.";
113
114 static char NMesh_addEdge_doc[] =
115   "create an edge between two vertices.\n\
116 If an edge already exists between those vertices, it is returned.\n\
117 (In Blender, only zero or one edge can link two vertices.)\n\
118 Created edge is automatically added to edges list.";
119
120 static char NMesh_findEdge_doc[] =
121   "find an edge between two vertices.";
122
123 static char NMesh_removeEdge_doc[] =
124   "remove an edge between two vertices.\n\
125 All faces using this edge are removed from faces list.";
126
127 static char NMesh_addEdgesData_doc[] =
128   "add edges data to the mesh.";
129
130 static char NMesh_addFace_doc[] =
131   "add a face to face list and add to edge list (if edge data exists) necessary edges.";
132
133 static char NMesh_removeFace_doc[] =
134   "remove a face for face list and remove edges no more used by any other face (if \
135 edge data exists).";
136
137 static char NMesh_addVertGroup_doc[] =
138         "add a named and empty vertex(deform) Group to a mesh that has been linked\n\
139 to an object. ";
140
141 static char NMesh_removeVertGroup_doc[] =
142         "remove a named vertex(deform) Group from a mesh that has been linked\n\
143 to an object.  Will remove all verts assigned to group.";
144
145 static char NMesh_assignVertsToGroup_doc[] =
146         "Adds an array (a python list) of vertex points (by index) to a named\n\
147 vertex group.  The list will have an associated wieght assigned to them.\n\
148 The weight represents the amount of influence this group has over these\n\
149 vertex points. Weights should be in the range of 0.0 - 1.0.\n\
150 The assignmode can be either 'add', 'subtract', or 'replace'.  If this vertex\n\
151 is not assigned to the group 'add' creates a new association with the weight\n\
152 specified, otherwise the weight given is added to the current weight of the\n\
153 vertex.\n\
154 'subtract' will attempt to subtract the weight passed from a vertex already\n\
155 associated with a group, else it does nothing. 'replace' attempts to replace\n\
156 the weight with the new weight value for an already associated vertex/group,\n\
157 else it does nothing. The mesh must have all it's vertex points set before\n\
158 attempting to assign any vertex points to a vertex group.";
159
160 static char NMesh_removeVertsFromGroup_doc[] =
161         "Remove an array (a python list) of vertex points from a named group in a\n\
162 mesh that has been linked to an object. If no list is given this will remove\n\
163 all vertex point associations with the group passed";
164
165 static char NMesh_getVertsFromGroup_doc[] =
166         "By passing a python list of vertex indices and a named group, this will\n\
167 return a python list representing the indeces that are a part of this vertex.\n\
168 group. If no association was found for the index passed nothing will be\n\
169 return for the index. An optional flag will also return the weights as well";
170
171 static char NMesh_renameVertGroup_doc[] = "Renames a vertex group";
172
173 static char NMesh_getVertGroupNames_doc[] =
174         "Returns a list of all the vertex group names";
175
176 static char M_NMesh_doc[] = "The Blender.NMesh submodule";
177
178 static char M_NMesh_Col_doc[] = "([r, g, b, a]) - Get a new mesh color\n\n\
179 [r=255, g=255, b=255, a=255] Specify the color components";
180
181 static char M_NMesh_Face_doc[] =
182         "(vertexlist = None) - Get a new face, and pass optional vertex list";
183
184 static char NMFace_append_doc[] =
185         "(vert) - appends Vertex 'vert' to face vertex list";
186
187 static char M_NMesh_Vert_doc[] = "([x, y, z]) - Get a new vertice\n\n\
188 [x, y, z] Specify new coordinates";
189
190 static char NMesh_getMaterials_doc[] =
191         "(i = -1) - Get this mesh's list of materials.\n\
192 (i = -1) - int: determines the list's contents:\n\
193 -1: return the current list, possibly modified by the script (default);\n\
194  0: get a fresh list from the Blender mesh -- modifications not included,\n\
195     unless the script called mesh.update() first;\n\
196  1: like 0, but does not ignore empty slots, returns them as 'None'.";
197
198 static char NMesh_setMaterials_doc[] =
199         "(matlist) - Set this mesh's list of materials.  This method makes sure\n\
200 the passed matlist is valid (can only include up to 16 materials and None's).";
201
202 static char NMesh_addMaterial_doc[] =
203         "(material) - add a new Blender Material 'material' to this Mesh's materials\n\
204 list.";
205
206 static char NMesh_insertKey_doc[] =
207         "(frame = None, type = 'relative') - inserts a Mesh key at the given frame\n\
208 if called without arguments, it inserts the key at the current Scene frame.\n\
209 (type) - 'relative' or 'absolute'.  Only relevant on the first call to this\n\
210 function for each nmesh.";
211
212 static char NMesh_removeAllKeys_doc[] =
213         "() - removes all keys from this mesh\n\
214 returns True if successful or False if this NMesh wasn't linked to a real\n\
215 Blender Mesh yet or the Mesh had no keys";
216
217 static char NMesh_getSelectedFaces_doc[] =
218         "(flag = None) - returns list of selected Faces\n\
219 If flag = 1, return indices instead";
220
221 static char NMesh_getActiveFace_doc[] =
222         "returns the index of the active face ";
223
224 static char NMesh_hasVertexUV_doc[] =
225         "(flag = None) - returns 1 if Mesh has per vertex UVs ('Sticky')\n\
226 The optional argument sets the Sticky flag";
227
228 static char NMesh_hasFaceUV_doc[] =
229         "(flag = None) - returns 1 if Mesh has textured faces\n\
230 The optional argument sets the textured faces flag";
231
232 static char NMesh_hasVertexColours_doc[] =
233         "(flag = None) - returns 1 if Mesh has vertex colours.\n\
234 The optional argument sets the vertex colour flag";
235
236 static char NMesh_getVertexInfluences_doc[] =
237         "Return a list of the influences of bones in the vertex \n\
238 specified by index. The list contains pairs with the \n\
239 bone name and the weight.";
240
241 static char NMesh_update_doc[] =
242 "(recalc_normals = 0, store_edges = 0, vertex_shade = 0) - Updates the Mesh.\n\
243 Optional arguments: if given and nonzero:\n\
244 'recalc_normals': normal vectors are recalculated;\n\
245 'store_edges': edges data is stored.\n\
246 'vertex_shade': vertex colors are added based on the current lamp setup.";
247
248 static char NMesh_getMode_doc[] =
249         "() - get the mode flags of this nmesh as an or'ed int value.";
250
251 static char NMesh_setMode_doc[] =
252         "(int or none to 5 strings) - set the mode flags of this nmesh.\n\
253 () - unset all flags.";
254
255 static char NMesh_getMaxSmoothAngle_doc[] =
256         "() - get the max smooth angle for mesh auto smoothing.";
257
258 static char NMesh_setMaxSmoothAngle_doc[] =
259         "(int) - set the max smooth angle for mesh auto smoothing in the range\n\
260 [1,80] in degrees.";
261
262 static char NMesh_getSubDivLevels_doc[] =
263         "() - get the subdivision levels for display and rendering: [display, render]";
264
265 static char NMesh_setSubDivLevels_doc[] =
266         "([int, int]) - set the subdivision levels for [display, render] -- they are\n\
267 clamped to the range [0,6].";
268
269 static char M_NMesh_New_doc[] =
270         "() - returns a new, empty NMesh mesh object\n";
271
272 static char M_NMesh_GetRaw_doc[] = "([name]) - Get a raw mesh from Blender\n\n\
273 [name] Name of the mesh to be returned\n\n\
274 If name is not specified a new empty mesh is\n\
275 returned, otherwise Blender returns an existing\n\
276 mesh.";
277
278 static char M_NMesh_GetRawFromObject_doc[] =
279         "(name) - Get the raw mesh used by a Blender object\n\n\
280 (name) Name of the object to get the mesh from\n\n\
281 This returns the mesh as used by the object, which\n\
282 means it contains all deformations and modifications.";
283
284 static char M_NMesh_PutRaw_doc[] =
285         "(mesh, name = None, recalc_normals = 1, store_edges = 0]) -\n\
286 Return a raw mesh to Blender\n\n\
287 (mesh) The NMesh object to store\n\
288 [name] The mesh to replace\n\
289 [recalc_normals = 1] Flag to control vertex normal recalculation\n\
290 [store_edges=0] Store edges data in the blender mesh\n\
291 If the name of a mesh to replace is not given a new\n\
292 object is created and returned.";
293
294 static char NMesh_transform_doc[] =
295         "(matrix, recalc_normals = 0) - Transform the mesh by the supplied 4x4\n\
296 matrix.\n\
297 (recalc_normals) - if given and 1 or True, transforming the vertex normals\n\
298 is skipped.";
299
300
301 void mesh_update( Mesh * mesh )
302 {
303         edge_drawflags_mesh( mesh );
304         tex_space_mesh( mesh );
305 }
306
307 /*****************************/
308 /*                      Mesh Color Object                */
309 /*****************************/
310
311 static void NMCol_dealloc( PyObject * self )
312 {
313         PyObject_DEL( self );
314 }
315
316 static BPy_NMCol *newcol( char r, char g, char b, char a )
317 {
318         BPy_NMCol *mc = ( BPy_NMCol * ) PyObject_NEW( BPy_NMCol, &NMCol_Type );
319
320         mc->r = r;
321         mc->g = g;
322         mc->b = b;
323         mc->a = a;
324
325         return mc;
326 }
327
328 static PyObject *M_NMesh_Col( PyObject * self, PyObject * args )
329 {
330         short r = 255, g = 255, b = 255, a = 255;
331
332         if( PyArg_ParseTuple( args, "|hhhh", &r, &g, &b, &a ) )
333                 return ( PyObject * ) newcol( r, g, b, a );
334
335         return NULL;
336 }
337
338 static PyObject *NMCol_getattr( PyObject * self, char *name )
339 {
340         BPy_NMCol *mc = ( BPy_NMCol * ) self;
341
342         if( strcmp( name, "r" ) == 0 )
343                 return Py_BuildValue( "i", mc->r );
344         else if( strcmp( name, "g" ) == 0 )
345                 return Py_BuildValue( "i", mc->g );
346         else if( strcmp( name, "b" ) == 0 )
347                 return Py_BuildValue( "i", mc->b );
348         else if( strcmp( name, "a" ) == 0 )
349                 return Py_BuildValue( "i", mc->a );
350         else if( strcmp( name, "__members__" ) == 0 )
351                 return Py_BuildValue( "[s,s,s,s]", "r", "g", "b", "a" );
352
353         return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
354 }
355
356 static int NMCol_setattr( PyObject * self, char *name, PyObject * v )
357 {
358         BPy_NMCol *mc = ( BPy_NMCol * ) self;
359         short ival;
360
361         if( !PyArg_Parse( v, "h", &ival ) )
362                 return -1;
363
364         ival = ( short ) EXPP_ClampInt( ival, 0, 255 );
365
366         if( strcmp( name, "r" ) == 0 )
367                 mc->r = ival;
368         else if( strcmp( name, "g" ) == 0 )
369                 mc->g = ival;
370         else if( strcmp( name, "b" ) == 0 )
371                 mc->b = ival;
372         else if( strcmp( name, "a" ) == 0 )
373                 mc->a = ival;
374         else
375                 return -1;
376
377         return 0;
378 }
379
380 static PyObject *NMCol_repr( BPy_NMCol * self )
381 {
382         static char s[256];
383         sprintf( s, "[NMCol - <%d, %d, %d, %d>]", self->r, self->g, self->b,
384                  self->a );
385         return Py_BuildValue( "s", s );
386 }
387
388 PyTypeObject NMCol_Type = {
389         PyObject_HEAD_INIT( NULL ) 0,   /* ob_size */
390         "Blender NMCol",        /* tp_name */
391         sizeof( BPy_NMCol ),    /* tp_basicsize */
392         0,                      /* tp_itemsize */
393         /* methods */
394         ( destructor ) NMCol_dealloc,   /* tp_dealloc */
395         ( printfunc ) 0,        /* tp_print */
396         ( getattrfunc ) NMCol_getattr,  /* tp_getattr */
397         ( setattrfunc ) NMCol_setattr,  /* tp_setattr */
398         0,                      /* tp_compare */
399         ( reprfunc ) NMCol_repr,        /* tp_repr */
400         0,                      /* tp_as_number */
401         0,                      /* tp_as_sequence */
402         0,                      /* tp_as_mapping */
403         0,                      /* tp_hash */
404         0,                      /* tp_as_number */
405         0,                      /* tp_as_sequence */
406         0,                      /* tp_as_mapping */
407         0,                      /* tp_hash */
408         0,0,0,0,0,0,0,0,0,0,0,0,0,0,
409         0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* up to tp_del to avoid a warning */
410 };
411
412 /*****************************/
413 /*              NMesh Python Object              */
414 /*****************************/
415 static void NMFace_dealloc( PyObject * self )
416 {
417         BPy_NMFace *mf = ( BPy_NMFace * ) self;
418
419         Py_DECREF( mf->v );
420         Py_DECREF( mf->uv );
421         Py_DECREF( mf->col );
422
423         PyObject_DEL( self );
424 }
425
426 static PyObject *new_NMFace( PyObject * vertexlist )
427 {
428         BPy_NMFace *mf = PyObject_NEW( BPy_NMFace, &NMFace_Type );
429         PyObject *vlcopy;
430
431         if( vertexlist ) {      /* create a copy of the given vertex list */
432                 PyObject *item;
433                 int i, len = PyList_Size( vertexlist );
434
435                 vlcopy = PyList_New( len );
436
437                 if( !vlcopy )
438                         return EXPP_ReturnPyObjError( PyExc_MemoryError,
439                                                       "couldn't create PyList" );
440
441                 for( i = 0; i < len; i++ ) {
442                         item = PySequence_GetItem( vertexlist, i );     /* PySequence increfs */
443
444                         if( item )
445                                 PyList_SET_ITEM( vlcopy, i, item );
446                         else
447                                 return EXPP_ReturnPyObjError
448                                         ( PyExc_RuntimeError,
449                                           "couldn't get vertex from a PyList" );
450                 }
451         } else                  /* create an empty vertex list */
452                 vlcopy = PyList_New( 0 );
453
454         mf->v = vlcopy;
455         mf->uv = PyList_New( 0 );
456         mf->image = NULL;
457         mf->mode = TF_DYNAMIC + TF_TEX;
458         mf->flag = TF_SELECT;
459         mf->transp = TF_SOLID;
460         mf->col = PyList_New( 0 );
461
462         mf->mf_flag = 0;
463         mf->mat_nr = 0;
464
465         return ( PyObject * ) mf;
466 }
467
468 static PyObject *M_NMesh_Face( PyObject * self, PyObject * args )
469 {
470         PyObject *vertlist = NULL;
471
472         if( !PyArg_ParseTuple( args, "|O!", &PyList_Type, &vertlist ) )
473                 return EXPP_ReturnPyObjError( PyExc_TypeError,
474                                               "expected a list of vertices or nothing as argument" );
475
476 /*      if (!vertlist) vertlist = PyList_New(0); */
477
478         return new_NMFace( vertlist );
479 }
480
481 static PyObject *NMFace_append( PyObject * self, PyObject * args )
482 {
483         PyObject *vert;
484         BPy_NMFace *f = ( BPy_NMFace * ) self;
485
486         if( !PyArg_ParseTuple( args, "O!", &NMVert_Type, &vert ) )
487                 return EXPP_ReturnPyObjError( PyExc_TypeError,
488                                               "expected an NMVert object" );
489
490         PyList_Append( f->v, vert );
491
492         return EXPP_incr_ret( Py_None );
493 }
494
495 #undef MethodDef
496 #define MethodDef(func) {#func, NMFace_##func, METH_VARARGS, NMFace_##func##_doc}
497
498 static struct PyMethodDef NMFace_methods[] = {
499         MethodDef( append ),
500         {NULL, NULL, 0, NULL}
501 };
502
503 static PyObject *NMFace_getattr( PyObject * self, char *name )
504 {
505         BPy_NMFace *mf = ( BPy_NMFace * ) self;
506
507         if( strcmp( name, "v" ) == 0 )
508                 return Py_BuildValue( "O", mf->v );
509         else if( strcmp( name, "col" ) == 0 )
510                 return Py_BuildValue( "O", mf->col );
511         else if( strcmp( name, "mat" ) == 0 )   // emulation XXX
512                 return Py_BuildValue( "i", mf->mat_nr );
513         else if( strcmp( name, "materialIndex" ) == 0 )
514                 return Py_BuildValue( "i", mf->mat_nr );
515         else if( strcmp( name, "smooth" ) == 0 )
516                 return Py_BuildValue( "i", (mf->mf_flag & ME_SMOOTH) ? 1:0 );
517         else if( strcmp( name, "sel" ) == 0 )
518                 return Py_BuildValue( "i", (mf->mf_flag & ME_FACE_SEL) ? 1:0 );
519         else if( strcmp( name, "hide" ) == 0 )
520                 return Py_BuildValue( "i", (mf->mf_flag & ME_HIDE) ? 1:0 );
521
522         else if( strcmp( name, "image" ) == 0 ) {
523                 if( mf->image )
524                         return Image_CreatePyObject( mf->image );
525                 else
526                         return EXPP_incr_ret( Py_None );
527         }
528
529         else if( strcmp( name, "mode" ) == 0 )
530                 return Py_BuildValue( "i", mf->mode );
531         else if( strcmp( name, "flag" ) == 0 )
532                 return Py_BuildValue( "i", mf->flag );
533         else if( strcmp( name, "transp" ) == 0 )
534                 return Py_BuildValue( "i", mf->transp );
535         else if( strcmp( name, "uv" ) == 0 )
536                 return Py_BuildValue( "O", mf->uv );
537
538         else if( ( strcmp( name, "normal" ) == 0 )
539                  || ( strcmp( name, "no" ) == 0 ) ) {
540
541                 if( EXPP_check_sequence_consistency( mf->v, &NMVert_Type ) ==
542                     1 ) {
543
544                         float fNormal[3] = { 0.0, 0.0, 0.0 };
545                         float *vco[4] = { NULL, NULL, NULL, NULL };
546                         int nSize = PyList_Size( mf->v );
547                         int loop;
548
549                         if( nSize != 3 && nSize != 4 )
550                                 return EXPP_ReturnPyObjError
551                                         ( PyExc_AttributeError,
552                                           "face must contain either 3 or 4 verts" );
553
554                         for( loop = 0; loop < nSize; loop++ ) {
555                                 BPy_NMVert *v =
556                                         ( BPy_NMVert * ) PyList_GetItem( mf->v,
557                                                                          loop );
558                                 vco[loop] = ( float * ) v->co;
559                         }
560
561                         if( nSize == 4 )
562                                 CalcNormFloat4( vco[0], vco[1], vco[2], vco[3],
563                                                 fNormal );
564                         else
565                                 CalcNormFloat( vco[0], vco[1], vco[2],
566                                                fNormal );
567
568                         return Py_BuildValue( "[f,f,f]", fNormal[0],
569                                               fNormal[1], fNormal[2] );
570                 } else          // EXPP_check_sequence_consistency failed
571                         return EXPP_ReturnPyObjError( PyExc_AttributeError,
572                                                       "this face does not contain a series of NMVerts" );
573         }
574
575         else if( strcmp( name, "__members__" ) == 0 )
576                 return Py_BuildValue( "[s,s,s,s,s,s,s,s,s,s,s,s,s]",
577                                       "v", "col", "mat", "materialIndex",
578                                       "smooth", "image", "mode", "flag",
579                                       "transp", "uv", "normal", "sel", "hide");
580         return Py_FindMethod( NMFace_methods, ( PyObject * ) self, name );
581 }
582
583 static int NMFace_setattr( PyObject * self, char *name, PyObject * v )
584 {
585         BPy_NMFace *mf = ( BPy_NMFace * ) self;
586         short ival;
587
588         if( strcmp( name, "v" ) == 0 ) {
589
590                 if( PySequence_Check( v ) ) {
591                         Py_DECREF( mf->v );
592                         mf->v = EXPP_incr_ret( v );
593
594                         return 0;
595                 }
596         } else if( strcmp( name, "col" ) == 0 ) {
597
598                 if( PySequence_Check( v ) ) {
599                         Py_DECREF( mf->col );
600                         mf->col = EXPP_incr_ret( v );
601
602                         return 0;
603                 }
604         } else if( !strcmp( name, "mat" ) || !strcmp( name, "materialIndex" ) ) {
605                 PyArg_Parse( v, "h", &ival );
606                 mf->mat_nr = ival;
607
608                 return 0;
609         } else if( strcmp( name, "smooth" ) == 0 ) {
610                 PyArg_Parse( v, "h", &ival );
611                 if (ival) mf->mf_flag |= ME_SMOOTH;
612                 else mf->mf_flag &= ~ME_SMOOTH;
613
614                 return 0;
615         } else if( strcmp( name, "sel" ) == 0 ) {
616                 PyArg_Parse( v, "h", &ival );
617                 if (ival) mf->mf_flag |= ME_FACE_SEL;
618                 else mf->mf_flag &= ~ME_FACE_SEL;
619
620                 return 0;
621         } else if( strcmp( name, "hide" ) == 0 ) {
622                 PyArg_Parse( v, "h", &ival );
623                 if (ival) mf->mf_flag |= ME_HIDE;
624                 else mf->mf_flag &= ~ME_HIDE;
625
626                 return 0;
627
628         } else if( strcmp( name, "uv" ) == 0 ) {
629
630                 if( PySequence_Check( v ) ) {
631                         Py_DECREF( mf->uv );
632                         mf->uv = EXPP_incr_ret( v );
633
634                         return 0;
635                 }
636         } else if( strcmp( name, "flag" ) == 0 ) {
637                 PyArg_Parse( v, "h", &ival );
638                 mf->flag = ival;
639
640                 return 0;
641         } else if( strcmp( name, "mode" ) == 0 ) {
642                 PyArg_Parse( v, "h", &ival );
643                 mf->mode = ival;
644
645                 return 0;
646         } else if( strcmp( name, "transp" ) == 0 ) {
647                 PyArg_Parse( v, "h", &ival );
648                 mf->transp = ival;
649
650                 return 0;
651         } else if( strcmp( name, "image" ) == 0 ) {
652                 PyObject *pyimg;
653                 if( !PyArg_Parse( v, "O!", &Image_Type, &pyimg ) )
654                         return EXPP_ReturnIntError( PyExc_TypeError,
655                                                     "expected image object" );
656
657                 if( pyimg == Py_None ) {
658                         mf->image = NULL;
659
660                         return 0;
661                 }
662
663                 mf->image = ( ( BPy_Image * ) pyimg )->image;
664
665                 return 0;
666         }
667
668         return EXPP_ReturnIntError( PyExc_AttributeError, name );
669 }
670
671 static PyObject *NMFace_repr( PyObject * self )
672 {
673         return PyString_FromString( "[NMFace]" );
674 }
675
676 static int NMFace_len( BPy_NMFace * self )
677 {
678         return PySequence_Length( self->v );
679 }
680
681 static PyObject *NMFace_item( BPy_NMFace * self, int i )
682 {
683         return PySequence_GetItem( self->v, i );        // new ref
684 }
685
686 static PyObject *NMFace_slice( BPy_NMFace * self, int begin, int end )
687 {
688         return PyList_GetSlice( self->v, begin, end );  // new ref
689 }
690
691 static PySequenceMethods NMFace_SeqMethods = {
692         ( inquiry ) NMFace_len, /* sq_length */
693         ( binaryfunc ) 0,       /* sq_concat */
694         ( intargfunc ) 0,       /* sq_repeat */
695         ( intargfunc ) NMFace_item,     /* sq_item */
696         ( intintargfunc ) NMFace_slice, /* sq_slice */
697         ( intobjargproc ) 0,    /* sq_ass_item */
698         ( intintobjargproc ) 0, /* sq_ass_slice */
699         0,0,0,
700 };
701
702 PyTypeObject NMFace_Type = {
703         PyObject_HEAD_INIT( NULL ) 0,   /*ob_size */
704         "Blender NMFace",       /*tp_name */
705         sizeof( BPy_NMFace ),   /*tp_basicsize */
706         0,                      /*tp_itemsize */
707         /* methods */
708         ( destructor ) NMFace_dealloc,  /*tp_dealloc */
709         ( printfunc ) 0,        /*tp_print */
710         ( getattrfunc ) NMFace_getattr, /*tp_getattr */
711         ( setattrfunc ) NMFace_setattr, /*tp_setattr */
712         0,                      /*tp_compare */
713         ( reprfunc ) NMFace_repr,       /*tp_repr */
714         0,                      /*tp_as_number */
715         &NMFace_SeqMethods,     /*tp_as_sequence */
716         0,                      /*tp_as_mapping */
717         0,                      /*tp_hash */
718         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
719         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* up to tp_del to avoid a warning */
720 };
721
722 static BPy_NMVert *newvert( float *co )
723 {
724         BPy_NMVert *mv = PyObject_NEW( BPy_NMVert, &NMVert_Type );
725
726         mv->co[0] = co[0];
727         mv->co[1] = co[1];
728         mv->co[2] = co[2];
729
730         mv->no[0] = mv->no[1] = mv->no[2] = 0.0;
731         mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0;
732         mv->flag = 0;
733
734         return mv;
735 }
736
737 static PyObject *M_NMesh_Vert( PyObject * self, PyObject * args )
738 {
739         float co[3] = { 0.0, 0.0, 0.0 };
740
741         if( !PyArg_ParseTuple( args, "|fff", &co[0], &co[1], &co[2] ) )
742                 return EXPP_ReturnPyObjError( PyExc_TypeError,
743                                               "expected three floats (or nothing) as arguments" );
744
745         return ( PyObject * ) newvert( co );
746 }
747
748 static void NMVert_dealloc( PyObject * self )
749 {
750         PyObject_DEL( self );
751 }
752
753 static PyObject *NMVert_getattr( PyObject * self, char *name )
754 {
755         BPy_NMVert *mv = ( BPy_NMVert * ) self;
756
757         if( !strcmp( name, "co" ) || !strcmp( name, "loc" ) )
758                 return newVectorProxy( mv->co, 3 );
759
760         else if( strcmp( name, "no" ) == 0 )
761                 return newVectorProxy( mv->no, 3 );
762         else if( strcmp( name, "uvco" ) == 0 )
763                 return newVectorProxy( mv->uvco, 3 );
764         else if( strcmp( name, "index" ) == 0 )
765                 return PyInt_FromLong( mv->index );
766         else if( strcmp( name, "sel" ) == 0 )
767                 return PyInt_FromLong( mv->flag & 1 );
768         else if( strcmp( name, "__members__" ) == 0 )
769                 return Py_BuildValue( "[s,s,s,s,s]", "co", "no", "uvco",
770                                       "index", "sel" );
771
772         return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
773 }
774
775 static int NMVert_setattr( PyObject * self, char *name, PyObject * v )
776 {
777         BPy_NMVert *mv = ( BPy_NMVert * ) self;
778         int i;
779
780         if( strcmp( name, "index" ) == 0 ) {
781                 PyArg_Parse( v, "i", &i );
782                 mv->index = i;
783                 return 0;
784         } else if( strcmp( name, "sel" ) == 0 ) {
785                 PyArg_Parse( v, "i", &i );
786                 mv->flag = i ? 1 : 0;
787                 return 0;
788         } else if( strcmp( name, "uvco" ) == 0 ) {
789
790                 if( !PyArg_ParseTuple( v, "ff|f",
791                                        &( mv->uvco[0] ), &( mv->uvco[1] ),
792                                        &( mv->uvco[2] ) ) )
793                         return EXPP_ReturnIntError( PyExc_AttributeError,
794                                                     "Vector tuple or triple expected" );
795
796                 return 0;
797         }
798
799         return EXPP_ReturnIntError( PyExc_AttributeError, name );
800 }
801
802 static int NMVert_len( BPy_NMVert * self )
803 {
804         return 3;
805 }
806
807 static PyObject *NMVert_item( BPy_NMVert * self, int i )
808 {
809         if( i < 0 || i >= 3 )
810                 return EXPP_ReturnPyObjError( PyExc_IndexError,
811                                               "array index out of range" );
812
813         return Py_BuildValue( "f", self->co[i] );
814 }
815
816 static PyObject *NMVert_slice( BPy_NMVert * self, int begin, int end )
817 {
818         PyObject *list;
819         int count;
820
821         if( begin < 0 )
822                 begin = 0;
823         if( end > 3 )
824                 end = 3;
825         if( begin > end )
826                 begin = end;
827
828         list = PyList_New( end - begin );
829
830         for( count = begin; count < end; count++ )
831                 PyList_SetItem( list, count - begin,
832                                 PyFloat_FromDouble( self->co[count] ) );
833
834         return list;
835 }
836
837 static int NMVert_ass_item( BPy_NMVert * self, int i, PyObject * ob )
838 {
839         if( i < 0 || i >= 3 )
840                 return EXPP_ReturnIntError( PyExc_IndexError,
841                                             "array assignment index out of range" );
842
843         if( !PyNumber_Check( ob ) )
844                 return EXPP_ReturnIntError( PyExc_IndexError,
845                                             "NMVert member must be a number" );
846
847         self->co[i] = PyFloat_AsDouble( ob );
848
849         return 0;
850 }
851
852 static int NMVert_ass_slice( BPy_NMVert * self, int begin, int end,
853                              PyObject * seq )
854 {
855         int count;
856
857         if( begin < 0 )
858                 begin = 0;
859         if( end > 3 )
860                 end = 3;
861         if( begin > end )
862                 begin = end;
863
864         if( !PySequence_Check( seq ) )
865                 EXPP_ReturnIntError( PyExc_TypeError,
866                                      "illegal argument type for built-in operation" );
867
868         if( PySequence_Length( seq ) != ( end - begin ) )
869                 EXPP_ReturnIntError( PyExc_TypeError,
870                                      "size mismatch in slice assignment" );
871
872         for( count = begin; count < end; count++ ) {
873                 PyObject *ob = PySequence_GetItem( seq, count );
874
875                 if( !PyArg_Parse( ob, "f", &self->co[count] ) ) {
876                         Py_DECREF( ob );
877                         return -1;
878                 }
879
880                 Py_DECREF( ob );
881         }
882
883         return 0;
884 }
885
886 static PySequenceMethods NMVert_SeqMethods = {
887         ( inquiry ) NMVert_len, /* sq_length */
888         ( binaryfunc ) 0,       /* sq_concat */
889         ( intargfunc ) 0,       /* sq_repeat */
890         ( intargfunc ) NMVert_item,     /* sq_item */
891         ( intintargfunc ) NMVert_slice, /* sq_slice */
892         ( intobjargproc ) NMVert_ass_item,      /* sq_ass_item */
893         ( intintobjargproc ) NMVert_ass_slice,  /* sq_ass_slice */
894         0,0,0,
895 };
896
897 PyTypeObject NMVert_Type = {
898         PyObject_HEAD_INIT( NULL ) 
899         0,      /*ob_size */
900         "Blender NMVert",       /*tp_name */
901         sizeof( BPy_NMVert ),   /*tp_basicsize */
902         0,                      /*tp_itemsize */
903         /* methods */
904         ( destructor ) NMVert_dealloc,  /*tp_dealloc */
905         ( printfunc ) 0,        /*tp_print */
906         ( getattrfunc ) NMVert_getattr, /*tp_getattr */
907         ( setattrfunc ) NMVert_setattr, /*tp_setattr */
908         0,                      /*tp_compare */
909         ( reprfunc ) 0,         /*tp_repr */
910         0,                      /*tp_as_number */
911         &NMVert_SeqMethods,     /*tp_as_sequence */
912         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
913         0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* tp_del */
914 };
915
916
917 /*****************************
918  * NMEdge
919  *****************************/
920
921 static BPy_NMEdge *new_NMEdge( BPy_NMVert * v1, BPy_NMVert * v2, char crease, short flag)
922 {
923   BPy_NMEdge *edge=NULL;
924
925   if (!v1 || !v2) return NULL;
926   if (!BPy_NMVert_Check(v1) || !BPy_NMVert_Check(v2)) return NULL;
927
928   edge = PyObject_NEW( BPy_NMEdge, &NMEdge_Type );
929
930   edge->v1=EXPP_incr_ret((PyObject*)v1);
931   edge->v2=EXPP_incr_ret((PyObject*)v2);
932   edge->flag=flag;
933   edge->crease=crease;
934
935   return edge;
936 }
937
938 static void NMEdge_dealloc( PyObject * self )
939 {
940   BPy_NMEdge *edge=(BPy_NMEdge *)self;
941
942   Py_DECREF(edge->v1);
943   Py_DECREF(edge->v2);
944
945   PyObject_DEL(self);
946 }
947
948 static PyObject *NMEdge_getattr( PyObject * self, char *name )
949 {
950   BPy_NMEdge *edge=(BPy_NMEdge *)self;
951
952   if      ( strcmp( name, "v1" ) == 0 )
953                 return EXPP_incr_ret( edge->v1 );
954   else if ( strcmp( name, "v2" ) == 0 )
955     return EXPP_incr_ret( edge->v2 );
956   else if ( strcmp( name, "flag" ) == 0 )
957     return PyInt_FromLong( edge->flag );
958   else if ( strcmp( name, "crease" ) == 0 )
959     return PyInt_FromLong( edge->crease );
960   else if( strcmp( name, "__members__" ) == 0 )
961     return Py_BuildValue( "[s,s,s,s]",
962                           "v1", "v2", "flag", "crease" );
963   
964   return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
965 }
966
967 static int NMEdge_setattr( PyObject * self, char *name, PyObject * v )
968 {
969   BPy_NMEdge *edge=(BPy_NMEdge *)self;
970
971   if ( strcmp( name, "flag" ) == 0 )
972   {
973     short flag=0;
974     if( !PyInt_Check( v ) )
975       return EXPP_ReturnIntError( PyExc_TypeError,
976                                   "expected int argument" );
977
978     flag = ( short ) PyInt_AsLong( v );
979
980     edge->flag = flag;
981
982     return 0;
983   }
984   else if ( strcmp( name, "crease" ) == 0 )
985   {
986     char crease=0;
987     if( !PyInt_Check( v ) )
988       return EXPP_ReturnIntError( PyExc_TypeError,
989                                   "expected int argument" );
990
991     crease = ( char ) PyInt_AsLong( v );
992
993     edge->crease = crease;
994
995     return 0;
996   }
997
998   return EXPP_ReturnIntError( PyExc_AttributeError, name );
999 }
1000
1001 PyTypeObject NMEdge_Type = {
1002         PyObject_HEAD_INIT( NULL ) 
1003         0,      /*ob_size */
1004         "Blender NMEdge",       /*tp_name */
1005         sizeof( BPy_NMEdge ),   /*tp_basicsize */
1006         0,                      /*tp_itemsize */
1007         /* methods */
1008         ( destructor ) NMEdge_dealloc,  /*tp_dealloc */
1009         ( printfunc ) 0,        /*tp_print */
1010         ( getattrfunc ) NMEdge_getattr, /*tp_getattr */
1011         ( setattrfunc ) NMEdge_setattr, /*tp_setattr */
1012         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1013         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1014         0,0,0,0,0,0,
1015 };
1016
1017 static void NMesh_dealloc( PyObject * self )
1018 {
1019         BPy_NMesh *me = ( BPy_NMesh * ) self;
1020
1021         Py_DECREF( me->name );
1022         Py_DECREF( me->verts );
1023         Py_DECREF( me->faces );
1024         Py_DECREF( me->materials );
1025         Py_XDECREF( me->edges );
1026
1027         PyObject_DEL( self );
1028 }
1029
1030 static PyObject *NMesh_getMaterials( PyObject * self, PyObject * args )
1031 {
1032         BPy_NMesh *nm = ( BPy_NMesh * ) self;
1033         PyObject *list = NULL;
1034         Mesh *me = nm->mesh;
1035         int all = -1;
1036
1037         if( !PyArg_ParseTuple( args, "|i", &all ) )
1038                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1039                                               "expected nothing or an int (bool) as argument" );
1040
1041         if( all >= 0 ) {
1042                 list = EXPP_PyList_fromMaterialList( me->mat, me->totcol,
1043                                                      all );
1044                 Py_DECREF( nm->materials );     /* update nmesh.materials attribute */
1045                 nm->materials = EXPP_incr_ret( list );
1046         } else
1047                 list = EXPP_incr_ret( nm->materials );
1048
1049         return list;
1050 }
1051
1052 static PyObject *NMesh_setMaterials( PyObject * self, PyObject * args )
1053 {
1054         BPy_NMesh *me = ( BPy_NMesh * ) self;
1055         PyObject *pymats = NULL;
1056
1057         if( !PyArg_ParseTuple( args, "O!", &PyList_Type, &pymats ) )
1058                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1059                                               "expected a list of materials (None's also accepted) as argument" );
1060
1061         if( !EXPP_check_sequence_consistency( pymats, &Material_Type ) )
1062                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1063                                               "list should only contain materials (None's also accepted)" );
1064
1065         if( PyList_Size( pymats ) > 16 )
1066                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1067                                               "list can't have more than 16 materials" );
1068
1069         Py_DECREF( me->materials );
1070         me->materials = EXPP_incr_ret( pymats );
1071
1072         return EXPP_incr_ret( Py_None );
1073 }
1074
1075 static PyObject *NMesh_addMaterial( PyObject * self, PyObject * args )
1076 {
1077         BPy_NMesh *me = ( BPy_NMesh * ) self;
1078         BPy_Material *pymat;
1079         Material *mat;
1080         PyObject *iter;
1081         int i, len = 0;
1082
1083         if( !PyArg_ParseTuple( args, "O!", &Material_Type, &pymat ) )
1084                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1085                                               "expected Blender Material PyObject" );
1086
1087         mat = pymat->material;
1088         len = PyList_Size( me->materials );
1089
1090         if( len >= 16 )
1091                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1092                                               "object data material lists can't have more than 16 materials" );
1093
1094         for( i = 0; i < len; i++ ) {
1095                 iter = PyList_GetItem( me->materials, i );
1096                 if( mat == Material_FromPyObject( iter ) )
1097                         return EXPP_ReturnPyObjError( PyExc_AttributeError,
1098                                                       "material already in the list" );
1099         }
1100
1101         PyList_Append( me->materials, ( PyObject * ) pymat );
1102
1103         return EXPP_incr_ret( Py_None );
1104 }
1105
1106 static PyObject *NMesh_removeAllKeys( PyObject * self, PyObject * args )
1107 {
1108         BPy_NMesh *nm = ( BPy_NMesh * ) self;
1109         Mesh *me = nm->mesh;
1110
1111         if( !PyArg_ParseTuple( args, "" ) )
1112                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1113                                               "this function expects no arguments" );
1114
1115         if( !me || !me->key )
1116                 return EXPP_incr_ret_False();
1117
1118         me->key->id.us--;
1119         me->key = 0;
1120
1121         return EXPP_incr_ret_True();
1122 }
1123
1124 static PyObject *NMesh_insertKey( PyObject * self, PyObject * args )
1125 {
1126         int fra = -1, oldfra = -1;
1127         char *type = NULL;
1128         short typenum;
1129         BPy_NMesh *nm = ( BPy_NMesh * ) self;
1130         Mesh *mesh = nm->mesh;
1131
1132         if( !PyArg_ParseTuple( args, "|is", &fra, &type ) )
1133                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1134                                               "expected nothing or an int and optionally a string as arguments" );
1135
1136         if( !type || !strcmp( type, "relative" ) )
1137                 typenum = 1;
1138         else if( !strcmp( type, "absolute" ) )
1139                 typenum = 2;
1140         else
1141                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
1142                                               "if given, type should be 'relative' or 'absolute'" );
1143
1144         if( fra > 0 ) {
1145                 fra = EXPP_ClampInt( fra, 1, NMESH_FRAME_MAX );
1146                 oldfra = G.scene->r.cfra;
1147                 G.scene->r.cfra = fra;
1148         }
1149
1150         if( !mesh )
1151                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1152                                               "update this NMesh first with its .update() method" );
1153
1154         insert_meshkey( mesh, typenum );
1155
1156         if( fra > 0 )
1157                 G.scene->r.cfra = oldfra;
1158
1159         return EXPP_incr_ret( Py_None );
1160 }
1161
1162 static PyObject *NMesh_getSelectedFaces( PyObject * self, PyObject * args )
1163 {
1164         BPy_NMesh *nm = ( BPy_NMesh * ) self;
1165         Mesh *me = nm->mesh;
1166         int flag = 0;
1167
1168         TFace *tf;
1169         int i;
1170         PyObject *l = PyList_New( 0 );
1171
1172         if( me == NULL )
1173                 return NULL;
1174
1175         tf = me->tface;
1176         if( tf == 0 )
1177                 return l;
1178
1179         if( !PyArg_ParseTuple( args, "|i", &flag ) )
1180                 return NULL;
1181
1182         if( flag ) {
1183                 for( i = 0; i < me->totface; i++ ) {
1184                         if( tf[i].flag & TF_SELECT )
1185                                 PyList_Append( l, PyInt_FromLong( i ) );
1186                 }
1187         } else {
1188                 for( i = 0; i < me->totface; i++ ) {
1189                         if( tf[i].flag & TF_SELECT )
1190                                 PyList_Append( l,
1191                                                PyList_GetItem( nm->faces,
1192                                                                i ) );
1193                 }
1194         }
1195         return l;
1196 }
1197
1198 static PyObject *NMesh_getActiveFace( PyObject * self )
1199 {
1200         if( ( ( BPy_NMesh * ) self )->sel_face < 0 )
1201                 return EXPP_incr_ret( Py_None );
1202
1203         return Py_BuildValue( "i", ( ( BPy_NMesh * ) self )->sel_face );
1204 }
1205
1206 static PyObject *NMesh_hasVertexUV( PyObject * self, PyObject * args )
1207 {
1208         BPy_NMesh *me = ( BPy_NMesh * ) self;
1209         int flag = -1;
1210
1211         if( !PyArg_ParseTuple( args, "|i", &flag ) )
1212                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1213                                               "expected int argument (or nothing)" );
1214
1215         switch ( flag ) {
1216         case 0:
1217                 me->flags &= ~NMESH_HASVERTUV;
1218                 break;
1219         case 1:
1220                 me->flags |= NMESH_HASVERTUV;
1221                 break;
1222         default:
1223                 break;
1224         }
1225
1226         if( me->flags & NMESH_HASVERTUV )
1227                 return EXPP_incr_ret_True();
1228         else
1229                 return EXPP_incr_ret_False();
1230 }
1231
1232 static PyObject *NMesh_hasFaceUV( PyObject * self, PyObject * args )
1233 {
1234         BPy_NMesh *me = ( BPy_NMesh * ) self;
1235         int flag = -1;
1236
1237         if( !PyArg_ParseTuple( args, "|i", &flag ) )
1238                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1239                                               "expected int argument (or nothing)" );
1240
1241         switch ( flag ) {
1242         case 0:
1243                 me->flags &= ~NMESH_HASFACEUV;
1244                 break;
1245         case 1:
1246                 me->flags |= NMESH_HASFACEUV;
1247                 break;
1248         default:
1249                 break;
1250         }
1251
1252         if( me->flags & NMESH_HASFACEUV )
1253                 return EXPP_incr_ret_True();
1254         else
1255                 return EXPP_incr_ret_False();
1256 }
1257
1258 static PyObject *NMesh_hasVertexColours( PyObject * self, PyObject * args )
1259 {
1260         BPy_NMesh *me = ( BPy_NMesh * ) self;
1261         int flag = -1;
1262
1263         if( !PyArg_ParseTuple( args, "|i", &flag ) )
1264                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1265                                               "expected int argument (or nothing)" );
1266
1267         switch ( flag ) {
1268         case 0:
1269                 me->flags &= ~NMESH_HASMCOL;
1270                 break;
1271         case 1:
1272                 me->flags |= NMESH_HASMCOL;
1273                 break;
1274         default:
1275                 break;
1276         }
1277
1278         if( me->flags & NMESH_HASMCOL )
1279                 return EXPP_incr_ret_True();
1280         else
1281                 return EXPP_incr_ret_False();
1282 }
1283
1284 static PyObject *NMesh_update( PyObject *self, PyObject *a, PyObject *kwd )
1285 {
1286         BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
1287         Mesh *mesh = nmesh->mesh;
1288         int recalc_normals = 0, store_edges = 0, vertex_shade = 0;
1289         static char *kwlist[] = {"recalc_normals", "store_edges",
1290                 "vertex_shade", NULL};
1291         int needs_redraw = 1;
1292
1293         if (!PyArg_ParseTupleAndKeywords(a, kwd, "|iii", kwlist, &recalc_normals,
1294                 &store_edges, &vertex_shade ) )
1295                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
1296             "expected nothing or one to three bool(s) (0 or 1) as argument" );
1297
1298         if( mesh ) {
1299                 unlink_existingMeshData( mesh );
1300                 convert_NMeshToMesh( mesh, nmesh, store_edges );
1301         } else {
1302                 nmesh->mesh = Mesh_fromNMesh( nmesh, store_edges );
1303                 mesh = nmesh->mesh;
1304         }
1305
1306         if( recalc_normals )
1307                 vertexnormals_mesh( mesh, 0 );
1308
1309         mesh_update( mesh );
1310
1311         nmesh_updateMaterials( nmesh );
1312
1313         if( nmesh->name && nmesh->name != Py_None )
1314                 new_id( &( G.main->mesh ), &mesh->id,
1315                         PyString_AsString( nmesh->name ) );
1316
1317         if (vertex_shade) {
1318                 Base *base = FIRSTBASE;
1319
1320                 if (!nmesh->object)
1321                         return EXPP_ReturnPyObjError(PyExc_RuntimeError,
1322                 "link this mesh to an object first with ob.link(mesh)" );
1323
1324                 if (G.obedit)
1325                         return EXPP_ReturnPyObjError(PyExc_RuntimeError,
1326                 "can't shade vertices while in edit mode" );
1327
1328                 while (base) {
1329                         if (base->object == nmesh->object) {
1330                                 base->flag |= SELECT;
1331                                 nmesh->object->flag = base->flag;
1332                                 set_active_base (base);
1333                                 needs_redraw = 0; /* already done in make_vertexcol */
1334                                 break;
1335                         }
1336                         base = base->next;
1337                 }
1338                 make_vertexcol();
1339
1340                 countall();
1341         }
1342
1343         if( !during_script(  ) && needs_redraw)
1344                 EXPP_allqueue( REDRAWVIEW3D, 0 );
1345
1346         return PyInt_FromLong( 1 );
1347 }
1348
1349 /** Implementation of the python method getVertexInfluence for an NMesh object.
1350  * This method returns a list of pairs (string,float) with bone names and
1351  * influences that this vertex receives.
1352  * @author Jordi Rovira i Bonet
1353  */
1354 static PyObject *NMesh_getVertexInfluences( PyObject * self, PyObject * args )
1355 {
1356         int index;
1357         PyObject *influence_list = NULL;
1358
1359         /* Get a reference to the mesh object wrapped in here. */
1360         Mesh *me = ( ( BPy_NMesh * ) self )->mesh;
1361
1362         if( !me )
1363                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1364                                               "unlinked nmesh: call its .update() method first" );
1365
1366         /* Parse the parameters: only on integer (vertex index) */
1367         if( !PyArg_ParseTuple( args, "i", &index ) )
1368                 return EXPP_ReturnPyObjError( PyExc_TypeError,
1369                                               "expected int argument (index of the vertex)" );
1370
1371         /* Proceed only if we have vertex deformation information and index is valid */
1372         if( me->dvert ) {
1373                 if( ( index >= 0 ) && ( index < me->totvert ) ) {
1374
1375                         int i;
1376                         MDeformWeight *sweight = NULL;
1377
1378                         /* Number of bones influencing the vertex */
1379                         int totinfluences = me->dvert[index].totweight;
1380
1381                         /* Build the list only with weights and names of the influent bones */
1382                         /*influence_list = PyList_New(totinfluences); */
1383                         influence_list = PyList_New( 0 );
1384
1385                         /* Get the reference of the first weight structure */
1386                         sweight = me->dvert[index].dw;
1387
1388                         for( i = 0; i < totinfluences; i++ ) {
1389
1390                                 /*Add the weight and the name of the bone, which is used to identify it */
1391
1392                                 if( sweight->data )
1393                                         /* valid bone: return its name */
1394                                         /*  PyList_SetItem(influence_list, i,
1395                                            Py_BuildValue("[sf]", sweight->data->name, sweight->weight));
1396                                            else // NULL bone: return Py_None instead
1397                                            PyList_SetItem(influence_list, i,
1398                                            Py_BuildValue("[Of]", Py_None, sweight->weight)); */
1399                                         PyList_Append( influence_list,
1400                                                        Py_BuildValue( "[sf]",
1401                                                                       sweight->
1402                                                                       data->
1403                                                                       name,
1404                                                                       sweight->
1405                                                                       weight ) );
1406
1407                                 /* Next weight */
1408                                 sweight++;
1409                         }
1410                 } else          //influence_list = PyList_New(0);
1411                         return EXPP_ReturnPyObjError( PyExc_IndexError,
1412                                                       "vertex index out of range" );
1413         } else
1414                 influence_list = PyList_New( 0 );
1415
1416         return influence_list;
1417 }
1418
1419 Mesh *Mesh_fromNMesh( BPy_NMesh * nmesh , int store_edges )
1420 {
1421         Mesh *mesh = NULL;
1422         mesh = add_mesh(  );
1423
1424         if( !mesh )
1425                 EXPP_ReturnPyObjError( PyExc_RuntimeError,
1426                                        "FATAL: could not create mesh object" );
1427
1428         mesh->id.us = 0;        /* no user yet */
1429         G.totmesh++;
1430         convert_NMeshToMesh( mesh, nmesh, store_edges );
1431
1432         return mesh;
1433 }
1434
1435 static PyObject *NMesh_getMaxSmoothAngle( BPy_NMesh * self )
1436 {
1437         PyObject *attr = PyInt_FromLong( self->smoothresh );
1438
1439         if( attr )
1440                 return attr;
1441
1442         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1443                                       "couldn't get NMesh.maxSmoothAngle attribute" );
1444 }
1445
1446 static PyObject *NMesh_setMaxSmoothAngle( PyObject * self, PyObject * args )
1447 {
1448         short value = 0;
1449         BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
1450
1451         if( !PyArg_ParseTuple( args, "h", &value ) )
1452                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
1453                                               "expected an int in [1, 80] as argument" );
1454
1455         nmesh->smoothresh =
1456                 ( short ) EXPP_ClampInt( value, NMESH_SMOOTHRESH_MIN,
1457                                          NMESH_SMOOTHRESH_MAX );
1458
1459         Py_INCREF( Py_None );
1460         return Py_None;
1461 }
1462
1463 static PyObject *NMesh_getSubDivLevels( BPy_NMesh * self )
1464 {
1465         PyObject *attr =
1466                 Py_BuildValue( "[h,h]", self->subdiv[0], self->subdiv[1] );
1467
1468         if( attr )
1469                 return attr;
1470
1471         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1472                                       "couldn't get NMesh.subDivLevels attribute" );
1473 }
1474
1475 static PyObject *NMesh_setSubDivLevels( PyObject * self, PyObject * args )
1476 {
1477         short display = 0, render = 0;
1478         BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
1479
1480         if( !PyArg_ParseTuple( args, "(hh)", &display, &render ) )
1481                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
1482                                               "expected a sequence [int, int] as argument" );
1483
1484         nmesh->subdiv[0] =
1485                 ( short ) EXPP_ClampInt( display, NMESH_SUBDIV_MIN,
1486                                          NMESH_SUBDIV_MAX );
1487
1488         nmesh->subdiv[1] =
1489                 ( short ) EXPP_ClampInt( render, NMESH_SUBDIV_MIN,
1490                                          NMESH_SUBDIV_MAX );
1491
1492         Py_INCREF( Py_None );
1493         return Py_None;
1494 }
1495
1496 static PyObject *NMesh_getMode( BPy_NMesh * self )
1497 {
1498         PyObject *attr = PyInt_FromLong( self->mode );
1499
1500         if( attr )
1501                 return attr;
1502
1503         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1504                                       "couldn't get NMesh.mode attribute" );
1505 }
1506
1507 static PyObject *NMesh_setMode( PyObject * self, PyObject * args )
1508 {
1509         BPy_NMesh *nmesh = ( BPy_NMesh * ) self;
1510         PyObject *arg1 = NULL;
1511         char *m[5] = { NULL, NULL, NULL, NULL, NULL };
1512         short i, mode = 0;
1513
1514         if( !PyArg_ParseTuple ( args, "|Ossss", &arg1, &m[1], &m[2], &m[3], &m[4] ) )
1515                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
1516                         "expected an int or from none to 5 strings as argument(s)" );
1517
1518         if (arg1) {
1519                 if (PyInt_Check(arg1)) {
1520                         mode = (short)PyInt_AsLong(arg1);
1521                 }
1522                 else if (PyString_Check(arg1)) {
1523                         m[0] = PyString_AsString(arg1);
1524                         for( i = 0; i < 5; i++ ) {
1525                                 if( !m[i] ) break;
1526                                 else if( strcmp( m[i], "NoVNormalsFlip" ) == 0 )
1527                                         mode |= EXPP_NMESH_MODE_NOPUNOFLIP;
1528                                 else if( strcmp( m[i], "TwoSided" ) == 0 )
1529                                         mode |= EXPP_NMESH_MODE_TWOSIDED;
1530                                 else if( strcmp( m[i], "AutoSmooth" ) == 0 )
1531                                         mode |= EXPP_NMESH_MODE_AUTOSMOOTH;
1532                                 else if( strcmp( m[i], "SubSurf" ) == 0 )
1533                                         mode |= EXPP_NMESH_MODE_SUBSURF;
1534                                 else if( strcmp( m[i], "Optimal" ) == 0 )
1535                                         mode |= EXPP_NMESH_MODE_OPTIMAL;
1536                                 else if( m[i][0] == '\0' )
1537                                         mode = 0;
1538                                 else
1539                                         return EXPP_ReturnPyObjError( PyExc_AttributeError,
1540                           "unknown NMesh mode" );
1541                         }
1542                 }
1543                 else return EXPP_ReturnPyObjError( PyExc_AttributeError,
1544                         "expected an int or from none to 5 strings as argument(s)" );
1545         }
1546
1547         nmesh->mode = mode;
1548
1549         Py_INCREF( Py_None );
1550         return Py_None;
1551 }
1552
1553 /* METH_VARARGS: function(PyObject *self, PyObject *args) */
1554 #undef MethodDef
1555 #define MethodDef(func) {#func, NMesh_##func, METH_VARARGS, NMesh_##func##_doc}
1556
1557 static struct PyMethodDef NMesh_methods[] = {
1558         MethodDef( addEdge ),
1559         MethodDef( findEdge ),
1560         MethodDef( removeEdge ),
1561         MethodDef( addFace ),
1562         MethodDef( removeFace ),
1563         MethodDef( addVertGroup ),
1564         MethodDef( removeVertGroup ),
1565         MethodDef( assignVertsToGroup ),
1566         MethodDef( removeVertsFromGroup ),
1567         MethodDef( getVertsFromGroup ),
1568         MethodDef( renameVertGroup ),
1569         MethodDef( hasVertexColours ),
1570         MethodDef( hasFaceUV ),
1571         MethodDef( hasVertexUV ),
1572         MethodDef( getSelectedFaces ),
1573         MethodDef( getVertexInfluences ),
1574         MethodDef( getMaterials ),
1575         MethodDef( setMaterials ),
1576         MethodDef( addMaterial ),
1577         MethodDef( insertKey ),
1578         MethodDef( removeAllKeys ),
1579         MethodDef( setMode ),
1580         MethodDef( setMaxSmoothAngle ),
1581         MethodDef( setSubDivLevels ),
1582         MethodDef( transform ),
1583
1584 /* METH_NOARGS: function(PyObject *self) */
1585 #undef MethodDef
1586 #define MethodDef(func) {#func, (PyCFunction)NMesh_##func, METH_NOARGS,\
1587         NMesh_##func##_doc}
1588
1589         MethodDef( printDebug ),
1590         MethodDef( addEdgesData ),
1591         MethodDef( getVertGroupNames ),
1592         MethodDef( getActiveFace ),
1593         MethodDef( getMode ),
1594         MethodDef( getMaxSmoothAngle ),
1595         MethodDef( getSubDivLevels ),
1596
1597 /* METH_VARARGS | METH_KEYWORDS:
1598  * function(PyObject *self, PyObject *args, PyObject *keywords) */
1599 #undef MethodDef
1600 #define MethodDef(func) {#func, (PyCFunction)NMesh_##func,\
1601         METH_VARARGS | METH_KEYWORDS, NMesh_##func##_doc}
1602
1603         MethodDef( update ),
1604         {NULL, NULL, 0, NULL}
1605 };
1606
1607 static PyObject *NMesh_getattr( PyObject * self, char *name )
1608 {
1609         BPy_NMesh *me = ( BPy_NMesh * ) self;
1610
1611         if( strcmp( name, "name" ) == 0 )
1612                 return EXPP_incr_ret( me->name );
1613
1614         else if( strcmp( name, "mode" ) == 0 )
1615                 return PyInt_FromLong( me->mode );
1616
1617         else if( strcmp( name, "block_type" ) == 0 )    /* for compatibility */
1618                 return PyString_FromString( "NMesh" );
1619
1620         else if( strcmp( name, "materials" ) == 0 )
1621                 return EXPP_incr_ret( me->materials );
1622
1623         else if( strcmp( name, "verts" ) == 0 )
1624                 return EXPP_incr_ret( me->verts );
1625
1626         else if( strcmp( name, "maxSmoothAngle" ) == 0 )
1627                 return PyInt_FromLong( me->smoothresh );
1628
1629         else if( strcmp( name, "subDivLevels" ) == 0 )
1630                 return Py_BuildValue( "[h,h]", me->subdiv[0], me->subdiv[1] );
1631
1632         else if( strcmp( name, "users" ) == 0 ) {
1633                 if( me->mesh ) {
1634                         return PyInt_FromLong( me->mesh->id.us );
1635                 } else {        /* it's a free mesh: */
1636                         return Py_BuildValue( "i", 0 );
1637                 }
1638         }
1639
1640         else if( strcmp( name, "faces" ) == 0 )
1641                 return EXPP_incr_ret( me->faces );
1642
1643   else if( strcmp( name, "edges" ) == 0 )
1644   {
1645     if (me->edges)
1646       return EXPP_incr_ret( me->edges );
1647     else
1648       return EXPP_incr_ret( Py_None );
1649   }
1650         else if (strcmp(name, "oopsLoc") == 0) {
1651     if (G.soops) { 
1652                         Oops *oops = G.soops->oops.first;
1653       while(oops) {
1654         if(oops->type==ID_ME) {
1655           if ((Mesh *)oops->id == me->mesh) {
1656             return (Py_BuildValue ("ff", oops->x, oops->y));
1657           }
1658         }
1659         oops = oops->next;
1660       }      
1661     }
1662     Py_INCREF (Py_None);
1663     return (Py_None);
1664   }
1665   /* Select in the oops view only since it's a mesh */
1666   else if (strcmp(name, "oopsSel") == 0) {
1667     if (G.soops) {
1668       Oops *oops = G.soops->oops.first;
1669       while(oops) {
1670         if(oops->type==ID_ME) {
1671           if ((Mesh *)oops->id == me->mesh) {
1672             if (oops->flag & SELECT) {
1673                                                         return EXPP_incr_ret_True();
1674             } else {
1675                                                         return EXPP_incr_ret_False();
1676             }
1677           }
1678         }
1679         oops = oops->next;
1680       }
1681     }
1682     return EXPP_incr_ret(Py_None);
1683   }     
1684         else if( strcmp( name, "__members__" ) == 0 )
1685                 return Py_BuildValue( "[s,s,s,s,s,s,s,s,s,s]",
1686                                       "name", "materials", "verts", "users",
1687                                       "faces", "maxSmoothAngle",
1688                                       "subdivLevels", "edges", "oopsLoc", "oopsSel" );
1689
1690         return Py_FindMethod( NMesh_methods, ( PyObject * ) self, name );
1691 }
1692
1693 static int NMesh_setattr( PyObject * self, char *name, PyObject * v )
1694 {
1695         BPy_NMesh *me = ( BPy_NMesh * ) self;
1696
1697         if( !strcmp( name, "name" ) ) {
1698
1699                 if( !PyString_Check( v ) )
1700                         return EXPP_ReturnIntError( PyExc_TypeError,
1701                                                     "expected string argument" );
1702
1703                 Py_DECREF( me->name );
1704                 me->name = EXPP_incr_ret( v );
1705         }
1706
1707         else if( !strcmp( name, "mode" ) ) {
1708                 short mode;
1709
1710                 if( !PyInt_Check( v ) )
1711                         return EXPP_ReturnIntError( PyExc_TypeError,
1712                                                     "expected int argument" );
1713
1714                 mode = ( short ) PyInt_AsLong( v );
1715                 if( mode >= 0 )
1716                         me->mode = mode;
1717                 else
1718                         return EXPP_ReturnIntError( PyExc_ValueError,
1719                                                     "expected positive int argument" );
1720         }
1721
1722         else if( !strcmp( name, "verts" ) || !strcmp( name, "faces" ) ||
1723                  !strcmp( name, "materials" ) ) {
1724
1725                 if( PySequence_Check( v ) ) {
1726
1727                         if( strcmp( name, "materials" ) == 0 ) {
1728                                 Py_DECREF( me->materials );
1729                                 me->materials = EXPP_incr_ret( v );
1730                         } else if( strcmp( name, "verts" ) == 0 ) {
1731                                 Py_DECREF( me->verts );
1732                                 me->verts = EXPP_incr_ret( v );
1733                         } else {
1734                                 Py_DECREF( me->faces );
1735                                 me->faces = EXPP_incr_ret( v );
1736                         }
1737                 }
1738
1739                 else
1740                         return EXPP_ReturnIntError( PyExc_TypeError,
1741                                                     "expected a sequence" );
1742         }
1743
1744         else if( !strcmp( name, "maxSmoothAngle" ) ) {
1745                 short smoothresh = 0;
1746
1747                 if( !PyInt_Check( v ) )
1748                         return EXPP_ReturnIntError( PyExc_TypeError,
1749                                                     "expected int argument" );
1750
1751                 smoothresh = ( short ) PyInt_AsLong( v );
1752
1753                 me->smoothresh =
1754                         EXPP_ClampInt( smoothresh, NMESH_SMOOTHRESH_MIN,
1755                                        NMESH_SMOOTHRESH_MAX );
1756         }
1757
1758         else if( !strcmp( name, "subDivLevels" ) ) {
1759                 int subdiv[2] = { 0, 0 };
1760                 int i;
1761                 PyObject *tmp;
1762
1763                 if( !PySequence_Check( v ) || ( PySequence_Length( v ) != 2 ) )
1764                         return EXPP_ReturnIntError( PyExc_TypeError,
1765                                                     "expected a list [int, int] as argument" );
1766
1767                 for( i = 0; i < 2; i++ ) {
1768                         tmp = PySequence_GetItem( v, i );
1769                         if( tmp ) {
1770                                 if( !PyInt_Check( tmp ) ) {
1771                                         Py_DECREF( tmp );
1772                                         return EXPP_ReturnIntError
1773                                                 ( PyExc_TypeError,
1774                                                   "expected a list [int, int] as argument" );
1775                                 }
1776
1777                                 subdiv[i] = PyInt_AsLong( tmp );
1778                                 me->subdiv[i] =
1779                                         ( short ) EXPP_ClampInt( subdiv[i],
1780                                                                  NMESH_SUBDIV_MIN,
1781                                                                  NMESH_SUBDIV_MAX );
1782                                 Py_DECREF( tmp );
1783                         } else
1784                                 return EXPP_ReturnIntError( PyExc_RuntimeError,
1785                                                             "couldn't retrieve subdiv values from list" );
1786                 }
1787         }
1788   else if( strcmp( name, "edges" ) == 0 )
1789   {
1790     if (me->edges)
1791     {
1792       if (PySequence_Check(v))
1793       {
1794         Py_DECREF(me->edges);
1795         me->edges = EXPP_incr_ret( v );
1796       }
1797     }
1798     else
1799       return EXPP_ReturnIntError( PyExc_RuntimeError, 
1800                "mesh has no edge information" );
1801   }
1802   else if (!strcmp(name, "oopsLoc")) {
1803     if (G.soops) {
1804       Oops *oops = G.soops->oops.first;
1805       while(oops) {
1806         if(oops->type==ID_ME) {
1807           if ((Mesh *)oops->id == me->mesh) {
1808             return (!PyArg_ParseTuple  (v, "ff", &(oops->x),&(oops->y)));
1809           }
1810         }
1811         oops = oops->next;
1812       }
1813     }
1814     return 0;
1815   }
1816   /* Select in the oops view only since its a mesh */
1817   else if (!strcmp(name, "oopsSel")) {
1818     int sel;
1819     if (!PyArg_Parse (v, "i", &sel))
1820       return EXPP_ReturnIntError 
1821         (PyExc_TypeError, "expected an integer, 0 or 1");
1822     if (G.soops) {
1823       Oops *oops = G.soops->oops.first;
1824       while(oops) {
1825         if(oops->type==ID_ME) {
1826           if ((Mesh *)oops->id == me->mesh) {
1827             if(sel == 0) oops->flag &= ~SELECT;
1828             else oops->flag |= SELECT;
1829             return 0;
1830           }
1831         }
1832         oops = oops->next;
1833       }
1834     }
1835     return 0;
1836   }
1837         else
1838                 return EXPP_ReturnIntError( PyExc_AttributeError, name );
1839
1840         return 0;
1841 }
1842
1843 PyTypeObject NMesh_Type = {
1844         PyObject_HEAD_INIT( NULL ) 0,   /*ob_size */
1845         "Blender NMesh",        /*tp_name */
1846         sizeof( BPy_NMesh ),    /*tp_basicsize */
1847         0,                      /*tp_itemsize */
1848         /* methods */
1849         ( destructor ) NMesh_dealloc,   /*tp_dealloc */
1850         ( printfunc ) 0,        /*tp_print */
1851         ( getattrfunc ) NMesh_getattr,  /*tp_getattr */
1852         ( setattrfunc ) NMesh_setattr,  /*tp_setattr */
1853         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1854         0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1855 };
1856
1857 static BPy_NMFace *nmface_from_data( BPy_NMesh * mesh, int vidxs[4],
1858         char mat_nr, char flag, TFace * tface, MCol * col )
1859 {
1860         BPy_NMFace *newf = PyObject_NEW( BPy_NMFace, &NMFace_Type );
1861         int i, len;
1862
1863         if( vidxs[3] )
1864                 len = 4;
1865         else if( vidxs[2] )
1866                 len = 3;
1867         else
1868                 len = 2;
1869
1870         newf->v = PyList_New( len );
1871
1872         for( i = 0; i < len; i++ )
1873                 PyList_SetItem( newf->v, i,
1874                                 EXPP_incr_ret( PyList_GetItem
1875                                                ( mesh->verts, vidxs[i] ) ) );
1876
1877         if( tface ) {
1878                 newf->uv = PyList_New( len );   // per-face UV coordinates
1879
1880                 for( i = 0; i < len; i++ ) {
1881                         PyList_SetItem( newf->uv, i,
1882                                         Py_BuildValue( "(ff)", tface->uv[i][0],
1883                                                        tface->uv[i][1] ) );
1884                 }
1885
1886                 if( tface->tpage )      /* pointer to image per face: */
1887                         newf->image = ( Image * ) tface->tpage;
1888                 else
1889                         newf->image = NULL;
1890
1891                 newf->mode = tface->mode;       /* draw mode */
1892                 newf->flag = tface->flag;       /* select flag */
1893                 newf->transp = tface->transp;   /* transparency flag */
1894                 col = ( MCol * ) ( tface->col );        /* weird, tface->col is uint[4] */
1895         } else {
1896                 newf->mode = TF_DYNAMIC;        /* just to initialize it to something meaninful, */
1897                 /* since without tfaces there are no tface->mode's, obviously. */
1898                 newf->image = NULL;
1899                 newf->uv = PyList_New( 0 );
1900         }
1901
1902         newf->mat_nr = mat_nr;
1903         newf->mf_flag = flag; /* MFace flag */
1904
1905         if( col ) {
1906                 newf->col = PyList_New( 4 );
1907                 for( i = 0; i < 4; i++, col++ ) {
1908                         PyList_SetItem( newf->col, i,
1909                                         ( PyObject * ) newcol( col->b, col->g,
1910                                                                col->r,
1911                                                                col->a ) );
1912                 }
1913         } else
1914                 newf->col = PyList_New( 0 );
1915
1916         return newf;
1917 }
1918
1919 static BPy_NMEdge *nmedge_from_data( BPy_NMesh * mesh, MEdge *edge )
1920 {
1921   BPy_NMVert *v1=(BPy_NMVert *)PyList_GetItem( mesh->verts, edge->v1 );
1922   BPy_NMVert *v2=(BPy_NMVert *)PyList_GetItem( mesh->verts, edge->v2 );
1923   return new_NMEdge(v1, v2, edge->crease, edge->flag);
1924 }
1925
1926 static BPy_NMVert *nmvert_from_data( MVert * vert, MSticky * st, float *co,
1927         int idx, char flag )
1928 {
1929         BPy_NMVert *mv = PyObject_NEW( BPy_NMVert, &NMVert_Type );
1930
1931         mv->co[0] = co[0];
1932         mv->co[1] = co[1];
1933         mv->co[2] = co[2];
1934
1935         mv->no[0] = vert->no[0] / 32767.0;
1936         mv->no[1] = vert->no[1] / 32767.0;
1937         mv->no[2] = vert->no[2] / 32767.0;
1938
1939         if( st ) {
1940                 mv->uvco[0] = st->co[0];
1941                 mv->uvco[1] = st->co[1];
1942                 mv->uvco[2] = 0.0;
1943
1944         } else
1945                 mv->uvco[0] = mv->uvco[1] = mv->uvco[2] = 0.0;
1946
1947         mv->index = idx;
1948         mv->flag = flag & 1;
1949
1950         return mv;
1951 }
1952
1953 static int get_active_faceindex( Mesh * me )
1954 {
1955         TFace *tf;
1956         int i;
1957
1958         if( me == NULL )
1959                 return -1;
1960
1961         tf = me->tface;
1962         if( tf == 0 )
1963                 return -1;
1964
1965         for( i = 0; i < me->totface; i++ )
1966                 if( tf[i].flag & TF_ACTIVE )
1967                         return i;
1968
1969         return -1;
1970 }
1971
1972 static PyObject *new_NMesh_internal( Mesh * oldmesh,
1973                                      DispListMesh * dlm, float *extverts )
1974 {
1975         BPy_NMesh *me = PyObject_NEW( BPy_NMesh, &NMesh_Type );
1976         me->flags = 0;
1977         me->mode = EXPP_NMESH_MODE_TWOSIDED;    /* default for new meshes */
1978         me->subdiv[0] = NMESH_SUBDIV;
1979         me->subdiv[1] = NMESH_SUBDIV;
1980         me->smoothresh = NMESH_SMOOTHRESH;
1981   me->edges = NULL; /* no edge data by default */
1982
1983         me->object = NULL;      /* not linked to any object yet */
1984
1985         if( !oldmesh ) {
1986                 me->name = EXPP_incr_ret( Py_None );
1987                 me->materials = PyList_New( 0 );
1988                 me->verts = PyList_New( 0 );
1989                 me->faces = PyList_New( 0 );
1990                 me->mesh = 0;
1991         } else {
1992                 MVert *mverts;
1993                 MSticky *msticky;
1994                 MFace *mfaces;
1995                 TFace *tfaces;
1996                 MCol *mcols;
1997     MEdge *medges;
1998                 int i, totvert, totface, totedge;
1999
2000                 if( dlm ) {
2001                         me->name = EXPP_incr_ret( Py_None );
2002                         me->mesh = 0;
2003
2004                         msticky = NULL;
2005                         mfaces = NULL;
2006                         mverts = dlm->mvert;
2007                         mfaces = dlm->mface;
2008                         tfaces = dlm->tface;
2009                         mcols = dlm->mcol;
2010       medges = dlm->medge;
2011
2012                         totvert = dlm->totvert;
2013                         totface = dlm->totface;
2014       totedge = dlm->totedge;
2015                 } else {
2016                         me->name = PyString_FromString( oldmesh->id.name + 2 );
2017                         me->mesh = oldmesh;
2018                         me->mode = oldmesh->flag;       /* yes, we save the mesh flags in nmesh->mode */
2019                         me->subdiv[0] = oldmesh->subdiv;
2020                         me->subdiv[1] = oldmesh->subdivr;
2021                         me->smoothresh = oldmesh->smoothresh;
2022
2023                         msticky = oldmesh->msticky;
2024                         mverts = oldmesh->mvert;
2025                         mfaces = oldmesh->mface;
2026                         tfaces = oldmesh->tface;
2027                         mcols = oldmesh->mcol;
2028       medges = oldmesh->medge;
2029
2030                         totvert = oldmesh->totvert;
2031                         totface = oldmesh->totface;
2032       totedge = oldmesh->totedge;
2033
2034                         me->sel_face = get_active_faceindex( oldmesh );
2035                 }
2036
2037                 if( msticky )
2038                         me->flags |= NMESH_HASVERTUV;
2039                 if( tfaces )
2040                         me->flags |= NMESH_HASFACEUV;
2041                 if( mcols )
2042                         me->flags |= NMESH_HASMCOL;
2043
2044                 me->verts = PyList_New( totvert );
2045
2046                 for( i = 0; i < totvert; i++ ) {
2047                         MVert *oldmv = &mverts[i];
2048                         MSticky *oldst = msticky ? &msticky[i] : NULL;
2049                         float *vco = extverts ? &extverts[i * 3] : oldmv->co;
2050
2051                         PyList_SetItem( me->verts, i,
2052                                         ( PyObject * ) nmvert_from_data( oldmv,
2053                                                                          oldst,
2054                                                                          vco,
2055                                                                          i,
2056                                                                          oldmv->
2057                                                                          flag ) );
2058                 }
2059
2060                 me->faces = PyList_New( totface );
2061                 for( i = 0; i < totface; i++ ) {
2062                         TFace *oldtf = tfaces ? &tfaces[i] : NULL;
2063                         MCol *oldmc = mcols ? &mcols[i * 4] : NULL;
2064                         MFace *oldmf = &mfaces[i];
2065                         int vidxs[4];
2066                         vidxs[0] = oldmf->v1;
2067                         vidxs[1] = oldmf->v2;
2068                         vidxs[2] = oldmf->v3;
2069                         vidxs[3] = oldmf->v4;
2070
2071                         PyList_SetItem( me->faces, i,
2072                                         ( PyObject * ) nmface_from_data( me,
2073                                                                          vidxs,
2074                                                                          oldmf->
2075                                                                          mat_nr,
2076                                                                          oldmf->
2077                                                                          flag,
2078                                                                          oldtf,
2079                                                                          oldmc ) );
2080                 }
2081
2082     if (medges)
2083     {
2084       me->edges = PyList_New( totedge );
2085       for( i = 0; i < totedge; i++ )
2086       {
2087         MEdge *edge = &medges[i];
2088         PyList_SetItem( me->edges, i, (PyObject*)nmedge_from_data ( me, edge ) );
2089       }
2090     }
2091
2092                 me->materials =
2093                         EXPP_PyList_fromMaterialList( oldmesh->mat,
2094                                                       oldmesh->totcol, 0 );
2095         }
2096
2097         return ( PyObject * ) me;
2098 }
2099
2100 PyObject *new_NMesh( Mesh * oldmesh )
2101 {
2102         return new_NMesh_internal( oldmesh, NULL, NULL );
2103 }
2104
2105 static PyObject *M_NMesh_New( PyObject * self, PyObject * args )
2106 {
2107         char *name = NULL;
2108         PyObject *ret = NULL;
2109
2110         if( !PyArg_ParseTuple( args, "|s", &name ) )
2111                 return EXPP_ReturnPyObjError( PyExc_TypeError,
2112                                               "expected nothing or a string as argument" );
2113
2114         ret = new_NMesh( NULL );
2115
2116         if( ret && name ) {
2117                 BPy_NMesh *nmesh = ( BPy_NMesh * ) ret;
2118                 Py_DECREF( nmesh->name );
2119                 nmesh->name = PyString_FromString( name );
2120         }
2121
2122         return ret;
2123 }
2124
2125 static PyObject *M_NMesh_GetRaw( PyObject * self, PyObject * args )
2126 {
2127         char *name = NULL;
2128         Mesh *oldmesh = NULL;
2129
2130         if( !PyArg_ParseTuple( args, "|s", &name ) )
2131                 return EXPP_ReturnPyObjError( PyExc_TypeError,
2132                                               "expected string argument (or nothing)" );
2133
2134         if( name ) {
2135                 oldmesh = ( Mesh * ) GetIdFromList( &( G.main->mesh ), name );
2136
2137                 if( !oldmesh )
2138                         return EXPP_incr_ret( Py_None );
2139         }
2140
2141         return new_NMesh( oldmesh );
2142 }
2143
2144 /* Note: NMesh.GetRawFromObject gets the display list mesh from Blender:
2145  * the vertices are already transformed / deformed. */
2146 static PyObject *M_NMesh_GetRawFromObject( PyObject * self, PyObject * args )
2147 {
2148         char *name;
2149         Object *ob;
2150         PyObject *nmesh;
2151
2152         if( !PyArg_ParseTuple( args, "s", &name ) )
2153                 return EXPP_ReturnPyObjError( PyExc_TypeError,
2154                                               "expected string argument" );
2155
2156         ob = ( Object * ) GetIdFromList( &( G.main->object ), name );
2157
2158         if( !ob )
2159                 return EXPP_ReturnPyObjError( PyExc_AttributeError, name );
2160         else if( ob->type != OB_MESH )
2161                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
2162                                               "Object does not have Mesh data" );
2163         else {
2164                 Mesh *me = ( Mesh * ) ob->data;
2165                 DispList *dl;
2166
2167                 if( mesh_uses_displist( me ) ) {
2168                         DerivedMesh *dm = mesh_get_derived(ob);
2169                         DispListMesh *dlm = dm->convertToDispListMesh(dm);
2170                         nmesh = new_NMesh_internal( me, dlm, NULL );
2171                         displistmesh_free(dlm);
2172                 }
2173                 else if( ( dl = find_displist( &ob->disp, DL_VERTS ) ) )
2174                         nmesh = new_NMesh_internal( me, NULL, dl->verts );
2175                 else
2176                         nmesh = new_NMesh( me );
2177         }
2178
2179 /* @hack: to mark that (deformed) mesh is readonly, so the update function
2180  * will not try to write it. */
2181
2182         ( ( BPy_NMesh * ) nmesh )->mesh = 0;
2183
2184         return nmesh;
2185 }
2186
2187 static void mvert_from_data( MVert * mv, MSticky * st, BPy_NMVert * from )
2188 {
2189         mv->co[0] = from->co[0];
2190         mv->co[1] = from->co[1];
2191         mv->co[2] = from->co[2];
2192
2193         mv->no[0] = from->no[0] * 32767.0;
2194         mv->no[1] = from->no[1] * 32767.0;
2195         mv->no[2] = from->no[2] * 32767.0;
2196
2197         mv->flag = ( from->flag & 1 );
2198         mv->mat_nr = 0;
2199
2200         if( st ) {
2201                 st->co[0] = from->uvco[0];
2202                 st->co[1] = from->uvco[1];
2203         }
2204 }
2205
2206 /*@ TODO: this function is just a added hack. Don't look at the
2207  * RGBA/BRGA confusion, it just works, but will never work with
2208  * a restructured Blender */
2209
2210 static void assign_perFaceColors( TFace * tf, BPy_NMFace * from )
2211 {
2212         MCol *col;
2213         int i;
2214
2215         col = ( MCol * ) ( tf->col );
2216
2217         if( col ) {
2218                 int len = PySequence_Length( from->col );
2219
2220                 if( len > 4 )
2221                         len = 4;
2222
2223                 for( i = 0; i < len; i++, col++ ) {
2224                         BPy_NMCol *mc =
2225                                 ( BPy_NMCol * ) PySequence_GetItem( from->col,
2226                                                                     i );
2227                         if( !BPy_NMCol_Check( mc ) ) {
2228                                 Py_DECREF( mc );
2229                                 continue;
2230                         }
2231
2232                         col->r = mc->b;
2233                         col->b = mc->r;
2234                         col->g = mc->g;
2235                         col->a = mc->a;
2236
2237                         Py_DECREF( mc );
2238                 }
2239         }
2240 }
2241
2242 static int assignFaceUV( TFace * tf, BPy_NMFace * nmface )
2243 {
2244         PyObject *fuv, *tmp;
2245         int i;
2246
2247         fuv = nmface->uv;
2248         if( PySequence_Length( fuv ) == 0 )
2249                 return 0;
2250         /* fuv = [(u_1, v_1), ... (u_n, v_n)] */
2251         for( i = 0; i < PySequence_Length( fuv ); i++ ) {
2252                 tmp = PyList_GetItem( fuv, i ); /* stolen reference ! */
2253                 if( !PyArg_ParseTuple
2254                     ( tmp, "ff", &( tf->uv[i][0] ), &( tf->uv[i][1] ) ) )
2255                         return 0;
2256         }
2257         if( nmface->image ) {   /* image assigned ? */
2258                 tf->tpage = ( void * ) nmface->image;
2259         } else
2260                 tf->tpage = 0;
2261
2262         tf->mode = nmface->mode;        /* copy mode */
2263         tf->flag = nmface->flag;        /* copy flag */
2264         tf->transp = nmface->transp;    /* copy transp flag */
2265
2266         /* assign vertex colours */
2267         assign_perFaceColors( tf, nmface );
2268         return 1;
2269 }
2270
2271 static void mface_from_data( MFace * mf, TFace * tf, MCol * col,
2272                              BPy_NMFace * from )
2273 {
2274         BPy_NMVert *nmv;
2275
2276         int i = PyList_Size( from->v );
2277         if( i >= 1 ) {
2278                 nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 0 );
2279                 if( BPy_NMVert_Check( nmv ) && nmv->index != -1 )
2280                         mf->v1 = nmv->index;
2281                 else
2282                         mf->v1 = 0;
2283         }
2284         if( i >= 2 ) {
2285                 nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 1 );
2286                 if( BPy_NMVert_Check( nmv ) && nmv->index != -1 )
2287                         mf->v2 = nmv->index;
2288                 else
2289                         mf->v2 = 0;
2290         }
2291         if( i >= 3 ) {
2292                 nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 2 );
2293                 if( BPy_NMVert_Check( nmv ) && nmv->index != -1 )
2294                         mf->v3 = nmv->index;
2295                 else
2296                         mf->v3 = 0;
2297         }
2298         if( i >= 4 ) {
2299                 nmv = ( BPy_NMVert * ) PyList_GetItem( from->v, 3 );
2300                 if( BPy_NMVert_Check( nmv ) && nmv->index != -1 )
2301                         mf->v4 = nmv->index;
2302                 else
2303                         mf->v4 = 0;
2304         }
2305
2306         if( tf ) {
2307                 assignFaceUV( tf, from );
2308                 if( PyErr_Occurred(  ) ) {
2309                         PyErr_Print(  );
2310                         return;
2311                 }
2312
2313                 test_index_face( mf, tf, i );
2314         } else {
2315                 test_index_mface( mf, i );
2316         }
2317
2318         mf->puno = 0;
2319         mf->mat_nr = from->mat_nr;
2320         mf->edcode = 0;
2321         mf->flag = from->mf_flag;
2322
2323         if( col ) {
2324                 int len = PySequence_Length( from->col );
2325
2326                 if( len > 4 )
2327                         len = 4;
2328
2329                 for( i = 0; i < len; i++, col++ ) {
2330                         BPy_NMCol *mc =
2331                                 ( BPy_NMCol * ) PySequence_GetItem( from->col,
2332                                                                     i );
2333                         if( !BPy_NMCol_Check( mc ) ) {
2334                                 Py_DECREF( mc );
2335                                 continue;
2336                         }
2337
2338                         col->b = mc->r;
2339                         col->g = mc->g;
2340                         col->r = mc->b;
2341                         col->a = mc->a;
2342
2343                         Py_DECREF( mc );
2344                 }
2345         }
2346 }
2347
2348 /* check for a valid UV sequence */
2349 static int check_validFaceUV( BPy_NMesh * nmesh )
2350 {
2351         PyObject *faces;
2352         BPy_NMFace *nmface;
2353         int i, n;
2354
2355         faces = nmesh->faces;
2356         for( i = 0; i < PySequence_Length( faces ); i++ ) {
2357                 nmface = ( BPy_NMFace * ) PyList_GetItem( faces, i );
2358                 n = PySequence_Length( nmface->uv );
2359                 if( n != PySequence_Length( nmface->v ) ) {
2360                         if( n > 0 )
2361                                 printf( "Warning: different length of vertex and UV coordinate " "list in face!\n" );
2362                         return 0;
2363                 }
2364         }
2365         return 1;
2366 }
2367
2368 /* this is a copy of unlink_mesh in mesh.c, because ... */
2369 static void EXPP_unlink_mesh( Mesh * me )
2370 {
2371         int a;
2372
2373         if( me == 0 )
2374                 return;
2375
2376         for( a = 0; a < me->totcol; a++ ) {
2377                 if( me->mat[a] )
2378                         me->mat[a]->id.us--;
2379                 me->mat[a] = 0;
2380         }
2381
2382 /*      ... here we want to preserve mesh keys */
2383 /* if users want to get rid of them, they can use mesh.removeAllKeys() */
2384 /*
2385         if(me->key) me->key->id.us--;
2386         me->key= 0;
2387 */
2388         if( me->texcomesh )
2389                 me->texcomesh = 0;
2390
2391         me->totcol = 0;
2392 }
2393
2394 static int unlink_existingMeshData( Mesh * mesh )
2395 {
2396         freedisplist( &mesh->disp );
2397         EXPP_unlink_mesh( mesh );
2398         if( mesh->mvert )
2399                 MEM_freeN( mesh->mvert );
2400         if( mesh->medge ) {
2401                 MEM_freeN( mesh->medge );
2402                 mesh->totedge = 0;
2403         }
2404         if( mesh->mface )
2405                 MEM_freeN( mesh->mface );
2406         if( mesh->mcol )
2407                 MEM_freeN( mesh->mcol );
2408         if( mesh->msticky )
2409                 MEM_freeN( mesh->msticky );
2410         if( mesh->mat )
2411                 MEM_freeN( mesh->mat );
2412         if( mesh->tface )
2413                 MEM_freeN( mesh->tface );
2414         return 1;
2415 }
2416
2417 Material **nmesh_updateMaterials( BPy_NMesh * nmesh )
2418 {
2419         Material **matlist;
2420         Mesh *mesh = nmesh->mesh;
2421         int len = PyList_Size( nmesh->materials );
2422
2423         if( !mesh ) {
2424                 printf( "FATAL INTERNAL ERROR: illegal call to updateMaterials()\n" );
2425                 return 0;
2426         }
2427
2428         if( len > 0 ) {
2429                 matlist = EXPP_newMaterialList_fromPyList( nmesh->materials );
2430                 EXPP_incr_mats_us( matlist, len );
2431
2432                 if( mesh->mat )
2433                         MEM_freeN( mesh->mat );
2434
2435                 mesh->mat = matlist;
2436
2437         } else {
2438                 matlist = 0;
2439         }
2440         mesh->totcol = len;
2441
2442 /**@ This is another ugly fix due to the weird material handling of blender.
2443         * it makes sure that object material lists get updated (by their length)
2444         * according to their data material lists, otherwise blender crashes.
2445         * It just stupidly runs through all objects...BAD BAD BAD.
2446         */
2447         test_object_materials( ( ID * ) mesh );
2448
2449         return matlist;
2450 }
2451
2452 PyObject *NMesh_assignMaterials_toObject( BPy_NMesh * nmesh, Object * ob )
2453 {
2454         BPy_Material *pymat;
2455         Material *ma;
2456         int i;
2457         short old_matmask;
2458         Mesh *mesh = nmesh->mesh;
2459         int nmats;              /* number of mats == len(nmesh->materials) */
2460
2461         old_matmask = ob->colbits;      /*@ HACK: save previous colbits */
2462         ob->colbits = 0;        /* make assign_material work on mesh linked material */
2463
2464         nmats = PyList_Size( nmesh->materials );
2465
2466         if( nmats > 0 && !mesh->mat ) {
2467                 ob->totcol = nmats;
2468                 mesh->totcol = nmats;
2469                 mesh->mat =
2470                         MEM_callocN( sizeof( void * ) * nmats, "bpy_memats" );
2471
2472                 if( ob->mat )
2473                         MEM_freeN( ob->mat );
2474                 ob->mat =
2475                         MEM_callocN( sizeof( void * ) * nmats, "bpy_obmats" );
2476         }
2477
2478         for( i = 0; i < nmats; i++ ) {
2479                 pymat = ( BPy_Material * ) PySequence_GetItem( nmesh->
2480                                                                materials, i );
2481
2482                 if( Material_CheckPyObject( ( PyObject * ) pymat ) ) {
2483                         ma = pymat->material;
2484                         assign_material( ob, ma, i + 1 );       /*@ XXX don't use this function anymore */
2485                 } else {
2486                         Py_DECREF( pymat );
2487                         return EXPP_ReturnPyObjError( PyExc_TypeError,
2488                                                       "expected Material type in attribute list 'materials'!" );
2489                 }
2490
2491                 Py_DECREF( pymat );
2492         }
2493
2494         ob->colbits = old_matmask;      /*@ HACK */
2495
2496         ob->actcol = 1;
2497         return EXPP_incr_ret( Py_None );
2498 }
2499
2500 static void fill_medge_from_nmesh(Mesh * mesh, BPy_NMesh * nmesh)
2501 {
2502   int i,j;
2503   MEdge *faces_edges=NULL;
2504   int   tot_faces_edges=0;
2505   int tot_valid_faces_edges=0;
2506   int nmeshtotedges=PyList_Size(nmesh->edges);
2507   int tot_valid_nmedges=0;
2508   BPy_NMEdge **valid_nmedges=NULL;
2509
2510   valid_nmedges=MEM_callocN(nmeshtotedges*sizeof(BPy_NMEdge *), "make BPy_NMEdge");
2511
2512   /* First compute the list of edges that exists because faces exists */
2513   make_edges(mesh);
2514
2515   faces_edges=mesh->medge;
2516   tot_faces_edges=mesh->totedge;
2517   tot_valid_faces_edges=tot_faces_edges;
2518
2519   mesh->medge=NULL;
2520         mesh->totedge = 0;
2521
2522   /* Flag each edge in faces_edges that is already in nmesh->edges list.
2523    * Flaging an edge means MEdge v1=v2=0.
2524    * Each time an edge is flagged, tot_valid_faces_edges is decremented.
2525    *
2526    * Also store in valid_nmedges pointers to each valid NMEdge in nmesh->edges.
2527    * An invalid NMEdge is an edge that has a vertex that is not in the vertices 
2528    * list. Ie its index is -1. 
2529    * Each time an valid NMEdge is flagged, tot_valid_nmedges is incremented.
2530    */
2531   for( i = 0; i < nmeshtotedges; ++i )
2532   {
2533     int v1idx,v2idx;
2534     BPy_NMEdge *edge=( BPy_NMEdge *) PyList_GetItem(nmesh->edges, i);
2535     BPy_NMVert *v=(BPy_NMVert *)edge->v1;
2536     v1idx=v->index;
2537     v=(BPy_NMVert *)edge->v2;
2538     v2idx=v->index;
2539     if (-1 == v1idx || -1 == v2idx) continue;
2540     valid_nmedges[tot_valid_nmedges]=edge;
2541     ++tot_valid_nmedges;
2542     for( j = 0; j < tot_faces_edges; j++ )
2543     {
2544       MEdge *me=faces_edges+j;
2545       if ( ((int)me->v1==v1idx && (int)me->v2==v2idx) ||
2546            ((int)me->v1==v2idx && (int)me->v2==v1idx) )
2547       {
2548         me->v1=0; me->v2=0;
2549         --tot_valid_faces_edges;
2550       }
2551     }
2552   }
2553
2554   /* Now we have the total count of valid edges */
2555   mesh->totedge=tot_valid_nmedges+tot_valid_faces_edges;
2556   mesh->medge=MEM_callocN(mesh->totedge*sizeof(MEdge), "make mesh edges");
2557   for ( i = 0; i < tot_valid_nmedges; ++i )
2558   {
2559     BPy_NMEdge *edge=valid_nmedges[i];
2560     MEdge *medge=mesh->medge+i;
2561     int v1=((BPy_NMVert *)edge->v1)->index;
2562     int v2=((BPy_NMVert *)edge->v2)->index;
2563     medge->v1=v1;
2564     medge->v2=v2;
2565     medge->flag=edge->flag;
2566     medge->crease=edge->crease;
2567   }
2568   for ( i = 0, j = tot_valid_nmedges; i < tot_faces_edges; ++i )
2569   {
2570     MEdge *edge=faces_edges+i;
2571     if (edge->v1!=0 || edge->v2!=0)  // valid edge
2572     {
2573       MEdge *medge=mesh->medge+j;
2574       medge->v1=edge->v1;
2575       medge->v2=edge->v2;
2576       medge->flag=ME_EDGEDRAW;
2577       medge->crease=0;
2578       ++j;
2579     }
2580   }
2581
2582   MEM_freeN( valid_nmedges );
2583   MEM_freeN( faces_edges );
2584 }
2585
2586 static int convert_NMeshToMesh( Mesh * mesh, BPy_NMesh * nmesh, int store_edges)
2587 {
2588         MFace *newmf;
2589         TFace *newtf;
2590         MVert *newmv;
2591         MSticky *newst;
2592         MCol *newmc;
2593
2594         int i, j;
2595
2596         mesh->mvert = NULL;
2597         mesh->medge = NULL;
2598         mesh->mface = NULL;
2599         mesh->mcol = NULL;
2600         mesh->msticky = NULL;
2601         mesh->tface = NULL;
2602         mesh->mat = NULL;
2603   mesh->medge = NULL;
2604
2605         /* Minor note: we used 'mode' because 'flag' was already used internally
2606          * by nmesh */
2607         mesh->flag = nmesh->mode;
2608         mesh->smoothresh = nmesh->smoothresh;
2609         mesh->subdiv = nmesh->subdiv[0];
2610         mesh->subdivr = nmesh->subdiv[1];
2611
2612         /*@ material assignment moved to PutRaw */
2613         mesh->totvert = PySequence_Length( nmesh->verts );
2614         if( mesh->totvert ) {
2615                 if( nmesh->flags & NMESH_HASVERTUV )
2616                         mesh->msticky =
2617                                 MEM_callocN( sizeof( MSticky ) * mesh->totvert,
2618                                              "msticky" );
2619
2620                 mesh->mvert =
2621                         MEM_callocN( sizeof( MVert ) * mesh->totvert,
2622                                      "mverts" );
2623         }
2624
2625         if( mesh->totvert )
2626                 mesh->totface = PySequence_Length( nmesh->faces );
2627         else
2628                 mesh->totface = 0;
2629
2630         if( mesh->totface ) {
2631 /*@ only create vertcol array if mesh has no texture faces */
2632
2633 /*@ TODO: get rid of double storage of vertex colours. In a mesh,
2634  * vertex colors can be stored the following ways:
2635  * - per (TFace*)->col
2636  * - per (Mesh*)->mcol
2637  * This is stupid, but will reside for the time being -- at least until
2638  * a redesign of the internal Mesh structure */
2639
2640                 if( !( nmesh->flags & NMESH_HASFACEUV )
2641                     && ( nmesh->flags & NMESH_HASMCOL ) )
2642                         mesh->mcol =
2643                                 MEM_callocN( 4 * sizeof( MCol ) *
2644                                              mesh->totface, "mcol" );
2645
2646                 mesh->mface =
2647                         MEM_callocN( sizeof( MFace ) * mesh->totface,
2648                                      "mfaces" );
2649         }
2650
2651         /*@ This stuff here is to tag all the vertices referenced
2652          * by faces, then untag the vertices which are actually
2653          * in the vert list. Any vertices untagged will be ignored
2654          * by the mface_from_data function. It comes from my
2655          * screwed up decision to not make faces only store the
2656          * index. - Zr
2657          */
2658         for( i = 0; i < mesh->totface; i++ ) {
2659                 BPy_NMFace *mf =
2660                         ( BPy_NMFace * ) PySequence_GetItem( nmesh->faces, i );
2661
2662                 j = PySequence_Length( mf->v );
2663                 while( j-- ) {
2664                         BPy_NMVert *mv =
2665                                 ( BPy_NMVert * ) PySequence_GetItem( mf->v,
2666                                                                      j );
2667                         if( BPy_NMVert_Check( mv ) )
2668                                 mv->index = -1;
2669                         Py_DECREF( mv );
2670                 }
2671
2672                 Py_DECREF( mf );
2673         }
2674   /* do the same for edges if there is edge data */
2675   if (nmesh->edges)
2676   {
2677     int nmeshtotedges=PyList_Size(nmesh->edges);
2678     for( i = 0; i < nmeshtotedges; ++i )
2679     {
2680       BPy_NMEdge *edge=( BPy_NMEdge *) PyList_GetItem(nmesh->edges, i);
2681       BPy_NMVert *v=(BPy_NMVert *)edge->v1;
2682       v->index=-1;
2683       v=(BPy_NMVert *)edge->v2;
2684       v->index=-1;
2685     }
2686   }
2687
2688         for( i = 0; i < mesh->totvert; i++ ) {
2689                 BPy_NMVert *mv =
2690                         ( BPy_NMVert * ) PySequence_GetItem( nmesh->verts, i );
2691                 mv->index = i;
2692                 Py_DECREF( mv );
2693         }
2694
2695         newmv = mesh->mvert;
2696         newst = mesh->msticky;
2697         for( i = 0; i < mesh->totvert; i++ ) {
2698                 PyObject *mv = PySequence_GetItem( nmesh->verts, i );
2699                 mvert_from_data( newmv, newst, ( BPy_NMVert * ) mv );
2700                 Py_DECREF( mv );
2701
2702                 newmv++;
2703                 if( newst )
2704                         newst++;
2705         }
2706
2707 /*      assign per face texture UVs */
2708
2709         /* check face UV flag, then check whether there was one 
2710          * UV coordinate assigned, if yes, make tfaces */
2711         if( ( nmesh->flags & NMESH_HASFACEUV )
2712             || ( check_validFaceUV( nmesh ) ) ) {
2713                 make_tfaces( mesh );    /* initialize TFaces */
2714
2715                 newmc = mesh->mcol;
2716                 newmf = mesh->mface;
2717                 newtf = mesh->tface;
2718                 for( i = 0; i < mesh->totface; i++ ) {
2719                         PyObject *mf = PySequence_GetItem( nmesh->faces, i );
2720                         mface_from_data( newmf, newtf, newmc,
2721                                          ( BPy_NMFace * ) mf );
2722                         Py_DECREF( mf );
2723
2724                         newtf++;
2725                         newmf++;
2726                         if( newmc )
2727                                 newmc += 4;
2728                 }
2729
2730                 nmesh->flags |= NMESH_HASFACEUV;
2731         } else {
2732                 newmc = mesh->mcol;
2733                 newmf = mesh->mface;
2734
2735                 for( i = 0; i < mesh->totface; i++ ) {
2736                         PyObject *mf = PySequence_GetItem( nmesh->faces, i );
2737                         mface_from_data( newmf, 0, newmc,
2738                                          ( BPy_NMFace * ) mf );
2739                         Py_DECREF( mf );
2740
2741                         newmf++;
2742                         if( newmc )
2743                                 newmc += 4;     /* there are 4 MCol's per face */
2744                 }
2745         }
2746
2747   /* After face data has been written, write edge data.
2748    * Edge data are not stored before face ones since we need
2749    * mesh->mface to be correctly initialized.
2750    */
2751   if (nmesh->edges && store_edges)
2752   {
2753     fill_medge_from_nmesh(mesh, nmesh);
2754   }
2755
2756         return 1;
2757 }
2758
2759 static PyObject *M_NMesh_PutRaw( PyObject * self, PyObject * args )
2760 {
2761         char *name = NULL;
2762         Mesh *mesh = NULL;
2763         Object *ob = NULL;
2764         BPy_NMesh *nmesh;
2765         int recalc_normals = 1;
2766   int store_edges = 0;
2767
2768         if( !PyArg_ParseTuple( args, "O!|sii",
2769                                &NMesh_Type, &nmesh, &name, &recalc_normals, &store_edges ) )
2770                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
2771                                               "expected an NMesh object and optionally also a string and two ints" );
2772
2773         if( !PySequence_Check( nmesh->verts ) )
2774                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
2775                                               "nmesh vertices are not a sequence" );
2776         if( !PySequence_Check( nmesh->faces ) )
2777                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
2778                                               "nmesh faces are not a sequence" );
2779         if( !PySequence_Check( nmesh->materials ) )
2780                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
2781                                               "nmesh materials are not a sequence" );
2782
2783         if( EXPP_check_sequence_consistency( nmesh->verts, &NMVert_Type ) !=
2784             1 )
2785                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
2786                                               "nmesh vertices must be NMVerts" );
2787         if( EXPP_check_sequence_consistency( nmesh->faces, &NMFace_Type ) !=
2788             1 )
2789                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
2790                                               "nmesh faces must be NMFaces" );
2791
2792         if( name )
2793                 mesh = ( Mesh * ) GetIdFromList( &( G.main->mesh ), name );
2794
2795         if( !mesh || mesh->id.us == 0 ) {
2796                 ob = add_object( OB_MESH );
2797                 if( !ob ) {
2798                         PyErr_SetString( PyExc_RuntimeError,
2799                                          "Fatal: could not create mesh object" );
2800                         return 0;
2801                 }
2802
2803                 if( !mesh )
2804                         mesh = ( Mesh * ) ob->data;
2805                 else
2806                         set_mesh( ob, mesh );   // also does id.us++
2807         }
2808
2809         if( name )
2810                 new_id( &( G.main->mesh ), &mesh->id, name );
2811         else if( nmesh->name && nmesh->name != Py_None )
2812                 new_id( &( G.main->mesh ), &mesh->id,
2813                         PyString_AsString( nmesh->name ) );
2814
2815         unlink_existingMeshData( mesh );
2816         convert_NMeshToMesh( mesh, nmesh, store_edges );
2817         nmesh->mesh = mesh;
2818
2819         if( recalc_normals )
2820                 vertexnormals_mesh( mesh, 0 );
2821
2822         mesh_update( mesh );
2823
2824         if( !during_script(  ) )
2825                 EXPP_allqueue( REDRAWVIEW3D, 0 );
2826
2827         // @OK...this requires some explanation:
2828         // Materials can be assigned two ways:
2829         // a) to the object data (in this case, the mesh)
2830         // b) to the Object
2831         //
2832         // Case a) is wanted, if Mesh data should be shared among objects,
2833         // as well as its materials (up to 16)
2834         // Case b) is wanted, when Mesh data should be shared, but not the
2835         // materials. For example, you want several checker boards sharing their
2836         // mesh data, but having different colors. So you would assign material
2837         // index 0 to all even, index 1 to all odd faces and bind the materials
2838         // to the Object instead (MaterialButtons: [OB] "link materials to object")
2839         //
2840         // This feature implies that pointers to materials can be stored in
2841         // an object or a mesh. The number of total materials MUST be
2842         // synchronized (ob->totcol <-> mesh->totcol). We avoid the dangerous
2843         // direct access by calling blenderkernel/material.c:assign_material().
2844
2845         // The flags setting the material binding is found in ob->colbits, where 
2846         // each bit indicates the binding PER MATERIAL 
2847
2848         if( ob ) {              // we created a new object
2849                 nmesh->object = ob;     // linking so vgrouping methods know which obj to work on
2850                 NMesh_assignMaterials_toObject( nmesh, ob );
2851                 EXPP_synchronizeMaterialLists( ob );
2852                 return Object_CreatePyObject( ob );
2853         } else {
2854                 mesh->mat =
2855                         EXPP_newMaterialList_fromPyList( nmesh->materials );
2856                 EXPP_incr_mats_us( mesh->mat,
2857                                    PyList_Size( nmesh->materials ) );
2858                 return EXPP_incr_ret( Py_None );
2859         }
2860
2861 }
2862
2863 #undef MethodDef
2864 #define MethodDef(func) \
2865         {#func, M_NMesh_##func, METH_VARARGS, M_NMesh_##func##_doc}
2866
2867 static struct PyMethodDef M_NMesh_methods[] = {
2868         MethodDef( Col ),
2869         MethodDef( Vert ),
2870         MethodDef( Face ),
2871         MethodDef( New ),
2872         MethodDef( GetRaw ),
2873         MethodDef( GetRawFromObject ),
2874         MethodDef( PutRaw ),
2875         {NULL, NULL, 0, NULL}
2876 };
2877
2878 static PyObject *M_NMesh_Modes( void )
2879 {
2880         PyObject *Modes = M_constant_New(  );
2881
2882         if( Modes ) {
2883                 BPy_constant *d = ( BPy_constant * ) Modes;
2884
2885                 constant_insert( d, "NOVNORMALSFLIP",
2886                                  PyInt_FromLong
2887                                  ( EXPP_NMESH_MODE_NOPUNOFLIP ) );
2888                 constant_insert( d, "TWOSIDED",
2889                                  PyInt_FromLong( EXPP_NMESH_MODE_TWOSIDED ) );
2890                 constant_insert( d, "AUTOSMOOTH",
2891                                  PyInt_FromLong
2892                                  ( EXPP_NMESH_MODE_AUTOSMOOTH ) );
2893                 constant_insert( d, "SUBSURF",
2894                                  PyInt_FromLong( EXPP_NMESH_MODE_SUBSURF ) );
2895                 constant_insert( d, "OPTIMAL",
2896                                  PyInt_FromLong( EXPP_NMESH_MODE_OPTIMAL ) );
2897         }
2898
2899         return Modes;
2900 }
2901
2902 #undef EXPP_ADDCONST
2903 #define EXPP_ADDCONST(dict, name) \
2904                          constant_insert(dict, #name, PyInt_FromLong(TF_##name))
2905 /* Set constants for face drawing mode -- see drawmesh.c */
2906
2907 static PyObject *M_NMesh_FaceModesDict( void )
2908 {
2909         PyObject *FM = M_constant_New(  );
2910
2911         if( FM ) {
2912                 BPy_constant *d = ( BPy_constant * ) FM;
2913
2914                 constant_insert( d, "BILLBOARD",
2915                                  PyInt_FromLong( TF_BILLBOARD2 ) );
2916                 constant_insert( d, "ALL", PyInt_FromLong( 0xffff ) );
2917                 constant_insert( d, "HALO", PyInt_FromLong( TF_BILLBOARD ) );
2918                 EXPP_ADDCONST( d, DYNAMIC );
2919                 EXPP_ADDCONST( d, INVISIBLE );
2920                 EXPP_ADDCONST( d, LIGHT );
2921                 EXPP_ADDCONST( d, OBCOL );
2922                 EXPP_ADDCONST( d, SHADOW );
2923                 EXPP_ADDCONST( d, SHAREDVERT );
2924                 EXPP_ADDCONST( d, SHAREDCOL );
2925                 EXPP_ADDCONST( d, TEX );
2926                 EXPP_ADDCONST( d, TILES );
2927                 EXPP_ADDCONST( d, TWOSIDE );
2928         }
2929
2930         return FM;
2931 }
2932
2933 static PyObject *M_NMesh_FaceFlagsDict( void )
2934 {
2935         PyObject *FF = M_constant_New(  );
2936
2937         if( FF ) {
2938                 BPy_constant *d = ( BPy_constant * ) FF;
2939
2940                 EXPP_ADDCONST( d, SELECT );
2941                 EXPP_ADDCONST( d, HIDE );
2942                 EXPP_ADDCONST( d, ACTIVE );
2943         }
2944
2945         return FF;
2946 }
2947
2948 static PyObject *M_NMesh_FaceTranspModesDict( void )
2949 {
2950         PyObject *FTM = M_constant_New(  );
2951
2952         if( FTM ) {
2953                 BPy_constant *d = ( BPy_constant * ) FTM;
2954
2955                 EXPP_ADDCONST( d, SOLID );
2956                 EXPP_ADDCONST( d, ADD );
2957                 EXPP_ADDCONST( d, ALPHA );
2958                 EXPP_ADDCONST( d, SUB );
2959         }
2960
2961         return FTM;
2962 }
2963
2964 static PyObject *M_NMesh_EdgeFlagsDict( void )
2965 {
2966         PyObject *EF = M_constant_New(  );
2967
2968         if( EF ) {
2969                 BPy_constant *d = ( BPy_constant * ) EF;
2970
2971                 constant_insert(d, "SELECT", PyInt_FromLong(1));
2972                 constant_insert(d, "EDGEDRAW", PyInt_FromLong(ME_EDGEDRAW));
2973                 constant_insert(d, "SEAM", PyInt_FromLong(ME_SEAM));
2974                 constant_insert(d, "FGON", PyInt_FromLong(ME_FGON));
2975         }
2976
2977         return EF;
2978 }
2979
2980 PyObject *NMesh_Init( void )
2981 {
2982         PyObject *submodule;
2983
2984         PyObject *Modes = M_NMesh_Modes(  );
2985         PyObject *FaceFlags = M_NMesh_FaceFlagsDict(  );
2986         PyObject *FaceModes = M_NMesh_FaceModesDict(  );
2987         PyObject *FaceTranspModes = M_NMesh_FaceTranspModesDict(  );
2988   PyObject *EdgeFlags = M_NMesh_EdgeFlagsDict(  );
2989
2990         NMCol_Type.ob_type = &PyType_Type;
2991         NMFace_Type.ob_type = &PyType_Type;
2992         NMVert_Type.ob_type = &PyType_Type;
2993         NMesh_Type.ob_type = &PyType_Type;
2994
2995         submodule =
2996                 Py_InitModule3( "Blender.NMesh", M_NMesh_methods,
2997                                 M_NMesh_doc );
2998
2999         if( Modes )
3000                 PyModule_AddObject( submodule, "Modes", Modes );
3001         if( FaceFlags )
3002                 PyModule_AddObject( submodule, "FaceFlags", FaceFlags );
3003         if( FaceModes )
3004                 PyModule_AddObject( submodule, "FaceModes", FaceModes );
3005         if( FaceTranspModes )
3006                 PyModule_AddObject( submodule, "FaceTranspModes",
3007                                     FaceTranspModes );
3008   if( EdgeFlags )
3009     PyModule_AddObject( submodule, "EdgeFlags", EdgeFlags );
3010
3011         g_nmeshmodule = submodule;
3012         return submodule;
3013 }
3014
3015 /* These are needed by Object.c */
3016
3017 PyObject *NMesh_CreatePyObject( Mesh * me, Object * ob )
3018 {
3019         BPy_NMesh *nmesh = ( BPy_NMesh * ) new_NMesh( me );
3020
3021         if( nmesh )
3022                 nmesh->object = ob;     /* linking nmesh and object for vgrouping methods */
3023
3024         return ( PyObject * ) nmesh;
3025 }
3026
3027 int NMesh_CheckPyObject( PyObject * pyobj )
3028 {
3029         return ( pyobj->ob_type == &NMesh_Type );
3030 }
3031
3032 Mesh *Mesh_FromPyObject( PyObject * pyobj, Object * ob )
3033 {
3034         if( pyobj->ob_type == &NMesh_Type ) {
3035                 Mesh *mesh;
3036                 BPy_NMesh *nmesh = ( BPy_NMesh * ) pyobj;
3037
3038                 if( nmesh->mesh ) {
3039                         mesh = nmesh->mesh;
3040                 } else {
3041                         nmesh->mesh = Mesh_fromNMesh( nmesh, 1 );
3042                         mesh = nmesh->mesh;
3043
3044                   nmesh->object = ob;   /* linking for vgrouping methods */
3045
3046                   if( nmesh->name && nmesh->name != Py_None )
3047                           new_id( &( G.main->mesh ), &mesh->id,
3048                                   PyString_AsString( nmesh->name ) );
3049
3050                   mesh_update( mesh );
3051
3052                   nmesh_updateMaterials( nmesh );
3053     }
3054                 return mesh;
3055         }
3056
3057         return NULL;
3058 }
3059
3060 #define POINTER_CROSS_EQ(a1, a2, b1, b2) (((a1)==(b1) && (a2)==(b2)) || ((a1)==(b2) && (a2)==(b1)))
3061
3062 static PyObject *findEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int create)
3063 {
3064   int i;
3065
3066   for ( i = 0; i < PyList_Size(nmesh->edges); ++i )
3067   {
3068     BPy_NMEdge *edge=(BPy_NMEdge*)PyList_GetItem( nmesh->edges, i );
3069     if (!BPy_NMEdge_Check(edge)) continue;
3070     if ( POINTER_CROSS_EQ((BPy_NMVert*)edge->v1, (BPy_NMVert*)edge->v2, v1, v2) )
3071     {
3072       return EXPP_incr_ret((PyObject*)edge);
3073     }
3074   }
3075
3076   /* if this line is reached, edge has not been found */
3077   if (create)
3078   {
3079     PyObject *newEdge=(PyObject *)new_NMEdge(v1, v2, 0, ME_EDGEDRAW);
3080     PyList_Append(nmesh->edges, newEdge);
3081     return newEdge;
3082   }
3083   else
3084     return EXPP_incr_ret( Py_None );
3085 }
3086
3087 static void removeEdge( BPy_NMesh *nmesh, BPy_NMVert *v1, BPy_NMVert *v2, int ununsedOnly)
3088 {
3089   int i,j;
3090   BPy_NMEdge *edge=NULL;
3091   int edgeUsedByFace=0;
3092   int totedge=PyList_Size(nmesh->edges);
3093
3094   /* find the edge in the edge list */
3095   for ( i = 0; i < totedge; ++i )
3096   {
3097     edge=(BPy_NMEdge*)PyList_GetItem( nmesh->edges, i );
3098     if (!BPy_NMEdge_Check(edge)) continue;
3099     if ( POINTER_CROSS_EQ((BPy_NMVert*)edge->v1, (BPy_NMVert*)edge->v2, v1, v2) )
3100     {
3101       break;
3102     }
3103   }
3104
3105   if (i==totedge || !edge) // edge not found
3106     return;
3107
3108   for  ( j = PyList_Size(nmesh->faces)-1; j >= 0 ; --j )
3109   {
3110     BPy_NMFace *face=(BPy_NMFace *)PyList_GetItem(nmesh->faces, j);
3111     int k, del_face=0;
3112     int totv;
3113     if (!BPy_NMFace_Check(face)) continue;
3114     totv=PyList_Size(face->v);
3115     if (totv<2) continue;
3116     for ( k = 0; k < totv && !del_face; ++k )
3117     {
3118       BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
3119       BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);
3120       if ( POINTER_CROSS_EQ(v1, v2, fe_v1, fe_v2) )
3121       {
3122         edgeUsedByFace=1;
3123         del_face=1;
3124       }
3125     }
3126     if (del_face && !ununsedOnly) 
3127     {
3128       PySequence_DelItem(nmesh->faces, j);
3129     }
3130   }
3131
3132   if (!ununsedOnly || (ununsedOnly && !edgeUsedByFace) )
3133     PySequence_DelItem(nmesh->edges, PySequence_Index(nmesh->edges, (PyObject*)edge));
3134 }
3135
3136
3137 static PyObject *NMesh_addEdge( PyObject * self, PyObject * args )
3138 {
3139   BPy_NMesh *bmesh=(BPy_NMesh *)self;
3140   BPy_NMVert *v1=NULL, *v2=NULL;
3141
3142   if (!bmesh->edges)
3143                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
3144                                               "NMesh has no edge data." );
3145
3146   if (!PyArg_ParseTuple
3147             ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
3148                 return EXPP_ReturnPyObjError( PyExc_TypeError,
3149                                               "expected NMVert, NMVert" );
3150         }
3151
3152   if (v1==v2)
3153                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
3154                                               "vertices must be different" );
3155
3156   return findEdge(bmesh, v1, v2, 1);
3157 }
3158
3159 static PyObject *NMesh_findEdge( PyObject * self, PyObject * args )
3160 {
3161   BPy_NMesh *bmesh=(BPy_NMesh *)self;
3162   BPy_NMVert *v1=NULL, *v2=NULL;
3163
3164   if (!bmesh->edges)
3165                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
3166                                               "NMesh has no edge data." );
3167
3168   if (!PyArg_ParseTuple
3169             ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
3170                 return EXPP_ReturnPyObjError( PyExc_TypeError,
3171                                               "expected NMVert, NMVert" );
3172         }
3173
3174   if (v1==v2)
3175                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
3176                                               "vertices must be different" );
3177
3178   return findEdge(bmesh, v1, v2, 0);
3179 }
3180
3181 static PyObject *NMesh_removeEdge( PyObject * self, PyObject * args )
3182 {
3183   BPy_NMesh *bmesh=(BPy_NMesh *)self;
3184   BPy_NMVert *v1=NULL, *v2=NULL;
3185
3186   if (!bmesh->edges)
3187                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
3188                                               "NMesh has no edge data." );
3189
3190   if (!PyArg_ParseTuple
3191             ( args, "O!O!", &NMVert_Type, &v1, &NMVert_Type, &v2 ) ) {
3192                 return EXPP_ReturnPyObjError( PyExc_TypeError,
3193                                               "expected NMVert, NMVert" );
3194         }
3195
3196   if (v1==v2)
3197                 return EXPP_ReturnPyObjError( PyExc_AttributeError,
3198                                               "vertices must be different" );
3199   removeEdge(bmesh, v1, v2, 0);
3200
3201   return EXPP_incr_ret( Py_None );
3202 }
3203
3204
3205 static PyObject *NMesh_addEdgesData( PyObject * self )
3206 {
3207   /* Here we uses make_edges to create edges data.
3208    * Since Mesh corresponding to NMesh may not content the same data as
3209    * the NMesh and since maybe the NMesh has been created from scratch,
3210    * we creates a temporary Mesh to use to call make_edges
3211    */
3212   BPy_NMesh *nmesh=(BPy_NMesh *)self;
3213   Mesh *tempMesh=NULL;
3214   int i;
3215
3216   if (nmesh->edges)
3217                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
3218                                               "NMesh has already edge data." );
3219
3220   tempMesh=MEM_callocN(sizeof(Mesh), "temp mesh");
3221   convert_NMeshToMesh(tempMesh, nmesh, 0);
3222
3223   make_edges(tempMesh);
3224
3225   nmesh->edges = PyList_New( tempMesh->totedge );
3226   for( i = 0; i < tempMesh->totedge; ++i )
3227   {
3228     MEdge *edge = (tempMesh->medge) + i;
3229     /* By using nmedge_from_data, an important assumption is made:
3230      * every vertex in nmesh has been written in tempMesh in the same order
3231      * than in nmesh->verts.
3232      * Actually this assumption is needed since nmedge_from_data get the 
3233      * two NMVert for the newly created edge by using a PyList_GetItem with
3234      * the indices stored in edge. Those indices are valid for nmesh only if
3235      * nmesh->verts and tempMesh->mvert are identical (same number of vertices
3236      * in same order).
3237      */
3238     PyList_SetItem( nmesh->edges, i, (PyObject*)nmedge_from_data ( nmesh, edge ) );
3239   }
3240
3241   unlink_existingMeshData(tempMesh);
3242   MEM_freeN(tempMesh);
3243
3244   return EXPP_incr_ret( Py_None );
3245 }
3246
3247 static PyObject *NMesh_addFace( PyObject * self, PyObject * args )
3248 {
3249   BPy_NMesh *nmesh=(BPy_NMesh *)self;
3250
3251   BPy_NMFace *face;
3252   int totv=0;
3253   
3254   if (!PyArg_ParseTuple
3255             ( args, "O!", &NMFace_Type, &face ) ) {
3256                 return EXPP_ReturnPyObjError( PyExc_TypeError,
3257                                               "expected NMFace argument" );
3258         }
3259
3260   totv=PyList_Size(face->v);
3261
3262   /*
3263    * Before edges data exists, having faces with two vertices was
3264    * the only way of storing edges not attached to any face.
3265    */
3266   if (totv!=2 || !nmesh->edges)
3267     PyList_Append(nmesh->faces, (PyObject*)face);
3268
3269   if (nmesh->edges)
3270   {
3271     
3272     if (totv>=2)
3273     {
3274       /* when totv==2, there is only one edge, when totv==3 there is three edges
3275        * and when totv==4 there is four edges.
3276        * that's why in the following line totv==2 is a special case */
3277       PyObject *edges = PyList_New((totv==2) ? 1 : totv);
3278       if (totv==2)
3279       {
3280         BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, 0);
3281         BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, 1);
3282         BPy_NMEdge *edge=(BPy_NMEdge *)findEdge(nmesh, fe_v1, fe_v2, 1);
3283         PyList_SetItem(edges, 0, (PyObject*)edge); // PyList_SetItem steals the reference
3284       }
3285       else
3286       {
3287         int k;
3288         for ( k = 0; k < totv; ++k )
3289         {
3290           BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
3291           BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);
3292           BPy_NMEdge *edge=(BPy_NMEdge *)findEdge(nmesh, fe_v1, fe_v2, 1);
3293           PyList_SetItem(edges, k, (PyObject*)edge); // PyList_SetItem steals the reference
3294         }
3295       }
3296       return edges;
3297     }
3298   }
3299
3300   return EXPP_incr_ret( Py_None );
3301 }
3302
3303 static PyObject *NMesh_removeFace( PyObject * self, PyObject * args )
3304 {
3305   BPy_NMesh *nmesh=(BPy_NMesh *)self;
3306
3307   BPy_NMFace *face;
3308   int totv=0;
3309   
3310   if (!PyArg_ParseTuple
3311             ( args, "O!", &NMFace_Type, &face ) ) {
3312                 return EXPP_ReturnPyObjError( PyExc_TypeError,
3313                                               "expected NMFace argument" );
3314         }
3315
3316   totv=PyList_Size(face->v);
3317
3318   {
3319     int index=PySequence_Index(nmesh->faces, (PyObject*)face);
3320     if (index>=0)
3321       PySequence_DelItem(nmesh->faces, index);
3322   }
3323
3324   if (nmesh->edges)
3325   {
3326     
3327     if (totv>=2)
3328     {
3329       /* when totv==2, there is only one edge, when totv==3 there is three edges
3330        * and when totv==4 there is four edges.
3331        * that's why in the following line totv==2 is a special case */
3332       if (totv==2)
3333       {
3334         BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, 0);
3335         BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, 1);
3336         removeEdge(nmesh, fe_v1, fe_v2, 1);
3337       }
3338       else
3339       {
3340         int k;
3341         for ( k = 0; k < totv; ++k )
3342         {
3343           BPy_NMVert *fe_v1=(BPy_NMVert *)PyList_GetItem(face->v, k ? k-1 : totv-1);
3344           BPy_NMVert *fe_v2=(BPy_NMVert *)PyList_GetItem(face->v, k);