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