2.5
authorTon Roosendaal <ton@blender.org>
Tue, 30 Dec 2008 13:16:14 +0000 (13:16 +0000)
committerTon Roosendaal <ton@blender.org>
Tue, 30 Dec 2008 13:16:14 +0000 (13:16 +0000)
Editmesh code cleaned and compiling/linking. A whopping
20k lines back! :)
Not that it does stuff... editmode in/out has to be done,
and loads of operators. Also linking/exporting editmesh
calls has to be reviewed.

Also: added a blender_test_break() mechanism in BKE.

30 files changed:
source/Makefile
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/intern/blender.c
source/blender/blenlib/BLI_editVert.h
source/blender/editors/Makefile
source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_multires.h [new file with mode: 0644]
source/blender/editors/include/ED_object.h
source/blender/editors/mesh/Makefile
source/blender/editors/mesh/SConscript
source/blender/editors/mesh/editface.c [new file with mode: 0644]
source/blender/editors/mesh/editmesh.c [new file with mode: 0644]
source/blender/editors/mesh/editmesh.h [new file with mode: 0644]
source/blender/editors/mesh/editmesh_add.c [new file with mode: 0644]
source/blender/editors/mesh/editmesh_lib.c [new file with mode: 0644]
source/blender/editors/mesh/editmesh_loop.c [new file with mode: 0644]
source/blender/editors/mesh/editmesh_mods.c [new file with mode: 0644]
source/blender/editors/mesh/editmesh_tools.c [new file with mode: 0644]
source/blender/editors/mesh/meshtools.c [new file with mode: 0644]
source/blender/editors/object/object_edit.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/makesdna/DNA_scene_types.h
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_init_exit.c
source/blender/windowmanager/intern/wm_subwindow.c
source/blender/windowmanager/intern/wm_window.c
source/blender/windowmanager/wm_window.h

index 0cc4ebc..85fbc36 100644 (file)
@@ -161,7 +161,6 @@ COMLIB += $(NAN_MEMUTIL)/lib/libmemutil.a
 COMLIB += $(NAN_BMFONT)/lib/$(DEBUG_DIR)libbmfont.a
 COMLIB += $(NAN_PNG)/lib/libpng.a
 COMLIB += $(OCGDIR)/blender/yafray/$(DEBUG_DIR)libyafrayexport.a
-COMLIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a
 
 ifeq ($(WITH_QUICKTIME), true)
     COMLIB += $(OCGDIR)/blender/blenderqt/$(DEBUG_DIR)libblenderqt.a
@@ -252,6 +251,7 @@ PULIB += $(OCGDIR)/blender/ed_time/libed_time.a
 PULIB += $(OCGDIR)/blender/ed_view3d/libed_view3d.a
 PULIB += $(OCGDIR)/blender/ed_interface/libed_interface.a
 PULIB += $(OCGDIR)/blender/ed_object/libed_object.a
+PULIB += $(OCGDIR)/blender/ed_mesh/libed_mesh.a
 PULIB += $(OCGDIR)/blender/ed_animation/libed_animation.a
 PULIB += $(OCGDIR)/blender/ed_transform/libed_transform.a
 PULIB += $(OCGDIR)/blender/ed_util/libed_util.a
@@ -260,6 +260,8 @@ PULIB += $(OCGDIR)/blender/ed_screen/libed_screen.a
 PULIB += $(OCGDIR)/blender/windowmanager/libwindowmanager.a
 PULIB += $(OCGDIR)/blender/python/$(DEBUG_DIR)libpython.a
 PULIB += $(OCGDIR)/blender/makesrna/$(DEBUG_DIR)librna.a
+# note, no idea but it suddenly doesn't compile :(
+PULIB += $(OCGDIR)/blender/blenlib/$(DEBUG_DIR)libblenlib.a
 
 ifeq ($(NAN_NO_KETSJI),true)
     PULIB += $(NAN_MOTO)/lib/libmoto.a
index dbdb570..5a37480 100644 (file)
@@ -55,6 +55,10 @@ int BKE_read_file_from_memfile(struct bContext *C, struct MemFile *memfile, stru
 void free_blender(void);
 void initglobals(void);
 
+/* set this callback when a UI is running */
+void set_blender_test_break_cb(void (*func)(void) );
+int blender_test_break(void);
+
 void pushdata(void *data, int len);
 void popfirst(void *data);
 void poplast(void *data);
index 979e5d0..0dd9a34 100644 (file)
@@ -90,7 +90,6 @@
 
 #include "BKE_utildefines.h" // O_BINARY FALSE
 
-
 Global G;
 UserDef U;
 ListBase WMlist= {NULL, NULL};
@@ -475,6 +474,26 @@ int BKE_read_file_from_memfile(bContext *C, MemFile *memfile, ReportList *report
        return (bfd?1:0);
 }
 
+/* *****************  testing for break ************* */
+
+static void (*blender_test_break_cb)(void)= NULL;
+
+void set_blender_test_break_cb(void (*func)(void) )
+{
+       blender_test_break_cb= func;
+}
+
+
+int blender_test_break(void)
+{
+       if (!G.background) {
+               if (blender_test_break_cb)
+                       blender_test_break_cb();
+       }
+       
+       return (G.afbreek==1);
+}
+
 
 /* ***************** GLOBAL UNDO *************** */
 
index 447f6a2..55be4cf 100644 (file)
@@ -172,6 +172,9 @@ typedef struct EditMesh
         * never access this directly, use EM_set_actFace and EM_get_actFace */
        EditFace *act_face; 
        
+       /* copy from scene */
+       int selectmode;
+       
        struct DerivedMesh *derivedCage, *derivedFinal;
        /* the custom data layer mask that was last used to calculate
         * derivedCage and derivedFinal
index dd3b029..1dd69bb 100644 (file)
@@ -29,6 +29,6 @@
 # Bounces make to subdirectories.
 
 SOURCEDIR = source/blender/editors
-DIRS = animation object datafiles transform screen space_outliner space_time space_view3d interface util  space_api space_ipo space_image space_node space_buttons space_info space_file space_sound space_action space_nla space_script space_text space_sequencer
+DIRS = mesh animation object datafiles transform screen space_outliner space_time space_view3d interface util  space_api space_ipo space_image space_node space_buttons space_info space_file space_sound space_action space_nla space_script space_text space_sequencer
 
 include nan_subdirs.mk
index 882ced8..9e01857 100644 (file)
 #ifndef ED_MESH_H
 #define ED_MESH_H
 
+struct View3D;
+
+// edge and face flag both
+#define EM_FGON                2
+// face flag
+#define EM_FGON_DRAW   1
+
+/* editbutflag */
+#define B_CLOCKWISE            1
+#define B_KEEPORIG             2
+#define B_BEAUTY               4
+#define B_SMOOTH               8
+#define B_BEAUTY_SHORT         16
+#define B_AUTOFGON             32
+#define B_KNIFE                        0x80
+#define B_PERCENTSUBD          0x40
+#define B_MESH_X_MIRROR                0x100
+#define B_JOINTRIA_UV          0x200
+#define B_JOINTRIA_VCOL                0X400
+#define B_JOINTRIA_SHARP       0X800
+#define B_JOINTRIA_MAT         0X1000
+
+
+/* editmesh.c */
+
+void           EM_init_index_arrays(EditMesh *em, int forVert, int forEdge, int forFace);
+void           EM_free_index_arrays(void);
+EditVert       *EM_get_vert_for_index(int index);
+EditEdge       *EM_get_edge_for_index(int index);
+EditFace       *EM_get_face_for_index(int index);
+int                    EM_texFaceCheck(EditMesh *em);
+int                    EM_vertColorCheck(EditMesh *em);
+
+
+/* editmesh_lib.c */
+
+EditFace       *EM_get_actFace(EditMesh *em, int sloppy);
+
+void           EM_select_edge(EditEdge *eed, int sel);
+void           EM_select_face_fgon(EditMesh *em, EditFace *efa, int val);
+void           EM_selectmode_flush(EditMesh *em);
+void           EM_deselect_flush(EditMesh *em);
+
+
+
+/* editmesh_mods.c */
+extern unsigned int em_vertoffs, em_solidoffs, em_wireoffs;
+
+int                    EM_check_backbuf(unsigned int index);
+int                    EM_mask_init_backbuf_border(struct View3D *v3d, short mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax);
+void           EM_free_backbuf(void);
+int                    EM_init_backbuf_border(struct View3D *v3d, short xmin, short ymin, short xmax, short ymax);
+int                    EM_init_backbuf_circle(struct View3D *v3d, short xs, short ys, short rads);
+
 
 #endif /* ED_MESH_H */
 
diff --git a/source/blender/editors/include/ED_multires.h b/source/blender/editors/include/ED_multires.h
new file mode 100644 (file)
index 0000000..e4726c0
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2006 by Nicholas Bishop
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */ 
+
+#ifndef MULTIRES_H
+#define MULTIRES_H
+
+struct CustomData;
+struct EditMesh;
+struct Object;
+struct MDeformVert;
+struct Mesh;
+struct MultiresLevel;
+struct Multires;
+struct uiBlock;
+
+/* For canceling operations that don't work with multires on or on a non-base level */
+int multires_test();
+int multires_level1_test();
+
+void multires_draw_interface(struct uiBlock *block, unsigned short cx, unsigned short cy);
+
+void multires_make(void *ob, void *me);
+void multires_delete(void *ob, void *me);
+void multires_level_to_editmesh(struct Object *ob, struct Mesh *me, const int render);
+void multires_finish_mesh_update(struct Object *ob);
+void multires_subdivide(void *ob, void *me);
+void multires_del_lower(void *ob, void *me);
+void multires_del_higher(void *ob, void *me);
+void multires_set_level_cb(void *ob, void *me);
+void multires_edge_level_update_cb(void *ob, void *me);
+int multires_modifier_warning();
+
+#endif
index 3665c71..ee79a25 100644 (file)
@@ -29,6 +29,7 @@
 #define ED_OBJECT_H
 
 struct wmWindowManager;
+struct Scene;
 struct Object;
 struct bContext;
 struct Base;
@@ -41,6 +42,9 @@ void ED_base_object_select(struct Base *base, short mode);
        /* includes notifier */
 void ED_base_object_activate(struct bContext *C, struct Base *base);
 
+void ED_base_object_free_and_unlink(struct Scene *scene, struct Base *base);
+
+
 /* cleanup */
 int object_data_is_libdata(struct Object *ob);
 int object_is_libdata(struct Object *ob);
index b2aeaa1..daa5702 100644 (file)
 #
 # Makes module object directory and bounces make to subdirectories.
 
-LIBNAME = ed_screen
+LIBNAME = ed_mesh
 DIR = $(OCGDIR)/blender/$(LIBNAME)
 
 include nan_compile.mk
 
 CFLAGS += $(LEVEL_1_C_WARNINGS)
 
+CPPFLAGS += -I$(NAN_GLEW)/include
 CPPFLAGS += -I$(OPENGL_HEADERS)
 
 CPPFLAGS += -I$(NAN_BMFONT)/include
 CPPFLAGS += -I$(NAN_GUARDEDALLOC)/include
+CPPFLAGS += -I$(NAN_ELBEEM)/include
 
 CPPFLAGS += -I../../windowmanager
 CPPFLAGS += -I../../blenkernel
@@ -46,6 +48,8 @@ CPPFLAGS += -I../../blenloader
 CPPFLAGS += -I../../blenlib
 CPPFLAGS += -I../../makesdna
 CPPFLAGS += -I../../imbuf
+CPPFLAGS += -I../../gpu
+CPPFLAGS += -I../../render/extern/include
 
 # own include 
 
index e69de29..40b1fa8 100644 (file)
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+Import ('env')
+
+sources = env.Glob('*.c')
+
+incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
+incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+incs += ' #/intern/guardedalloc #intern/bmfont ../../gpu'
+incs += ' ../../makesrna ../../render/extern/include  #/intern/elbeem/extern'
+
+env.BlenderLib ( 'bf_editors_mesh', sources, Split(incs), [], libtype=['core'], priority=[35] )
diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c
new file mode 100644 (file)
index 0000000..69d7384
--- /dev/null
@@ -0,0 +1,1439 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, Campbell Barton
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include <math.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_heap.h"
+#include "BLI_edgehash.h"
+#include "BLI_editVert.h"
+
+#include "IMB_imbuf_types.h"
+#include "IMB_imbuf.h"
+
+#include "DNA_image_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BKE_brush.h"
+#include "BKE_customdata.h"
+#include "BKE_depsgraph.h"
+#include "BKE_DerivedMesh.h"
+#include "BKE_displist.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_multires.h"
+#include "BKE_object.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+#include "BKE_customdata.h"
+
+#include "BIF_gl.h"
+#include "BIF_glutil.h"
+
+#include "GPU_draw.h"
+
+#ifndef DISABLE_PYTHON
+//#include "BPY_extern.h"
+//#include "BPY_menus.h"
+#endif
+
+#include "ED_mesh.h"
+#include "ED_object.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+/* own include */
+#include "editmesh.h"
+
+
+/* Pupmenu codes: */
+#define UV_CUBE_MAPPING 2
+#define UV_CYL_MAPPING 3
+#define UV_SPHERE_MAPPING 4
+#define UV_BOUNDS_MAPPING 5
+#define UV_RESET_MAPPING 6
+#define UV_WINDOW_MAPPING 7
+#define UV_UNWRAP_MAPPING 8
+#define UV_CYL_EX 32
+#define UV_SPHERE_EX 34
+
+/* Some macro tricks to make pupmenu construction look nicer :-)
+   Sorry, just did it for fun. */
+
+#define _STR(x) " " #x
+#define STRING(x) _STR(x)
+
+#define MENUSTRING(string, code) string " %x" STRING(code)
+#define MENUTITLE(string) string " %t|" 
+
+/* ***************** XXX **************** */
+static int sample_backbuf_rect() {return 0;}
+static int sample_backbuf() {return 0;}
+static void BIF_undo_push() {}
+static void error() {}
+static int pupmenu() {return 0;}
+static void *give_cursor() {return NULL;}
+/* ***************** XXX **************** */
+
+
+/* returns 0 if not found, otherwise 1 */
+int facesel_face_pick(View3D *v3d, Mesh *me, short *mval, unsigned int *index, short rect)
+{
+       if (!me || me->totface==0)
+               return 0;
+
+       if (v3d->flag & V3D_NEEDBACKBUFDRAW) {
+// XXX drawview.c!             check_backbuf();
+// XXX         persp(PERSP_VIEW);
+       }
+
+       if (rect) {
+               /* sample rect to increase changes of selecting, so that when clicking
+                  on an edge in the backbuf, we can still select a face */
+               int dist;
+               *index = sample_backbuf_rect(mval, 3, 1, me->totface+1, &dist,0,NULL);
+       }
+       else
+               /* sample only on the exact position */
+               *index = sample_backbuf(mval[0], mval[1]);
+
+       if ((*index)<=0 || (*index)>(unsigned int)me->totface)
+               return 0;
+
+       (*index)--;
+       
+       return 1;
+}
+
+/* only operates on the edit object - this is all thats needed at the moment */
+static void uv_calc_center_vector(Scene *scene, View3D *v3d, float *result, Object *ob, EditMesh *em)
+{
+       float min[3], max[3], *cursx;
+       
+       EditFace *efa;
+       switch (v3d->around) 
+       {
+       case V3D_CENTER: /* bounding box center */
+               min[0]= min[1]= min[2]= 1e20f;
+               max[0]= max[1]= max[2]= -1e20f; 
+
+               for (efa= em->faces.first; efa; efa= efa->next) {
+                       if (efa->f & SELECT) {
+                               DO_MINMAX(efa->v1->co, min, max);
+                               DO_MINMAX(efa->v2->co, min, max);
+                               DO_MINMAX(efa->v3->co, min, max);
+                               if(efa->v4) DO_MINMAX(efa->v4->co, min, max);
+                       }
+               }
+               VecMidf(result, min, max);
+               break;
+       case V3D_CURSOR: /*cursor center*/ 
+               cursx= give_cursor(scene, v3d);
+               /* shift to objects world */
+               result[0]= cursx[0]-ob->obmat[3][0];
+               result[1]= cursx[1]-ob->obmat[3][1];
+               result[2]= cursx[2]-ob->obmat[3][2];
+               break;
+       case V3D_LOCAL: /*object center*/
+       case V3D_CENTROID: /* multiple objects centers, only one object here*/
+       default:
+               result[0]= result[1]= result[2]= 0.0;
+               break;
+       }
+}
+
+static void uv_calc_map_matrix(float result[][4], View3D *v3d, Object *ob, float upangledeg, float sideangledeg, float radius)
+{
+       float rotup[4][4], rotside[4][4], viewmatrix[4][4], rotobj[4][4];
+       float sideangle= 0.0, upangle= 0.0;
+       int k;
+
+       /* get rotation of the current view matrix */
+       Mat4CpyMat4(viewmatrix,v3d->viewmat);
+       /* but shifting */
+       for( k= 0; k< 4; k++) viewmatrix[3][k] =0.0;
+
+       /* get rotation of the current object matrix */
+       Mat4CpyMat4(rotobj,ob->obmat);
+       /* but shifting */
+       for( k= 0; k< 4; k++) rotobj[3][k] =0.0;
+
+       Mat4Clr(*rotup);
+       Mat4Clr(*rotside);
+
+       /* compensate front/side.. against opengl x,y,z world definition */
+       /* this is "kanonen gegen spatzen", a few plus minus 1 will do here */
+       /* i wanted to keep the reason here, so we're rotating*/
+       sideangle= M_PI * (sideangledeg + 180.0) /180.0;
+       rotside[0][0]= (float)cos(sideangle);
+       rotside[0][1]= -(float)sin(sideangle);
+       rotside[1][0]= (float)sin(sideangle);
+       rotside[1][1]= (float)cos(sideangle);
+       rotside[2][2]= 1.0f;
+      
+       upangle= M_PI * upangledeg /180.0;
+       rotup[1][1]= (float)cos(upangle)/radius;
+       rotup[1][2]= -(float)sin(upangle)/radius;
+       rotup[2][1]= (float)sin(upangle)/radius;
+       rotup[2][2]= (float)cos(upangle)/radius;
+       rotup[0][0]= (float)1.0/radius;
+
+       /* calculate transforms*/
+       Mat4MulSerie(result,rotup,rotside,viewmatrix,rotobj,NULL,NULL,NULL,NULL);
+}
+
+static void uv_calc_shift_project(ARegion *ar, View3D *v3d, float *target, float *shift, float rotmat[][4], int projectionmode, float *source, float *min, float *max)
+{
+       float pv[3];
+
+       VecSubf(pv, source, shift);
+       Mat4MulVecfl(rotmat, pv);
+
+       switch(projectionmode) {
+       case B_UVAUTO_CYLINDER: 
+               tubemap(pv[0], pv[1], pv[2], &target[0],&target[1]);
+               /* split line is always zero */
+               if (target[0] >= 1.0f) target[0] -= 1.0f;  
+               break;
+
+       case B_UVAUTO_SPHERE: 
+               spheremap(pv[0], pv[1], pv[2], &target[0],&target[1]);
+               /* split line is always zero */
+               if (target[0] >= 1.0f) target[0] -= 1.0f;
+               break;
+
+       case 3: /* ortho special case for BOUNDS */
+               target[0] = -pv[0];
+               target[1] = pv[2];
+               break;
+
+       case 4: 
+               {
+               /* very special case for FROM WINDOW */
+               float pv4[4], dx, dy, x= 0.0, y= 0.0;
+
+               dx= ar->winx;
+               dy= ar->winy;
+
+               VecCopyf(pv4, source);
+        pv4[3] = 1.0;
+
+               /* rotmat is the object matrix in this case */
+        Mat4MulVec4fl(rotmat, pv4); 
+
+               /* almost project_short */
+           Mat4MulVec4fl(v3d->persmat, pv4);
+               if (fabs(pv4[3]) > 0.00001) { /* avoid division by zero */
+                       target[0] = dx/2.0 + (dx/2.0)*pv4[0]/pv4[3];
+                       target[1] = dy/2.0 + (dy/2.0)*pv4[1]/pv4[3];
+               }
+               else {
+                       /* scaling is lost but give a valid result */
+                       target[0] = dx/2.0 + (dx/2.0)*pv4[0];
+                       target[1] = dy/2.0 + (dy/2.0)*pv4[1];
+               }
+
+        /* v3d->persmat seems to do this funky scaling */ 
+               if(dx > dy) {
+                       y= (dx-dy)/2.0;
+                       dy = dx;
+               }
+               else {
+                       x= (dy-dx)/2.0;
+                       dx = dy;
+               }
+               target[0]= (x + target[0])/dx;
+               target[1]= (y + target[1])/dy;
+
+               }
+               break;
+
+    default:
+               target[0] = 0.0;
+               target[1] = 1.0;
+       }
+
+       /* we know the values here and may need min_max later */
+       /* max requests independand from min; not fastest but safest */ 
+       if(min) {
+               min[0] = MIN2(target[0], min[0]);
+               min[1] = MIN2(target[1], min[1]);
+       }
+       if(max) {
+               max[0] = MAX2(target[0], max[0]);
+               max[1] = MAX2(target[1], max[1]);
+       }
+}
+
+static void correct_uv_aspect( EditMesh *em )
+{
+       float aspx=1, aspy=1;
+       EditFace *efa = EM_get_actFace(em, 1);
+       MTFace *tface;
+       
+       if (efa) {
+               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+// XXX         image_final_aspect(tface->tpage, &aspx, &aspy);
+       }
+       
+       if (aspx != aspy) {
+               
+               float scale;
+               
+               if (aspx > aspy) {
+                       scale = aspy/aspx;
+                       for (efa= em->faces.first; efa; efa= efa->next) {
+                               if (efa->f & SELECT) {
+                                       tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                                       tface->uv[0][0] = ((tface->uv[0][0]-0.5)*scale)+0.5;
+                                       tface->uv[1][0] = ((tface->uv[1][0]-0.5)*scale)+0.5;
+                                       tface->uv[2][0] = ((tface->uv[2][0]-0.5)*scale)+0.5;
+                                       if(efa->v4) {
+                                               tface->uv[3][0] = ((tface->uv[3][0]-0.5)*scale)+0.5;
+                                       }
+                               }
+                       }
+               } else {
+                       scale = aspx/aspy;
+                       for (efa= em->faces.first; efa; efa= efa->next) {
+                               if (efa->f & SELECT) {
+                                       tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                                       tface->uv[0][1] = ((tface->uv[0][1]-0.5)*scale)+0.5;
+                                       tface->uv[1][1] = ((tface->uv[1][1]-0.5)*scale)+0.5;
+                                       tface->uv[2][1] = ((tface->uv[2][1]-0.5)*scale)+0.5;
+                                       if(efa->v4) {
+                                               tface->uv[3][1] = ((tface->uv[3][1]-0.5)*scale)+0.5;
+                                       }
+                               }
+                       }
+               }
+       }
+}
+
+static void default_uv(float uv[][2], float size)
+{
+       int dy;
+       
+       if(size>1.0) size= 1.0;
+       
+       dy= 1.0-size;
+       
+       uv[0][0]= 0;
+       uv[0][1]= size+dy;
+       
+       uv[1][0]= 0;
+       uv[1][1]= dy;
+       
+       uv[2][0]= size;
+       uv[2][1]= dy;
+       
+       uv[3][0]= size;
+       uv[3][1]= size+dy;
+}
+
+static void calculate_uv_map(Scene *scene, ARegion *ar, View3D *v3d, EditMesh *em, unsigned short mapmode)
+{
+       MTFace *tface;
+       Object *ob;
+       EditFace *efa;
+       float dx, dy, rotatematrix[4][4], radius= 1.0, min[3], cent[3], max[3];
+       float fac= 1.0, upangledeg= 0.0, sideangledeg= 90.0;
+       int i, b, mi, n;
+       
+       if(scene->toolsettings->uvcalc_mapdir==1)  {
+               upangledeg= 90.0;
+               sideangledeg= 0.0;
+       } else {
+               upangledeg= 0.0;
+               if(scene->toolsettings->uvcalc_mapalign==1) sideangledeg= 0.0;
+               else sideangledeg= 90.0;
+       }
+       
+       /* add uvs if there not here */
+       if (!EM_texFaceCheck(em)) {
+               if (em && em->faces.first)
+                       EM_add_data_layer(em, &em->fdata, CD_MTFACE);
+               
+// XXX         if (G.sima && G.sima->image) /* this is a bit of a kludge, but assume they want the image on their mesh when UVs are added */
+//                     image_changed(G.sima, G.sima->image);
+               
+               if (!EM_texFaceCheck(em))
+                       return;
+               
+               /* select new UV's */
+// XX          if ((G.sima && G.sima->flag & SI_SYNC_UVSEL)==0) {
+//                     for(efa=em->faces.first; efa; efa=efa->next) {
+//                             MTFace *tf= (MTFace *)CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+//                             simaFaceSel_Set(efa, tf);
+//                     }
+               
+       }
+       
+       ob=OBACT;
+       
+       switch(mapmode) {
+       case B_UVAUTO_BOUNDS:
+               min[0]= min[1]= 10000000.0;
+               max[0]= max[1]= -10000000.0;
+
+               cent[0] = cent[1] = cent[2] = 0.0; 
+               uv_calc_map_matrix(rotatematrix, v3d, ob, upangledeg, sideangledeg, 1.0f);
+               
+               for (efa= em->faces.first; efa; efa= efa->next) {
+                       if (efa->f & SELECT) {
+                               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               uv_calc_shift_project(ar, v3d, tface->uv[0],cent,rotatematrix,3, efa->v1->co, min,max);
+                               uv_calc_shift_project(ar, v3d, tface->uv[1],cent,rotatematrix,3, efa->v2->co, min,max);
+                               uv_calc_shift_project(ar, v3d, tface->uv[2],cent,rotatematrix,3, efa->v3->co,min,max);
+                               if(efa->v4)
+                                       uv_calc_shift_project(ar, v3d, tface->uv[3],cent,rotatematrix,3, efa->v4->co,min,max);
+                       }
+               }
+               
+               /* rescale UV to be in 1/1 */
+               dx= (max[0]-min[0]);
+               dy= (max[1]-min[1]);
+
+               for (efa= em->faces.first; efa; efa= efa->next) {
+                       if (efa->f & SELECT) {
+                               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               if(efa->v4) b= 3; else b= 2;
+                               for(; b>=0; b--) {
+                                       tface->uv[b][0]= ((tface->uv[b][0]-min[0])*fac)/dx;
+                                       tface->uv[b][1]= 1.0-fac+((tface->uv[b][1]-min[1])/* *fac */)/dy;
+                               }
+                       }
+               }
+               break;
+
+       case B_UVAUTO_WINDOW:           
+               cent[0] = cent[1] = cent[2] = 0.0; 
+               Mat4CpyMat4(rotatematrix,ob->obmat);
+               for (efa= em->faces.first; efa; efa= efa->next) {
+                       if (efa->f & SELECT) {
+                               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               uv_calc_shift_project(ar, v3d, tface->uv[0],cent,rotatematrix,4, efa->v1->co, NULL,NULL);
+                               uv_calc_shift_project(ar, v3d, tface->uv[1],cent,rotatematrix,4, efa->v2->co, NULL,NULL);
+                               uv_calc_shift_project(ar, v3d, tface->uv[2],cent,rotatematrix,4, efa->v3->co, NULL,NULL);
+                               if(efa->v4)
+                                       uv_calc_shift_project(ar, v3d, tface->uv[3],cent,rotatematrix,4, efa->v4->co, NULL,NULL);
+                       }
+               }
+               break;
+
+       case B_UVAUTO_RESET:
+               for (efa= em->faces.first; efa; efa= efa->next) {
+                       if (efa->f & SELECT) {
+                               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               default_uv(tface->uv, 1.0);
+                       }
+               }
+               break;
+
+       case B_UVAUTO_CYLINDER:
+       case B_UVAUTO_SPHERE:
+               uv_calc_center_vector(scene, v3d, cent, ob, em);
+                       
+               if(mapmode==B_UVAUTO_CYLINDER) radius = scene->toolsettings->uvcalc_radius;
+
+               /* be compatible to the "old" sphere/cylinder mode */
+               if (scene->toolsettings->uvcalc_mapdir== 2)
+                       Mat4One(rotatematrix);
+               else 
+                       uv_calc_map_matrix(rotatematrix, v3d, ob, upangledeg,sideangledeg,radius);
+               for (efa= em->faces.first; efa; efa= efa->next) {
+                       if (efa->f & SELECT) {
+                               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               uv_calc_shift_project(ar, v3d, tface->uv[0],cent,rotatematrix,mapmode, efa->v1->co, NULL,NULL);
+                               uv_calc_shift_project(ar, v3d, tface->uv[1],cent,rotatematrix,mapmode, efa->v2->co, NULL,NULL);
+                               uv_calc_shift_project(ar, v3d, tface->uv[2],cent,rotatematrix,mapmode, efa->v3->co, NULL,NULL);
+                               n = 3;       
+                               if(efa->v4) {
+                                       uv_calc_shift_project(ar, v3d, tface->uv[3],cent,rotatematrix,mapmode, efa->v4->co, NULL,NULL);
+                                       n=4;
+                               }
+
+                               mi = 0;
+                               for (i = 1; i < n; i++)
+                                       if (tface->uv[i][0] > tface->uv[mi][0]) mi = i;
+
+                               for (i = 0; i < n; i++) {
+                                       if (i != mi) {
+                                               dx = tface->uv[mi][0] - tface->uv[i][0];
+                                               if (dx > 0.5) tface->uv[i][0] += 1.0;
+                                       } 
+                               } 
+                       }
+               }
+
+               break;
+
+       case B_UVAUTO_CUBE:
+               {
+               /* choose x,y,z axis for projetion depending on the largest normal */
+               /* component, but clusters all together around the center of map */
+               float no[3];
+               short cox, coy;
+               float *loc= ob->obmat[3];
+               /*MVert *mv= me->mvert;*/
+               float cubesize = scene->toolsettings->uvcalc_cubesize;
+
+               for (efa= em->faces.first; efa; efa= efa->next) {
+                       if (efa->f & SELECT) {
+                               tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+                               CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, no);
+                               
+                               no[0]= fabs(no[0]);
+                               no[1]= fabs(no[1]);
+                               no[2]= fabs(no[2]);
+                               
+                               cox=0; coy= 1;
+                               if(no[2]>=no[0] && no[2]>=no[1]);
+                               else if(no[1]>=no[0] && no[1]>=no[2]) coy= 2;
+                               else { cox= 1; coy= 2; }
+                               
+                               tface->uv[0][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v1->co[cox]);
+                               tface->uv[0][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v1->co[coy]);
+                               dx = floor(tface->uv[0][0]);
+                               dy = floor(tface->uv[0][1]);
+                               tface->uv[0][0] -= dx;
+                               tface->uv[0][1] -= dy;
+                               tface->uv[1][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v2->co[cox]);
+                               tface->uv[1][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v2->co[coy]);
+                               tface->uv[1][0] -= dx;
+                               tface->uv[1][1] -= dy;
+                               tface->uv[2][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v3->co[cox]);
+                               tface->uv[2][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v3->co[coy]);
+                               tface->uv[2][0] -= dx;
+                               tface->uv[2][1] -= dy;
+                               if(efa->v4) {
+                                       tface->uv[3][0]= 0.5+0.5*cubesize*(loc[cox] + efa->v4->co[cox]);
+                                       tface->uv[3][1]= 0.5+0.5*cubesize*(loc[coy] + efa->v4->co[coy]);
+                                       tface->uv[3][0] -= dx;
+                                       tface->uv[3][1] -= dy;
+                               }
+                       }
+               }
+               break;
+               }
+       default:
+               if ((scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT)==0)
+                       correct_uv_aspect(em);
+               return;
+       } /* end switch mapmode */
+
+       /* clipping and wrapping */
+       if(0) { // XXX (make it uv layer property!) G.sima && G.sima->flag & SI_CLIP_UV) {
+               for (efa= em->faces.first; efa; efa= efa->next) {
+                       if (!(efa->f & SELECT)) continue;
+                       tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+               
+                       dx= dy= 0;
+                       if(efa->v4) b= 3; else b= 2;
+                       for(; b>=0; b--) {
+                               while(tface->uv[b][0] + dx < 0.0) dx+= 0.5;
+                               while(tface->uv[b][0] + dx > 1.0) dx-= 0.5;
+                               while(tface->uv[b][1] + dy < 0.0) dy+= 0.5;
+                               while(tface->uv[b][1] + dy > 1.0) dy-= 0.5;
+                       }
+       
+                       if(efa->v4) b= 3; else b= 2;
+                       for(; b>=0; b--) {
+                               tface->uv[b][0]+= dx;
+                               CLAMP(tface->uv[b][0], 0.0, 1.0);
+                               
+                               tface->uv[b][1]+= dy;
+                               CLAMP(tface->uv[b][1], 0.0, 1.0);
+                       }
+               }
+       }
+
+       if (    (mapmode!=B_UVAUTO_BOUNDS) &&
+                       (mapmode!=B_UVAUTO_RESET) &&
+                       (scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT)==0
+               ) {
+               correct_uv_aspect(em);
+       }
+       
+       BIF_undo_push("UV calculation");
+
+// XXX notifier        object_uvs_changed(OBACT);
+
+}
+
+/* last_sel, use em->act_face otherwise get the last selected face in the editselections
+ * at the moment, last_sel is mainly useful for gaking sure the space image dosnt flicker */
+MTFace *get_active_mtface(EditMesh *em, EditFace **act_efa, MCol **mcol, int sloppy)
+{
+       EditFace *efa = NULL;
+       
+       if(!EM_texFaceCheck(em))
+               return NULL;
+       
+       efa = EM_get_actFace(em, sloppy);
+       
+       if (efa) {
+               if (mcol) {
+                       if (CustomData_has_layer(&em->fdata, CD_MCOL))
+                               *mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
+                       else
+                               *mcol = NULL;
+               }
+               if (act_efa) *act_efa = efa; 
+               return CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       }
+       if (act_efa) *act_efa= NULL;
+       if(mcol) *mcol = NULL;
+       return NULL;
+}
+
+void make_tfaces(Mesh *me) 
+{
+       if(!me->mtface) {
+               if(me->mr) {
+                       multires_add_layer(me, &me->mr->fdata, CD_MTFACE,
+                                          CustomData_number_of_layers(&me->fdata, CD_MTFACE));
+               }
+               else {
+                       me->mtface= CustomData_add_layer(&me->fdata, CD_MTFACE, CD_DEFAULT,
+                               NULL, me->totface);
+               }
+       }
+}
+
+void reveal_tface(Scene *scene)
+{
+       Mesh *me;
+       MFace *mface;
+       int a;
+       
+       me= get_mesh(OBACT);
+       if(me==0 || me->totface==0) return;
+       
+       mface= me->mface;
+       a= me->totface;
+       while(a--) {
+               if(mface->flag & ME_HIDE) {
+                       mface->flag |= ME_FACE_SEL;
+                       mface->flag -= ME_HIDE;
+               }
+               mface++;
+       }
+
+       BIF_undo_push("Reveal face");
+
+// XXX notifier!       object_tface_flags_changed(OBACT, 0);
+}
+
+void hide_tface(Scene *scene)
+{
+       Mesh *me;
+       MFace *mface;
+       int a;
+       int shift=0, alt= 0; // XXX
+       
+       me= get_mesh(OBACT);
+       if(me==0 || me->totface==0) return;
+       
+       if(alt) {
+               reveal_tface(scene);
+               return;
+       }
+       
+       mface= me->mface;
+       a= me->totface;
+       while(a--) {
+               if(mface->flag & ME_HIDE);
+               else {
+                       if(shift) {
+                               if( (mface->flag & ME_FACE_SEL)==0) mface->flag |= ME_HIDE;
+                       }
+                       else {
+                               if( (mface->flag & ME_FACE_SEL)) mface->flag |= ME_HIDE;
+                       }
+               }
+               if(mface->flag & ME_HIDE) mface->flag &= ~ME_FACE_SEL;
+               
+               mface++;
+       }
+
+       BIF_undo_push("Hide face");
+
+// XXX notifier!               object_tface_flags_changed(OBACT, 0);
+}
+
+void select_linked_tfaces(Scene *scene, View3D *v3d, int mode)
+{
+       Object *ob;
+       Mesh *me;
+       short mval[2];
+       unsigned int index=0;
+
+       ob = OBACT;
+       me = get_mesh(ob);
+       if(me==0 || me->totface==0) return;
+
+       if (mode==0 || mode==1) {
+               if (!(ob->lay & v3d->lay))
+                       error("The active object is not in this layer");
+                       
+// XXX         getmouseco_areawin(mval);
+               if (!facesel_face_pick(v3d, me, mval, &index, 1)) return;
+       }
+
+// XXX unwrapper.c     select_linked_tfaces_with_seams(mode, me, index);
+}
+
+void deselectall_tface(Scene *scene)
+{
+       Mesh *me;
+       MFace *mface;
+       int a, sel;
+               
+       me= get_mesh(OBACT);
+       if(me==0) return;
+       
+       mface= me->mface;
+       a= me->totface;
+       sel= 0;
+       while(a--) {
+               if(mface->flag & ME_HIDE);
+               else if(mface->flag & ME_FACE_SEL) sel= 1;
+               mface++;
+       }
+       
+       mface= me->mface;
+       a= me->totface;
+       while(a--) {
+               if(mface->flag & ME_HIDE);
+               else {
+                       if(sel) mface->flag &= ~ME_FACE_SEL;
+                       else mface->flag |= ME_FACE_SEL;
+               }
+               mface++;
+       }
+
+       BIF_undo_push("(De)select all faces");
+
+// XXX notifier!               object_tface_flags_changed(OBACT, 0);
+}
+
+void selectswap_tface(Scene *scene)
+{
+       Mesh *me;
+       MFace *mface;
+       int a;
+               
+       me= get_mesh(OBACT);
+       if(me==0) return;
+       
+       mface= me->mface;
+       a= me->totface;
+       while(a--) {
+               if(mface->flag & ME_HIDE);
+               else {
+                       if(mface->flag & ME_FACE_SEL) mface->flag &= ~ME_FACE_SEL;
+                       else mface->flag |= ME_FACE_SEL;
+               }
+               mface++;
+       }
+
+       BIF_undo_push("Select inverse face");
+
+// XXX notifier!               object_tface_flags_changed(OBACT, 0);
+}
+
+int minmax_tface(Scene *scene, float *min, float *max)
+{
+       Object *ob;
+       Mesh *me;
+       MFace *mf;
+       MTFace *tf;
+       MVert *mv;
+       int a, ok=0;
+       float vec[3], bmat[3][3];
+       
+       ob = OBACT;
+       if (ob==0) return ok;
+       me= get_mesh(ob);
+       if(me==0 || me->mtface==0) return ok;
+       
+       Mat3CpyMat4(bmat, ob->obmat);
+
+       mv= me->mvert;
+       mf= me->mface;
+       tf= me->mtface;
+       for (a=me->totface; a>0; a--, mf++, tf++) {
+               if (mf->flag & ME_HIDE || !(mf->flag & ME_FACE_SEL))
+                       continue;
+
+               VECCOPY(vec, (mv+mf->v1)->co);
+               Mat3MulVecfl(bmat, vec);
+               VecAddf(vec, vec, ob->obmat[3]);
+               DO_MINMAX(vec, min, max);               
+
+               VECCOPY(vec, (mv+mf->v2)->co);
+               Mat3MulVecfl(bmat, vec);
+               VecAddf(vec, vec, ob->obmat[3]);
+               DO_MINMAX(vec, min, max);               
+
+               VECCOPY(vec, (mv+mf->v3)->co);
+               Mat3MulVecfl(bmat, vec);
+               VecAddf(vec, vec, ob->obmat[3]);
+               DO_MINMAX(vec, min, max);               
+
+               if (mf->v4) {
+                       VECCOPY(vec, (mv+mf->v4)->co);
+                       Mat3MulVecfl(bmat, vec);
+                       VecAddf(vec, vec, ob->obmat[3]);
+                       DO_MINMAX(vec, min, max);
+               }
+               ok= 1;
+       }
+       return ok;
+}
+
+#define ME_SEAM_DONE 2         /* reuse this flag */
+
+static float edgetag_cut_cost(EditMesh *em, int e1, int e2, int vert)
+{
+       EditVert *v = EM_get_vert_for_index(vert);
+       EditEdge *eed1 = EM_get_edge_for_index(e1), *eed2 = EM_get_edge_for_index(e2);
+       EditVert *v1 = EM_get_vert_for_index( (eed1->v1->tmp.l == vert)? eed1->v2->tmp.l: eed1->v1->tmp.l );
+       EditVert *v2 = EM_get_vert_for_index( (eed2->v1->tmp.l == vert)? eed2->v2->tmp.l: eed2->v1->tmp.l );
+       float cost, d1[3], d2[3];
+
+       cost = VecLenf(v1->co, v->co);
+       cost += VecLenf(v->co, v2->co);
+
+       VecSubf(d1, v->co, v1->co);
+       VecSubf(d2, v2->co, v->co);
+
+       cost = cost + 0.5f*cost*(2.0f - fabs(d1[0]*d2[0] + d1[1]*d2[1] + d1[2]*d2[2]));
+
+       return cost;
+}
+
+static void edgetag_add_adjacent(EditMesh *em, Heap *heap, int mednum, int vertnum, int *nedges, int *edges, int *prevedge, float *cost)
+{
+       int startadj, endadj = nedges[vertnum+1];
+
+       for (startadj = nedges[vertnum]; startadj < endadj; startadj++) {
+               int adjnum = edges[startadj];
+               EditEdge *eedadj = EM_get_edge_for_index(adjnum);
+               float newcost;
+
+               if (eedadj->f2 & ME_SEAM_DONE)
+                       continue;
+
+               newcost = cost[mednum] + edgetag_cut_cost(em, mednum, adjnum, vertnum);
+
+               if (cost[adjnum] > newcost) {
+                       cost[adjnum] = newcost;
+                       prevedge[adjnum] = mednum;
+                       BLI_heap_insert(heap, newcost, SET_INT_IN_POINTER(adjnum));
+               }
+       }
+}
+
+void edgetag_context_set(Scene *scene, EditEdge *eed, int val)
+{
+       switch (scene->toolsettings->edge_mode) {
+       case EDGE_MODE_TAG_SEAM:
+               if (val)                {eed->seam = 255;}
+               else                    {eed->seam = 0;}
+               break;
+       case EDGE_MODE_TAG_SHARP:
+               if (val)                {eed->sharp = 1;}
+               else                    {eed->sharp = 0;}
+               break;                          
+       case EDGE_MODE_TAG_CREASE:      
+               if (val)                {eed->crease = 1.0f;}
+               else                    {eed->crease = 0.0f;}
+               break;
+       case EDGE_MODE_TAG_BEVEL:
+               if (val)                {eed->bweight = 1.0f;}
+               else                    {eed->bweight = 0.0f;}
+               break;
+       }
+}
+
+int edgetag_context_check(Scene *scene, EditEdge *eed)
+{
+       switch (scene->toolsettings->edge_mode) {
+       case EDGE_MODE_TAG_SEAM:
+               return eed->seam ? 1 : 0;
+       case EDGE_MODE_TAG_SHARP:
+               return eed->sharp ? 1 : 0;
+       case EDGE_MODE_TAG_CREASE:      
+               return eed->crease ? 1 : 0;
+       case EDGE_MODE_TAG_BEVEL:
+               return eed->bweight ? 1 : 0;
+       }
+       return 0;
+}
+
+
+int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target)
+{
+       EditEdge *eed;
+       EditVert *ev;
+       
+       Heap *heap;
+       float *cost;
+       int a, totvert=0, totedge=0, *nedges, *edges, *prevedge, mednum = -1, nedgeswap = 0;
+
+
+       /* we need the vert */
+       for (ev= em->verts.first, totvert=0; ev; ev= ev->next) {
+               ev->tmp.l = totvert;
+               totvert++;
+       }
+
+       for (eed= em->edges.first; eed; eed = eed->next) {
+               eed->f2 = 0;
+               if (eed->h) {
+                       eed->f2 |= ME_SEAM_DONE;
+               }
+               eed->tmp.l = totedge;
+               totedge++;
+       }
+
+       /* alloc */
+       nedges = MEM_callocN(sizeof(*nedges)*totvert+1, "SeamPathNEdges");
+       edges = MEM_mallocN(sizeof(*edges)*totedge*2, "SeamPathEdges");
+       prevedge = MEM_mallocN(sizeof(*prevedge)*totedge, "SeamPathPrevious");
+       cost = MEM_mallocN(sizeof(*cost)*totedge, "SeamPathCost");
+
+       /* count edges, compute adjacent edges offsets and fill adjacent edges */
+       for (eed= em->edges.first; eed; eed = eed->next) {
+               nedges[eed->v1->tmp.l+1]++;
+               nedges[eed->v2->tmp.l+1]++;
+       }
+
+       for (a=1; a<totvert; a++) {
+               int newswap = nedges[a+1];
+               nedges[a+1] = nedgeswap + nedges[a];
+               nedgeswap = newswap;
+       }
+       nedges[0] = nedges[1] = 0;
+
+       for (a=0, eed= em->edges.first; eed; a++, eed = eed->next) {
+               edges[nedges[eed->v1->tmp.l+1]++] = a;
+               edges[nedges[eed->v2->tmp.l+1]++] = a;
+
+               cost[a] = 1e20f;
+               prevedge[a] = -1;
+       }
+
+       /* regular dijkstra shortest path, but over edges instead of vertices */
+       heap = BLI_heap_new();
+       BLI_heap_insert(heap, 0.0f, SET_INT_IN_POINTER(source->tmp.l));
+       cost[source->tmp.l] = 0.0f;
+
+       EM_init_index_arrays(em, 1, 1, 0);
+
+
+       while (!BLI_heap_empty(heap)) {
+               mednum = GET_INT_FROM_POINTER(BLI_heap_popmin(heap));
+               eed = EM_get_edge_for_index( mednum );
+
+               if (mednum == target->tmp.l)
+                       break;
+
+               if (eed->f2 & ME_SEAM_DONE)
+                       continue;
+
+               eed->f2 |= ME_SEAM_DONE;
+
+               edgetag_add_adjacent(em, heap, mednum, eed->v1->tmp.l, nedges, edges, prevedge, cost);
+               edgetag_add_adjacent(em, heap, mednum, eed->v2->tmp.l, nedges, edges, prevedge, cost);
+       }
+       
+       
+       MEM_freeN(nedges);
+       MEM_freeN(edges);
+       MEM_freeN(cost);
+       BLI_heap_free(heap, NULL);
+
+       for (eed= em->edges.first; eed; eed = eed->next) {
+               eed->f2 &= ~ME_SEAM_DONE;
+       }
+
+       if (mednum != target->tmp.l) {
+               MEM_freeN(prevedge);
+               EM_free_index_arrays();
+               return 0;
+       }
+
+       /* follow path back to source and mark as seam */
+       if (mednum == target->tmp.l) {
+               short allseams = 1;
+
+               mednum = target->tmp.l;
+               do {
+                       eed = EM_get_edge_for_index( mednum );
+                       if (!edgetag_context_check(scene, eed)) {
+                               allseams = 0;
+                               break;
+                       }
+                       mednum = prevedge[mednum];
+               } while (mednum != source->tmp.l);
+
+               mednum = target->tmp.l;
+               do {
+                       eed = EM_get_edge_for_index( mednum );
+                       if (allseams)
+                               edgetag_context_set(scene, eed, 0);
+                       else
+                               edgetag_context_set(scene, eed, 1);
+                       mednum = prevedge[mednum];
+               } while (mednum != -1);
+       }
+
+       MEM_freeN(prevedge);
+       EM_free_index_arrays();
+       return 1;
+}
+
+static void seam_edgehash_insert_face(EdgeHash *ehash, MFace *mf)
+{
+       BLI_edgehash_insert(ehash, mf->v1, mf->v2, NULL);
+       BLI_edgehash_insert(ehash, mf->v2, mf->v3, NULL);
+       if (mf->v4) {
+               BLI_edgehash_insert(ehash, mf->v3, mf->v4, NULL);
+               BLI_edgehash_insert(ehash, mf->v4, mf->v1, NULL);
+       }
+       else
+               BLI_edgehash_insert(ehash, mf->v3, mf->v1, NULL);
+}
+
+void seam_mark_clear_tface(Scene *scene, short mode)
+{
+       Mesh *me;
+       MFace *mf;
+       MEdge *med;
+       int a;
+       
+       me= get_mesh(OBACT);
+       if(me==0 ||  me->totface==0) return;
+
+       if (mode == 0)
+               mode = pupmenu("Seams%t|Mark Border Seam %x1|Clear Seam %x2");
+
+       if (mode != 1 && mode != 2)
+               return;
+
+       if (mode == 2) {
+               EdgeHash *ehash = BLI_edgehash_new();
+
+               for (a=0, mf=me->mface; a<me->totface; a++, mf++)
+                       if (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))
+                               seam_edgehash_insert_face(ehash, mf);
+
+               for (a=0, med=me->medge; a<me->totedge; a++, med++)
+                       if (BLI_edgehash_haskey(ehash, med->v1, med->v2))
+                               med->flag &= ~ME_SEAM;
+
+               BLI_edgehash_free(ehash, NULL);
+       }
+       else {
+               /* mark edges that are on both selected and deselected faces */
+               EdgeHash *ehash1 = BLI_edgehash_new();
+               EdgeHash *ehash2 = BLI_edgehash_new();
+
+               for (a=0, mf=me->mface; a<me->totface; a++, mf++) {
+                       if ((mf->flag & ME_HIDE) || !(mf->flag & ME_FACE_SEL))
+                               seam_edgehash_insert_face(ehash1, mf);
+                       else
+                               seam_edgehash_insert_face(ehash2, mf);
+               }
+
+               for (a=0, med=me->medge; a<me->totedge; a++, med++)
+                       if (BLI_edgehash_haskey(ehash1, med->v1, med->v2) &&
+                           BLI_edgehash_haskey(ehash2, med->v1, med->v2))
+                               med->flag |= ME_SEAM;
+
+               BLI_edgehash_free(ehash1, NULL);
+               BLI_edgehash_free(ehash2, NULL);
+       }
+
+// XXX if (G.rt == 8)
+//             unwrap_lscm(1);
+
+       G.f |= G_DRAWSEAMS;
+       BIF_undo_push("Mark Seam");
+
+// XXX notifier!               object_tface_flags_changed(OBACT, 1);
+}
+
+void face_select(Scene *scene, View3D *v3d)
+{
+       Object *ob;
+       Mesh *me;
+       MFace *mface, *msel;
+       short mval[2];
+       unsigned int a, index;
+       int shift= 0; // XXX
+       
+       /* Get the face under the cursor */
+       ob = OBACT;
+       if (!(ob->lay & v3d->lay)) {
+               error("The active object is not in this layer");
+       }
+       me = get_mesh(ob);
+// XXX getmouseco_areawin(mval);
+
+       if (!facesel_face_pick(v3d, me, mval, &index, 1)) return;
+       
+       msel= (((MFace*)me->mface)+index);
+       if (msel->flag & ME_HIDE) return;
+       
+       /* clear flags */
+       mface = me->mface;
+       a = me->totface;
+       if ((shift)==0) {
+               while (a--) {
+                       mface->flag &= ~ME_FACE_SEL;
+                       mface++;
+               }
+       }
+       
+       me->act_face = (int)index;
+
+       if (shift) {
+               if (msel->flag & ME_FACE_SEL)
+                       msel->flag &= ~ME_FACE_SEL;
+               else
+                       msel->flag |= ME_FACE_SEL;
+       }
+       else msel->flag |= ME_FACE_SEL;
+       
+       /* image window redraw */
+       
+       BIF_undo_push("Select UV face");
+
+// XXX notifier!               object_tface_flags_changed(OBACT, 1);
+}
+
+void face_borderselect(Scene *scene, ARegion *ar)
+{
+       Mesh *me;
+       MFace *mface;
+       rcti rect;
+       struct ImBuf *ibuf;
+       unsigned int *rt;
+       int a, sx, sy, index, val;
+       char *selar;
+       
+       me= get_mesh(OBACT);
+       if(me==0) return;
+       if(me->totface==0) return;
+       
+// XXX val= get_border(&rect, 3);
+       
+       /* why readbuffer here? shouldn't be necessary (maybe a flush or so) */
+       glReadBuffer(GL_BACK);
+#ifdef __APPLE__
+       glReadBuffer(GL_AUX0); /* apple only */
+#endif
+       
+       if(val) {
+               selar= MEM_callocN(me->totface+1, "selar");
+               
+               sx= (rect.xmax-rect.xmin+1);
+               sy= (rect.ymax-rect.ymin+1);
+               if(sx*sy<=0) return;
+
+               ibuf = IMB_allocImBuf(sx,sy,32,IB_rect,0);
+               rt = ibuf->rect;
+               glReadPixels(rect.xmin+ar->winrct.xmin,  rect.ymin+ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
+               if(ENDIAN_ORDER==B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
+
+               a= sx*sy;
+               while(a--) {
+                       if(*rt) {
+                               index= WM_framebuffer_to_index(*rt);
+                               if(index<=me->totface) selar[index]= 1;
+                       }
+                       rt++;
+               }
+               
+               mface= me->mface;
+               for(a=1; a<=me->totface; a++, mface++) {
+                       if(selar[a]) {
+                               if(mface->flag & ME_HIDE);
+                               else {
+                                       if(val==LEFTMOUSE) mface->flag |= ME_FACE_SEL;
+                                       else mface->flag &= ~ME_FACE_SEL;
+                               }
+                       }
+               }
+               
+               IMB_freeImBuf(ibuf);
+               MEM_freeN(selar);
+
+               BIF_undo_push("Border Select UV face");
+
+// XXX notifier!                       object_tface_flags_changed(OBACT, 0);
+       }
+#ifdef __APPLE__       
+       glReadBuffer(GL_BACK);
+#endif
+}
+
+void uv_autocalc_tface(Scene *scene, ARegion *ar, View3D *v3d, EditMesh *em)
+{
+       short mode;
+#ifndef DISABLE_PYTHON
+//     short i=0, has_pymenu=0; /* pymenu must be bigger then UV_*_MAPPING */
+// XXX BPyMenu *pym;
+//     char menu_number[3];
+#endif
+       
+       /* uvmenu, will add python items */
+       char uvmenu[4096]=MENUTITLE("UV Calculation")
+                                       MENUSTRING("Unwrap",                            UV_UNWRAP_MAPPING) "|%l|"
+                                       
+                                       MENUSTRING("Cube Projection",                   UV_CUBE_MAPPING) "|"
+                                       MENUSTRING("Cylinder from View",                UV_CYL_MAPPING) "|"
+                                       MENUSTRING("Sphere from View",                  UV_SPHERE_MAPPING) "|%l|"
+
+                                       MENUSTRING("Project From View",                 UV_WINDOW_MAPPING) "|"
+                                       MENUSTRING("Project from View (Bounds)",UV_BOUNDS_MAPPING) "|%l|"
+                                       
+                                       MENUSTRING("Reset",                                             UV_RESET_MAPPING);
+#ifndef DISABLE_PYTHON
+#if 0
+       XXX
+       /* note that we account for the 10 previous entries with i+10: */
+       for (pym = BPyMenuTable[PYMENU_UVCALCULATION]; pym; pym = pym->next, i++) {
+               
+               if (!has_pymenu) {
+                       strcat(uvmenu, "|%l");
+                       has_pymenu = 1;
+               }
+               
+               strcat(uvmenu, "|");
+               strcat(uvmenu, pym->name);
+               strcat(uvmenu, " %x");
+               sprintf(menu_number, "%d", i+10);
+               strcat(uvmenu, menu_number);
+       }
+#endif
+#endif
+       
+       mode= pupmenu(uvmenu);
+#ifndef DISABLE_PYTHON
+//     if (mode >= 10) {
+//             BPY_menu_do_python(PYMENU_UVCALCULATION, mode - 10);
+//             return;
+//     }
+#endif 
+       switch(mode) {
+       case UV_CUBE_MAPPING:
+               calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_CUBE); break;
+       case UV_CYL_MAPPING:
+               calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_CYLINDER); break;
+       case UV_SPHERE_MAPPING:
+               calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_SPHERE); break;
+       case UV_BOUNDS_MAPPING:
+               calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_BOUNDS); break;
+       case UV_RESET_MAPPING:
+               calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_RESET); break;
+       case UV_WINDOW_MAPPING:
+               calculate_uv_map(scene, ar, v3d, em, B_UVAUTO_WINDOW); break;
+       case UV_UNWRAP_MAPPING:
+// XXX         unwrap_lscm(0); 
+               break;
+       }
+}
+
+/* Texture Paint */
+
+void set_texturepaint(Scene *scene) /* toggle */
+{
+       Object *ob = OBACT;
+       Mesh *me = 0;
+       
+       if(ob==NULL) return;
+       
+       if (object_data_is_libdata(ob)) {
+// XXX         error_libdata();
+               return;
+       }
+
+       me= get_mesh(ob);
+       
+       if(me)
+               DAG_object_flush_update(scene, ob, OB_RECALC_DATA);
+
+       if(G.f & G_TEXTUREPAINT) {
+               G.f &= ~G_TEXTUREPAINT;
+               GPU_paint_set_mipmap(1);
+       }
+       else if (me) {
+               G.f |= G_TEXTUREPAINT;
+
+               if(me->mtface==NULL)
+                       make_tfaces(me);
+
+               brush_check_exists(&scene->toolsettings->imapaint.brush);
+               GPU_paint_set_mipmap(0);
+       }
+
+}
+
+static void texpaint_project(Object *ob, float *model, float *proj, float *co, float *pco)
+{
+       VECCOPY(pco, co);
+       pco[3]= 1.0f;
+
+       Mat4MulVecfl(ob->obmat, pco);
+       Mat4MulVecfl((float(*)[4])model, pco);
+       Mat4MulVec4fl((float(*)[4])proj, pco);
+}
+
+static void texpaint_tri_weights(Object *ob, float *v1, float *v2, float *v3, float *co, float *w)
+{
+       float pv1[4], pv2[4], pv3[4], h[3], divw;
+       float model[16], proj[16], wmat[3][3], invwmat[3][3];
+       GLint view[4];
+
+       /* compute barycentric coordinates */
+
+       /* get the needed opengl matrices */
+       glGetIntegerv(GL_VIEWPORT, view);
+       glGetFloatv(GL_MODELVIEW_MATRIX, model);
+       glGetFloatv(GL_PROJECTION_MATRIX, proj);
+       view[0] = view[1] = 0;
+
+       /* project the verts */
+       texpaint_project(ob, model, proj, v1, pv1);
+       texpaint_project(ob, model, proj, v2, pv2);
+       texpaint_project(ob, model, proj, v3, pv3);
+
+       /* do inverse view mapping, see gluProject man page */
+       h[0]= (co[0] - view[0])*2.0f/view[2] - 1;
+       h[1]= (co[1] - view[1])*2.0f/view[3] - 1;
+       h[2]= 1.0f;
+
+       /* solve for (w1,w2,w3)/perspdiv in:
+          h*perspdiv = Project*Model*(w1*v1 + w2*v2 + w3*v3) */
+
+       wmat[0][0]= pv1[0];  wmat[1][0]= pv2[0];  wmat[2][0]= pv3[0];
+       wmat[0][1]= pv1[1];  wmat[1][1]= pv2[1];  wmat[2][1]= pv3[1];
+       wmat[0][2]= pv1[3];  wmat[1][2]= pv2[3];  wmat[2][2]= pv3[3];
+
+       Mat3Inv(invwmat, wmat);
+       Mat3MulVecfl(invwmat, h);
+
+       VECCOPY(w, h);
+
+       /* w is still divided by perspdiv, make it sum to one */
+       divw= w[0] + w[1] + w[2];
+       if(divw != 0.0f)
+               VecMulf(w, 1.0f/divw);
+}
+
+/* compute uv coordinates of mouse in face */
+void texpaint_pick_uv(Object *ob, Mesh *mesh, unsigned int faceindex, short *xy, float *uv)
+{
+       DerivedMesh *dm = mesh_get_derived_final(ob, CD_MASK_BAREMESH);
+       int *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+       MTFace *tface = dm->getFaceDataArray(dm, CD_MTFACE), *tf;
+       int numfaces = dm->getNumFaces(dm), a;
+       float p[2], w[3], absw, minabsw;
+       MFace mf;
+       MVert mv[4];
+
+       minabsw = 1e10;
+       uv[0] = uv[1] = 0.0;
+
+// XXX persp(PERSP_VIEW);
+
+       /* test all faces in the derivedmesh with the original index of the picked face */
+       for (a = 0; a < numfaces; a++) {
+               if (index[a] == faceindex) {
+                       dm->getFace(dm, a, &mf);
+
+                       dm->getVert(dm, mf.v1, &mv[0]);
+                       dm->getVert(dm, mf.v2, &mv[1]);
+                       dm->getVert(dm, mf.v3, &mv[2]);
+                       if (mf.v4)
+                               dm->getVert(dm, mf.v4, &mv[3]);
+
+                       tf= &tface[a];
+
+                       p[0]= xy[0];
+                       p[1]= xy[1];
+
+                       if (mf.v4) {
+                               /* the triangle with the largest absolute values is the one
+                                  with the most negative weights */
+                               texpaint_tri_weights(ob, mv[0].co, mv[1].co, mv[3].co, p, w);
+                               absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
+                               if(absw < minabsw) {
+                                       uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[3][0]*w[2];
+                                       uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[3][1]*w[2];
+                                       minabsw = absw;
+                               }
+
+                               texpaint_tri_weights(ob, mv[1].co, mv[2].co, mv[3].co, p, w);
+                               absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
+                               if (absw < minabsw) {
+                                       uv[0]= tf->uv[1][0]*w[0] + tf->uv[2][0]*w[1] + tf->uv[3][0]*w[2];
+                                       uv[1]= tf->uv[1][1]*w[0] + tf->uv[2][1]*w[1] + tf->uv[3][1]*w[2];
+                                       minabsw = absw;
+                               }
+                       }
+                       else {
+                               texpaint_tri_weights(ob, mv[0].co, mv[1].co, mv[2].co, p, w);
+                               absw= fabs(w[0]) + fabs(w[1]) + fabs(w[2]);
+                               if (absw < minabsw) {
+                                       uv[0]= tf->uv[0][0]*w[0] + tf->uv[1][0]*w[1] + tf->uv[2][0]*w[2];
+                                       uv[1]= tf->uv[0][1]*w[0] + tf->uv[1][1]*w[1] + tf->uv[2][1]*w[2];
+                                       minabsw = absw;
+                               }
+                       }
+               }
+       }
+
+       dm->release(dm);
+}
diff --git a/source/blender/editors/mesh/editmesh.c b/source/blender/editors/mesh/editmesh.c
new file mode 100644 (file)
index 0000000..e64667e
--- /dev/null
@@ -0,0 +1,2190 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * Contributor(s): Blender Foundation, full recode 2002-2008
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+#include "DNA_customdata_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_object_force.h"
+#include "DNA_screen_types.h"
+#include "DNA_key_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_view3d_types.h"
+#include "DNA_material_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_userdef_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+#include "BLI_dynstr.h"
+#include "BLI_rand.h"
+
+#include "BKE_DerivedMesh.h"
+#include "BKE_cloth.h"
+#include "BKE_customdata.h"
+#include "BKE_context.h"
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_multires.h"
+#include "BKE_object.h"
+#include "BKE_pointcache.h"
+#include "BKE_softbody.h"
+#include "BKE_texture.h"
+#include "BKE_utildefines.h"
+
+#include "LBM_fluidsim.h"
+
+#include "BIF_retopo.h"
+
+#include "ED_mesh.h"
+
+/* own include */
+#include "editmesh.h"
+
+/* 
+editmesh.c:
+       - add/alloc/free data
+       - hashtables
+       - enter/exit editmode
+*/
+
+/* XXX */
+static void BIF_undo_push() {}
+static void waitcursor() {}
+static void error() {}
+static int pupmenu() {return 0;}
+static void key_to_mesh() {}
+static void undo_editmode_clear() {}
+static int multires_test() {return 0;}
+static void adduplicate() {}
+static void *undo_editmode_get_prev() {return NULL;}
+static void undo_editmode_push() {}
+
+
+/* ***************** HASH ********************* */
+
+
+#define EDHASHSIZE             (512*512)
+#define EDHASH(a, b)   (a % EDHASHSIZE)
+
+
+/* ************ ADD / REMOVE / FIND ****************** */
+
+static void *calloc_em(EditMesh *em, size_t size, size_t nr)
+{
+       return calloc(size, nr);
+}
+
+/* used to bypass normal calloc with fast one */
+static void *(*callocvert)(EditMesh *, size_t, size_t) = calloc_em;
+static void *(*callocedge)(EditMesh *, size_t, size_t) = calloc_em;
+static void *(*callocface)(EditMesh *, size_t, size_t) = calloc_em;
+
+EditVert *addvertlist(EditMesh *em, float *vec, EditVert *example)
+{
+       EditVert *eve;
+       static int hashnr= 0;
+
+       eve= callocvert(em, sizeof(EditVert), 1);
+       BLI_addtail(&em->verts, eve);
+       
+       if(vec) VECCOPY(eve->co, vec);
+
+       eve->hash= hashnr++;
+       if( hashnr>=EDHASHSIZE) hashnr= 0;
+
+       /* new verts get keyindex of -1 since they did not
+        * have a pre-editmode vertex order
+        */
+       eve->keyindex = -1;
+
+       if(example) {
+               CustomData_em_copy_data(&em->vdata, &em->vdata, example->data, &eve->data);
+               eve->bweight = example->bweight;
+       }
+       else {
+               CustomData_em_set_default(&em->vdata, &eve->data);
+       }
+
+       return eve;
+}
+
+void free_editvert (EditMesh *em, EditVert *eve)
+{
+
+       EM_remove_selection(em, eve, EDITVERT);
+       CustomData_em_free_block(&em->vdata, &eve->data);
+       if(eve->fast==0)
+               free(eve);
+}
+
+
+EditEdge *findedgelist(EditMesh *em, EditVert *v1, EditVert *v2)
+{
+       EditVert *v3;
+       struct HashEdge *he;
+
+       /* swap ? */
+       if( v1 > v2) {
+               v3= v2; 
+               v2= v1; 
+               v1= v3;
+       }
+       
+       if(em->hashedgetab==NULL)
+               em->hashedgetab= MEM_callocN(EDHASHSIZE*sizeof(struct HashEdge), "hashedgetab");
+
+       he= em->hashedgetab + EDHASH(v1->hash, v2->hash);
+       
+       while(he) {
+               
+               if(he->eed && he->eed->v1==v1 && he->eed->v2==v2) return he->eed;
+               
+               he= he->next;
+       }
+       return 0;
+}
+
+static void insert_hashedge(EditMesh *em, EditEdge *eed)
+{
+       /* assuming that eed is not in the list yet, and that a find has been done before */
+       
+       struct HashEdge *first, *he;
+
+       first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
+
+       if( first->eed==0 ) {
+               first->eed= eed;
+       }
+       else {
+               he= &eed->hash; 
+               he->eed= eed;
+               he->next= first->next;
+               first->next= he;
+       }
+}
+
+static void remove_hashedge(EditMesh *em, EditEdge *eed)
+{
+       /* assuming eed is in the list */
+       
+       struct HashEdge *first, *he, *prev=NULL;
+
+       he=first= em->hashedgetab + EDHASH(eed->v1->hash, eed->v2->hash);
+
+       while(he) {
+               if(he->eed == eed) {
+                       /* remove from list */
+                       if(he==first) {
+                               if(first->next) {
+                                       he= first->next;
+                                       first->eed= he->eed;
+                                       first->next= he->next;
+                               }
+                               else he->eed= 0;
+                       }
+                       else {
+                               prev->next= he->next;
+                       }
+                       return;
+               }
+               prev= he;
+               he= he->next;
+       }
+}
+
+EditEdge *addedgelist(EditMesh *em, EditVert *v1, EditVert *v2, EditEdge *example)
+{
+       EditVert *v3;
+       EditEdge *eed;
+       int swap= 0;
+       
+       if(v1==v2) return NULL;
+       if(v1==NULL || v2==NULL) return NULL;
+
+       /* swap ? */
+       if(v1>v2) {
+               v3= v2; 
+               v2= v1; 
+               v1= v3;
+               swap= 1;
+       }
+       
+       /* find in hashlist */
+       eed= findedgelist(em, v1, v2);
+
+       if(eed==NULL) {
+       
+               eed= (EditEdge *)callocedge(em, sizeof(EditEdge), 1);
+               eed->v1= v1;
+               eed->v2= v2;
+               BLI_addtail(&em->edges, eed);
+               eed->dir= swap;
+               insert_hashedge(em, eed);
+               
+               /* copy edge data:
+                  rule is to do this with addedgelist call, before addfacelist */
+               if(example) {
+                       eed->crease= example->crease;
+                       eed->bweight= example->bweight;
+                       eed->sharp = example->sharp;
+                       eed->seam = example->seam;
+                       eed->h |= (example->h & EM_FGON);
+               }
+       }
+
+       return eed;
+}
+
+void remedge(EditMesh *em, EditEdge *eed)
+{
+
+       BLI_remlink(&em->edges, eed);
+       remove_hashedge(em, eed);
+}
+
+void free_editedge(EditMesh *em, EditEdge *eed)
+{
+       EM_remove_selection(em, eed, EDITEDGE);
+       if(eed->fast==0){ 
+               free(eed);
+       }
+}
+
+void free_editface(EditMesh *em, EditFace *efa)
+{
+
+       EM_remove_selection(em, efa, EDITFACE);
+       
+       if (em->act_face==efa) {
+               EM_set_actFace(em, em->faces.first == efa ? NULL : em->faces.first);
+       }
+               
+       CustomData_em_free_block(&em->fdata, &efa->data);
+       if(efa->fast==0)
+               free(efa);
+}
+
+void free_vertlist(EditMesh *em, ListBase *edve) 
+{
+       EditVert *eve, *next;
+
+       if (!edve) return;
+
+       eve= edve->first;
+       while(eve) {
+               next= eve->next;
+               free_editvert(em, eve);
+               eve= next;
+       }
+       edve->first= edve->last= NULL;
+}
+
+void free_edgelist(EditMesh *em, ListBase *lb)
+{
+       EditEdge *eed, *next;
+       
+       eed= lb->first;
+       while(eed) {
+               next= eed->next;
+               free_editedge(em, eed);
+               eed= next;
+       }
+       lb->first= lb->last= NULL;
+}
+
+void free_facelist(EditMesh *em, ListBase *lb)
+{
+       EditFace *efa, *next;
+       
+       efa= lb->first;
+       while(efa) {
+               next= efa->next;
+               free_editface(em, efa);
+               efa= next;
+       }
+       lb->first= lb->last= NULL;
+}
+
+EditFace *addfacelist(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4, EditFace *example, EditFace *exampleEdges)
+{
+       EditFace *efa;
+       EditEdge *e1, *e2=0, *e3=0, *e4=0;
+
+       /* added sanity check... seems to happen for some tools, or for enter editmode for corrupted meshes */
+       if(v1==v4 || v2==v4 || v3==v4) v4= NULL;
+       
+       /* add face to list and do the edges */
+       if(exampleEdges) {
+               e1= addedgelist(em, v1, v2, exampleEdges->e1);
+               e2= addedgelist(em, v2, v3, exampleEdges->e2);
+               if(v4) e3= addedgelist(em, v3, v4, exampleEdges->e3); 
+               else e3= addedgelist(em, v3, v1, exampleEdges->e3);
+               if(v4) e4= addedgelist(em, v4, v1, exampleEdges->e4);
+       }
+       else {
+               e1= addedgelist(em, v1, v2, NULL);
+               e2= addedgelist(em, v2, v3, NULL);
+               if(v4) e3= addedgelist(em, v3, v4, NULL); 
+               else e3= addedgelist(em, v3, v1, NULL);
+               if(v4) e4= addedgelist(em, v4, v1, NULL);
+       }
+       
+       if(v1==v2 || v2==v3 || v1==v3) return NULL;
+       if(e2==0) return NULL;
+
+       efa= (EditFace *)callocface(em, sizeof(EditFace), 1);
+       efa->v1= v1;
+       efa->v2= v2;
+       efa->v3= v3;
+       efa->v4= v4;
+
+       efa->e1= e1;
+       efa->e2= e2;
+       efa->e3= e3;
+       efa->e4= e4;
+
+       if(example) {
+               efa->mat_nr= example->mat_nr;
+               efa->flag= example->flag;
+               CustomData_em_copy_data(&em->fdata, &em->fdata, example->data, &efa->data);
+       }
+       else {
+               if (G.obedit && G.obedit->actcol)
+                       efa->mat_nr= G.obedit->actcol-1;
+
+               CustomData_em_set_default(&em->fdata, &efa->data);
+       }
+
+       BLI_addtail(&em->faces, efa);
+
+       if(efa->v4) {
+               CalcNormFloat4(efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co, efa->n);
+               CalcCent4f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co, efa->v4->co);
+       }
+       else {
+               CalcNormFloat(efa->v1->co, efa->v2->co, efa->v3->co, efa->n);
+               CalcCent3f(efa->cent, efa->v1->co, efa->v2->co, efa->v3->co);
+       }
+
+       return efa;
+}
+
+/* ************************ end add/new/find ************  */
+
+/* ************************ Edit{Vert,Edge,Face} utilss ***************************** */
+
+/* some nice utility functions */
+
+EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve)
+{
+       if (eve==eed->v1) {
+               return eed->v2;
+       } else if (eve==eed->v2) {
+               return eed->v1;
+       } else {
+               return NULL;
+       }
+}
+
+EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2) 
+{
+       if (eed->v1==eed2->v1 || eed->v1==eed2->v2) {
+               return eed->v1;
+       } else if (eed->v2==eed2->v1 || eed->v2==eed2->v2) {
+               return eed->v2;
+       } else {
+               return NULL;
+       }
+}
+
+int editedge_containsVert(EditEdge *eed, EditVert *eve) 
+{
+       return (eed->v1==eve || eed->v2==eve);
+}
+
+int editface_containsVert(EditFace *efa, EditVert *eve) 
+{
+       return (efa->v1==eve || efa->v2==eve || efa->v3==eve || (efa->v4 && efa->v4==eve));
+}
+
+int editface_containsEdge(EditFace *efa, EditEdge *eed) 
+{
+       return (efa->e1==eed || efa->e2==eed || efa->e3==eed || (efa->e4 && efa->e4==eed));
+}
+
+
+/* ************************ stuct EditMesh manipulation ***************************** */
+
+/* fake callocs for fastmalloc below */
+static void *calloc_fastvert(EditMesh *em, size_t size, size_t nr)
+{
+       EditVert *eve= em->curvert++;
+       eve->fast= 1;
+       return eve;
+}
+static void *calloc_fastedge(EditMesh *em, size_t size, size_t nr)
+{
+       EditEdge *eed= em->curedge++;
+       eed->fast= 1;
+       return eed;
+}
+static void *calloc_fastface(EditMesh *em, size_t size, size_t nr)
+{
+       EditFace *efa= em->curface++;
+       efa->fast= 1;
+       return efa;
+}
+
+/* allocate 1 chunk for all vertices, edges, faces. These get tagged to
+   prevent it from being freed
+*/
+static void init_editmesh_fastmalloc(EditMesh *em, int totvert, int totedge, int totface)
+{
+       if(totvert) em->allverts= MEM_callocN(totvert*sizeof(EditVert), "allverts");
+       else em->allverts= NULL;
+       em->curvert= em->allverts;
+       
+       if(totedge==0) totedge= 4*totface;      // max possible
+
+       if(totedge) em->alledges= MEM_callocN(totedge*sizeof(EditEdge), "alledges");
+       else em->alledges= NULL;
+       em->curedge= em->alledges;
+       
+       if(totface) em->allfaces= MEM_callocN(totface*sizeof(EditFace), "allfaces");
+       else em->allfaces= NULL;
+       em->curface= em->allfaces;
+
+       callocvert= calloc_fastvert;
+       callocedge= calloc_fastedge;
+       callocface= calloc_fastface;
+}
+
+static void end_editmesh_fastmalloc(void)
+{
+       callocvert= calloc_em;
+       callocedge= calloc_em;
+       callocface= calloc_em;
+}
+
+/* do not free editmesh itself here */
+void free_editMesh(EditMesh *em)
+{
+       if(em==NULL) return;
+
+       if(em->verts.first) free_vertlist(em, &em->verts);
+       if(em->edges.first) free_edgelist(em, &em->edges);
+       if(em->faces.first) free_facelist(em, &em->faces);
+       if(em->selected.first) BLI_freelistN(&(em->selected));
+
+       CustomData_free(&em->vdata, 0);
+       CustomData_free(&em->fdata, 0);
+
+       if(em->derivedFinal) {
+               if (em->derivedFinal!=em->derivedCage) {
+                       em->derivedFinal->needsFree= 1;
+                       em->derivedFinal->release(em->derivedFinal);
+               }
+               em->derivedFinal= NULL;
+       }
+       if(em->derivedCage) {
+               em->derivedCage->needsFree= 1;
+               em->derivedCage->release(em->derivedCage);
+               em->derivedCage= NULL;
+       }
+
+       /* DEBUG: hashtabs are slowest part of enter/exit editmode. here a testprint */
+#if 0
+       if(em->hashedgetab) {
+               HashEdge *he, *hen;
+               int a, used=0, max=0, nr;
+               he= em->hashedgetab;
+               for(a=0; a<EDHASHSIZE; a++, he++) {
+                       if(he->eed) used++;
+                       hen= he->next;
+                       nr= 0;
+                       while(hen) {
+                               nr++;
+                               hen= hen->next;
+                       }
+                       if(max<nr) max= nr;
+               }
+               printf("hastab used %d max %d\n", used, max);
+       }
+#endif
+       if(em->hashedgetab) MEM_freeN(em->hashedgetab);
+       em->hashedgetab= NULL;
+       
+       if(em->allverts) MEM_freeN(em->allverts);
+       if(em->alledges) MEM_freeN(em->alledges);
+       if(em->allfaces) MEM_freeN(em->allfaces);
+       
+       em->allverts= em->curvert= NULL;
+       em->alledges= em->curedge= NULL;
+       em->allfaces= em->curface= NULL;
+       
+       mesh_octree_table(NULL, NULL, NULL, 'e');
+       
+       G.totvert= G.totface= 0;
+
+// XXX if(em->retopo_paint_data) retopo_free_paint_data(em->retopo_paint_data);
+       em->retopo_paint_data= NULL;
+       em->act_face = NULL;
+}
+
+static void editMesh_set_hash(EditMesh *em)
+{
+       EditEdge *eed;
+
+       em->hashedgetab= NULL;
+       
+       for(eed=em->edges.first; eed; eed= eed->next)  {
+               if( findedgelist(em, eed->v1, eed->v2)==NULL )
+                       insert_hashedge(em, eed);
+       }
+
+}
+
+
+/* ************************ IN & OUT EDITMODE ***************************** */
+
+
+static void edge_normal_compare(EditEdge *eed, EditFace *efa1)
+{
+       EditFace *efa2;
+       float cent1[3], cent2[3];
+       float inp;
+       
+       efa2 = eed->tmp.f;
+       if(efa1==efa2) return;
+       
+       inp= efa1->n[0]*efa2->n[0] + efa1->n[1]*efa2->n[1] + efa1->n[2]*efa2->n[2];
+       if(inp<0.999 && inp >-0.999) eed->f2= 1;
+               
+       if(efa1->v4) CalcCent4f(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co, efa1->v4->co);
+       else CalcCent3f(cent1, efa1->v1->co, efa1->v2->co, efa1->v3->co);
+       if(efa2->v4) CalcCent4f(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co, efa2->v4->co);
+       else CalcCent3f(cent2, efa2->v1->co, efa2->v2->co, efa2->v3->co);
+       
+       VecSubf(cent1, cent2, cent1);
+       Normalize(cent1);
+       inp= cent1[0]*efa1->n[0] + cent1[1]*efa1->n[1] + cent1[2]*efa1->n[2]; 
+
+       if(inp < -0.001 ) eed->f1= 1;
+}
+
+#if 0
+typedef struct {
+       EditEdge *eed;
+       float noLen,no[3];
+       int adjCount;
+} EdgeDrawFlagInfo;
+
+static int edgeDrawFlagInfo_cmp(const void *av, const void *bv)
+{
+       const EdgeDrawFlagInfo *a = av;
+       const EdgeDrawFlagInfo *b = bv;
+
+       if (a->noLen<b->noLen) return -1;
+       else if (a->noLen>b->noLen) return 1;
+       else return 0;
+}
+#endif
+
+static void edge_drawflags(EditMesh *em)
+{
+       EditVert *eve;
+       EditEdge *eed, *e1, *e2, *e3, *e4;
+       EditFace *efa;
+       
+       /* - count number of times edges are used in faces: 0 en 1 time means draw edge
+        * - edges more than 1 time used: in *tmp.f is pointer to first face
+        * - check all faces, when normal differs to much: draw (flag becomes 1)
+        */
+
+       /* later on: added flags for 'cylinder' and 'sphere' intersection tests in old
+          game engine (2.04)
+        */
+       
+       recalc_editnormals(em);
+       
+       /* init */
+       eve= em->verts.first;
+       while(eve) {
+               eve->f1= 1;             /* during test it's set at zero */
+               eve= eve->next;
+       }
+       eed= em->edges.first;
+       while(eed) {
+               eed->f2= eed->f1= 0;
+               eed->tmp.f = 0;
+               eed= eed->next;
+       }
+
+       efa= em->faces.first;
+       while(efa) {
+               e1= efa->e1;
+               e2= efa->e2;
+               e3= efa->e3;
+               e4= efa->e4;
+               if(e1->f2<4) e1->f2+= 1;
+               if(e2->f2<4) e2->f2+= 1;
+               if(e3->f2<4) e3->f2+= 1;
+               if(e4 && e4->f2<4) e4->f2+= 1;
+               
+               if(e1->tmp.f == 0) e1->tmp.f = (void *) efa;
+               if(e2->tmp.f == 0) e2->tmp.f = (void *) efa;
+               if(e3->tmp.f ==0) e3->tmp.f = (void *) efa;
+               if(e4 && (e4->tmp.f == 0)) e4->tmp.f = (void *) efa;
+               
+               efa= efa->next;
+       }
+
+       if(G.f & G_ALLEDGES) {
+               efa= em->faces.first;
+               while(efa) {
+                       if(efa->e1->f2>=2) efa->e1->f2= 1;
+                       if(efa->e2->f2>=2) efa->e2->f2= 1;
+                       if(efa->e3->f2>=2) efa->e3->f2= 1;
+                       if(efa->e4 && efa->e4->f2>=2) efa->e4->f2= 1;
+                       
+                       efa= efa->next;
+               }               
+       }       
+       else {
+               
+               /* handle single-edges for 'test cylinder flag' (old engine) */
+               
+               eed= em->edges.first;
+               while(eed) {
+                       if(eed->f2==1) eed->f1= 1;
+                       eed= eed->next;
+               }
+
+               /* all faces, all edges with flag==2: compare normal */
+               efa= em->faces.first;
+               while(efa) {
+                       if(efa->e1->f2==2) edge_normal_compare(efa->e1, efa);
+                       else efa->e1->f2= 1;
+                       if(efa->e2->f2==2) edge_normal_compare(efa->e2, efa);
+                       else efa->e2->f2= 1;
+                       if(efa->e3->f2==2) edge_normal_compare(efa->e3, efa);
+                       else efa->e3->f2= 1;
+                       if(efa->e4) {
+                               if(efa->e4->f2==2) edge_normal_compare(efa->e4, efa);
+                               else efa->e4->f2= 1;
+                       }
+                       efa= efa->next;
+               }
+               
+               /* sphere collision flag */
+               
+               eed= em->edges.first;
+               while(eed) {
+                       if(eed->f1!=1) {
+                               eed->v1->f1= eed->v2->f1= 0;
+                       }
+                       eed= eed->next;
+               }
+               
+       }
+}
+
+static int editmesh_pointcache_edit(Scene *scene, Object *ob, int totvert, PTCacheID *pid_p, float mat[][4], int load)
+{
+       Cloth *cloth;
+       SoftBody *sb;
+       ClothModifierData *clmd;
+       PTCacheID pid, tmpid;
+       int cfra= (int)scene->r.cfra, found= 0;
+
+       pid.cache= NULL;
+
+       /* check for cloth */
+       if(modifiers_isClothEnabled(ob)) {
+               clmd= (ClothModifierData*)modifiers_findByType(ob, eModifierType_Cloth);
+               cloth= clmd->clothObject;
+               
+               BKE_ptcache_id_from_cloth(&tmpid, ob, clmd);
+
+               /* verify vertex count and baked status */
+               if(cloth && (totvert == cloth->numverts)) {
+                       if((tmpid.cache->flag & PTCACHE_BAKED) && (tmpid.cache->flag & PTCACHE_BAKE_EDIT)) {
+                               pid= tmpid;
+
+                               if(load && (pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE))
+                                       found= 1;
+                       }
+               }
+       }
+
+       /* check for softbody */
+       if(!found && ob->soft) {
+               sb= ob->soft;
+
+               BKE_ptcache_id_from_softbody(&tmpid, ob, sb);
+
+               /* verify vertex count and baked status */
+               if(sb->bpoint && (totvert == sb->totpoint)) {
+                       if((tmpid.cache->flag & PTCACHE_BAKED) && (tmpid.cache->flag & PTCACHE_BAKE_EDIT)) {
+                               pid= tmpid;
+
+                               if(load && (pid.cache->flag & PTCACHE_BAKE_EDIT_ACTIVE))
+                                       found= 1;
+                       }
+               }
+       }
+
+       /* if not making editmesh verify editing was active for this point cache */
+       if(load) {
+               if(found)
+                       pid.cache->flag &= ~PTCACHE_BAKE_EDIT_ACTIVE;
+               else
+                       return 0;
+       }
+
+       /* check if we have cache for this frame */
+       if(pid.cache && BKE_ptcache_id_exist(&pid, cfra)) {
+               *pid_p = pid;
+               
+               if(load) {
+                       Mat4CpyMat4(mat, ob->obmat);
+               }
+               else {
+                       pid.cache->editframe= cfra;
+                       pid.cache->flag |= PTCACHE_BAKE_EDIT_ACTIVE;
+                       Mat4Invert(mat, ob->obmat); /* ob->imat is not up to date */
+               }
+
+               return 1;
+       }
+
+       return 0;
+}
+
+/* turns Mesh into editmesh */
+void make_editMesh(Scene *scene, EditMesh *em)
+{
+       Mesh *me= G.obedit->data;
+       MFace *mface;
+       MVert *mvert;
+       MSelect *mselect;
+       KeyBlock *actkey;
+       EditVert *eve, **evlist, *eve1, *eve2, *eve3, *eve4;
+       EditFace *efa;
+       EditEdge *eed;
+       EditSelection *ese;
+       PTCacheID pid;
+       Cloth *cloth;
+       SoftBody *sb;
+       float cacheco[3], cachemat[4][4], *co;
+       int tot, a, cacheedit= 0, eekadoodle= 0;
+
+       /* because of reload */
+       free_editMesh(em);
+       
+       em->act_face = NULL;
+       G.totvert= tot= me->totvert;
+       G.totedge= me->totedge;
+       G.totface= me->totface;
+       
+       if(tot==0) {
+               return;
+       }
+       
+       /* initialize fastmalloc for editmesh */
+       init_editmesh_fastmalloc(em, me->totvert, me->totedge, me->totface);
+
+       actkey = ob_get_keyblock(G.obedit);
+       if(actkey) {
+               strcpy(G.editModeTitleExtra, "(Key) ");
+               key_to_mesh(actkey, me);
+               tot= actkey->totelem;
+               /* undo-ing in past for previous editmode sessions gives corrupt 'keyindex' values */
+               undo_editmode_clear();
+       }
+
+       
+       /* make editverts */
+       CustomData_copy(&me->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       mvert= me->mvert;
+
+       cacheedit= editmesh_pointcache_edit(scene, G.obedit, tot, &pid, cachemat, 0);
+
+       evlist= (EditVert **)MEM_mallocN(tot*sizeof(void *),"evlist");
+       for(a=0; a<tot; a++, mvert++) {
+               
+               if(cacheedit) {
+                       if(pid.type == PTCACHE_TYPE_CLOTH) {
+                               cloth= ((ClothModifierData*)pid.data)->clothObject;
+                               VECCOPY(cacheco, cloth->verts[a].x)
+                       }
+                       else if(pid.type == PTCACHE_TYPE_SOFTBODY) {
+                               sb= (SoftBody*)pid.data;
+                               VECCOPY(cacheco, sb->bpoint[a].pos)
+                       }
+
+                       Mat4MulVecfl(cachemat, cacheco);
+                       co= cacheco;
+               }
+               else
+                       co= mvert->co;
+
+               eve= addvertlist(em, co, NULL);
+               evlist[a]= eve;
+               
+               // face select sets selection in next loop
+               if( (FACESEL_PAINT_TEST)==0 )
+                       eve->f |= (mvert->flag & 1);
+               
+               if (mvert->flag & ME_HIDE) eve->h= 1;           
+               eve->no[0]= mvert->no[0]/32767.0;
+               eve->no[1]= mvert->no[1]/32767.0;
+               eve->no[2]= mvert->no[2]/32767.0;
+
+               eve->bweight= ((float)mvert->bweight)/255.0f;
+
+               /* lets overwrite the keyindex of the editvert
+                * with the order it used to be in before
+                * editmode
+                */
+               eve->keyindex = a;
+
+               CustomData_to_em_block(&me->vdata, &em->vdata, a, &eve->data);
+       }
+
+       if(actkey && actkey->totelem!=me->totvert);
+       else {
+               MEdge *medge= me->medge;
+               
+               CustomData_copy(&me->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+               /* make edges */
+               for(a=0; a<me->totedge; a++, medge++) {
+                       eed= addedgelist(em, evlist[medge->v1], evlist[medge->v2], NULL);
+                       /* eed can be zero when v1 and v2 are identical, dxf import does this... */
+                       if(eed) {
+                               eed->crease= ((float)medge->crease)/255.0f;
+                               eed->bweight= ((float)medge->bweight)/255.0f;
+                               
+                               if(medge->flag & ME_SEAM) eed->seam= 1;
+                               if(medge->flag & ME_SHARP) eed->sharp = 1;
+                               if(medge->flag & SELECT) eed->f |= SELECT;
+                               if(medge->flag & ME_FGON) eed->h= EM_FGON;      // 2 different defines!
+                               if(medge->flag & ME_HIDE) eed->h |= 1;
+                               if(em->selectmode==SCE_SELECT_EDGE) 
+                                       EM_select_edge(eed, eed->f & SELECT);           // force edge selection to vertices, seems to be needed ...
+                               CustomData_to_em_block(&me->edata,&em->edata, a, &eed->data);
+                       }
+               }
+               
+               CustomData_copy(&me->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+
+               /* make faces */
+               mface= me->mface;
+
+               for(a=0; a<me->totface; a++, mface++) {
+                       eve1= evlist[mface->v1];
+                       eve2= evlist[mface->v2];
+                       if(!mface->v3) eekadoodle= 1;
+                       eve3= evlist[mface->v3];
+                       if(mface->v4) eve4= evlist[mface->v4]; else eve4= NULL;
+                       
+                       efa= addfacelist(em, eve1, eve2, eve3, eve4, NULL, NULL);
+
+                       if(efa) {
+                               CustomData_to_em_block(&me->fdata, &em->fdata, a, &efa->data);
+
+                               efa->mat_nr= mface->mat_nr;
+                               efa->flag= mface->flag & ~ME_HIDE;
+                               
+                               /* select and hide face flag */
+                               if(mface->flag & ME_HIDE) {
+                                       efa->h= 1;
+                               } else {
+                                       if (a==me->act_face) {
+                                               EM_set_actFace(em, efa);
+                                       }
+                                       
+                                       /* dont allow hidden and selected */
+                                       if(mface->flag & ME_FACE_SEL) {
+                                               efa->f |= SELECT;
+                                               
+                                               if(FACESEL_PAINT_TEST) {
+                                                       EM_select_face(efa, 1); /* flush down */
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       if(eekadoodle)
+               error("This Mesh has old style edgecodes, please put it in the bugtracker!");
+       
+       MEM_freeN(evlist);
+
+       end_editmesh_fastmalloc();      // resets global function pointers
+       
+       if(me->mselect){
+               //restore editselections
+               EM_init_index_arrays(em, 1,1,1);
+               mselect = me->mselect;
+               
+               for(a=0; a<me->totselect; a++, mselect++){
+                       /*check if recorded selection is still valid, if so copy into editmesh*/
+                       if( (mselect->type == EDITVERT && me->mvert[mselect->index].flag & SELECT) || (mselect->type == EDITEDGE && me->medge[mselect->index].flag & SELECT) || (mselect->type == EDITFACE && me->mface[mselect->index].flag & ME_FACE_SEL) ){
+                               ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
+                               ese->type = mselect->type;      
+                               if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(mselect->index); else
+                               if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(mselect->index); else
+                               if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(mselect->index);
+                               BLI_addtail(&(em->selected),ese);
+                       }
+               }
+               EM_free_index_arrays();
+       }
+       /* this creates coherent selections. also needed for older files */
+       EM_selectmode_set(em);
+       /* paranoia check to enforce hide rules */
+       EM_hide_reset(em);
+       /* sets helper flags which arent saved */
+       EM_fgon_flags(em);
+       
+       if (EM_get_actFace(em, 0)==NULL) {
+               EM_set_actFace(em, em->faces.first ); /* will use the first face, this is so we alwats have an active face */
+       }
+               
+       /* vertex coordinates change with cache edit, need to recalc */
+       if(cacheedit)
+               recalc_editnormals(em);
+       
+}
+
+/* makes Mesh out of editmesh */
+void load_editMesh(Scene *scene, EditMesh *em)
+{
+       Mesh *me= G.obedit->data;
+       MVert *mvert, *oldverts;
+       MEdge *medge;
+       MFace *mface;
+       MSelect *mselect;
+       EditVert *eve;
+       EditFace *efa, *efa_act;
+       EditEdge *eed;
+       EditSelection *ese;
+       SoftBody *sb;
+       Cloth *cloth;
+       ClothModifierData *clmd;
+       PTCacheID pid;
+       float *fp, *newkey, *oldkey, nor[3], cacheco[3], cachemat[4][4];
+       int i, a, ototvert, totedge=0, cacheedit= 0;
+       
+       /* this one also tests of edges are not in faces: */
+       /* eed->f2==0: not in face, f2==1: draw it */
+       /* eed->f1 : flag for dynaface (cylindertest, old engine) */
+       /* eve->f1 : flag for dynaface (sphere test, old engine) */
+       /* eve->f2 : being used in vertexnormals */
+       edge_drawflags(em);
+       
+       eed= em->edges.first;
+       while(eed) {
+               totedge++;
+               eed= eed->next;
+       }
+       
+       /* new Vertex block */
+       if(G.totvert==0) mvert= NULL;
+       else mvert= MEM_callocN(G.totvert*sizeof(MVert), "loadeditMesh vert");
+
+       /* new Edge block */
+       if(totedge==0) medge= NULL;
+       else medge= MEM_callocN(totedge*sizeof(MEdge), "loadeditMesh edge");
+       
+       /* new Face block */
+       if(G.totface==0) mface= NULL;
+       else mface= MEM_callocN(G.totface*sizeof(MFace), "loadeditMesh face");
+
+       /* lets save the old verts just in case we are actually working on
+        * a key ... we now do processing of the keys at the end */
+       oldverts= me->mvert;
+       ototvert= me->totvert;
+
+       /* don't free this yet */
+       CustomData_set_layer(&me->vdata, CD_MVERT, NULL);
+
+       /* free custom data */
+       CustomData_free(&me->vdata, me->totvert);
+       CustomData_free(&me->edata, me->totedge);
+       CustomData_free(&me->fdata, me->totface);
+
+       /* add new custom data */
+       me->totvert= G.totvert;
+       me->totedge= totedge;
+       me->totface= G.totface;
+
+       CustomData_copy(&em->vdata, &me->vdata, CD_MASK_MESH, CD_CALLOC, me->totvert);
+       CustomData_copy(&em->edata, &me->edata, CD_MASK_MESH, CD_CALLOC, me->totedge);
+       CustomData_copy(&em->fdata, &me->fdata, CD_MASK_MESH, CD_CALLOC, me->totface);
+
+       CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, mvert, me->totvert);
+       CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, medge, me->totedge);
+       CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, mface, me->totface);
+       mesh_update_customdata_pointers(me);
+
+       /* the vertices, use ->tmp.l as counter */
+       eve= em->verts.first;
+       a= 0;
+
+       /* check for point cache editing */
+       cacheedit= editmesh_pointcache_edit(scene, G.obedit, G.totvert, &pid, cachemat, 1);
+
+       while(eve) {
+               if(cacheedit) {
+                       if(pid.type == PTCACHE_TYPE_CLOTH) {
+                               clmd= (ClothModifierData*)pid.data;
+                               cloth= clmd->clothObject;
+
+                               /* assign position */
+                               VECCOPY(cacheco, cloth->verts[a].x)
+                               VECCOPY(cloth->verts[a].x, eve->co);
+                               Mat4MulVecfl(cachemat, cloth->verts[a].x);
+
+                               /* find plausible velocity, not physical correct but gives
+                                * nicer results when commented */
+                               VECSUB(cacheco, cloth->verts[a].x, cacheco);
+                               VecMulf(cacheco, clmd->sim_parms->stepsPerFrame*10.0f);
+                               VECADD(cloth->verts[a].v, cloth->verts[a].v, cacheco);
+                       }
+                       else if(pid.type == PTCACHE_TYPE_SOFTBODY) {
+                               sb= (SoftBody*)pid.data;
+
+                               /* assign position */
+                               VECCOPY(cacheco, sb->bpoint[a].pos)
+                               VECCOPY(sb->bpoint[a].pos, eve->co);
+                               Mat4MulVecfl(cachemat, sb->bpoint[a].pos);
+
+                               /* changing velocity for softbody doesn't seem to give
+                                * good results? */
+#if 0
+                               VECSUB(cacheco, sb->bpoint[a].pos, cacheco);
+                               VecMulf(cacheco, sb->minloops*10.0f);
+                               VECADD(sb->bpoint[a].vec, sb->bpoint[a].pos, cacheco);
+#endif
+                       }
+
+                       if(oldverts)
+                               VECCOPY(mvert->co, oldverts[a].co)
+               }
+               else
+                       VECCOPY(mvert->co, eve->co);
+
+               mvert->mat_nr= 255;  /* what was this for, halos? */
+               
+               /* vertex normal */
+               VECCOPY(nor, eve->no);
+               VecMulf(nor, 32767.0);
+               VECCOPY(mvert->no, nor);
+
+               /* note: it used to remove me->dvert when it was not in use, cancelled
+                  that... annoying when you have a fresh vgroup */
+               CustomData_from_em_block(&em->vdata, &me->vdata, eve->data, a);
+
+               eve->tmp.l = a++;  /* counter */
+                       
+               mvert->flag= 0;
+               if(eve->f1==1) mvert->flag |= ME_SPHERETEST;
+               mvert->flag |= (eve->f & SELECT);
+               if (eve->h) mvert->flag |= ME_HIDE;
+               mvert->bweight= (char)(255.0*eve->bweight);
+
+               eve= eve->next;
+               mvert++;
+       }
+       
+       /* write changes to cache */
+       if(cacheedit) {
+               if(pid.type == PTCACHE_TYPE_CLOTH)
+                       cloth_write_cache(G.obedit, pid.data, pid.cache->editframe);
+               else if(pid.type == PTCACHE_TYPE_SOFTBODY)
+                       sbWriteCache(G.obedit, pid.cache->editframe);
+       }
+
+       /* the edges */
+       a= 0;
+       eed= em->edges.first;
+       while(eed) {
+               medge->v1= (unsigned int) eed->v1->tmp.l;
+               medge->v2= (unsigned int) eed->v2->tmp.l;
+               
+               medge->flag= (eed->f & SELECT) | ME_EDGERENDER;
+               if(eed->f2<2) medge->flag |= ME_EDGEDRAW;
+               if(eed->f2==0) medge->flag |= ME_LOOSEEDGE;
+               if(eed->sharp) medge->flag |= ME_SHARP;
+               if(eed->seam) medge->flag |= ME_SEAM;
+               if(eed->h & EM_FGON) medge->flag |= ME_FGON;    // different defines yes
+               if(eed->h & 1) medge->flag |= ME_HIDE;
+               
+               medge->crease= (char)(255.0*eed->crease);
+               medge->bweight= (char)(255.0*eed->bweight);
+               CustomData_from_em_block(&em->edata, &me->edata, eed->data, a);         
+
+               eed->tmp.l = a++;
+               
+               medge++;
+               eed= eed->next;
+       }
+
+       /* the faces */
+       a = 0;
+       efa= em->faces.first;
+       efa_act= EM_get_actFace(em, 0);
+       i = 0;
+       me->act_face = -1;
+       while(efa) {
+               mface= &((MFace *) me->mface)[i];
+               
+               mface->v1= (unsigned int) efa->v1->tmp.l;
+               mface->v2= (unsigned int) efa->v2->tmp.l;
+               mface->v3= (unsigned int) efa->v3->tmp.l;
+               if (efa->v4) mface->v4 = (unsigned int) efa->v4->tmp.l;
+
+               mface->mat_nr= efa->mat_nr;
+               
+               mface->flag= efa->flag;
+               /* bit 0 of flag is already taken for smooth... */
+               
+               if(efa->h) {
+                       mface->flag |= ME_HIDE;
+                       mface->flag &= ~ME_FACE_SEL;
+               } else {
+                       if(efa->f & 1) mface->flag |= ME_FACE_SEL;
+                       else mface->flag &= ~ME_FACE_SEL;
+               }
+               
+               /* mat_nr in vertex */
+               if(me->totcol>1) {
+                       mvert= me->mvert+mface->v1;
+                       if(mvert->mat_nr == (char)255) mvert->mat_nr= mface->mat_nr;
+                       mvert= me->mvert+mface->v2;
+                       if(mvert->mat_nr == (char)255) mvert->mat_nr= mface->mat_nr;
+                       mvert= me->mvert+mface->v3;
+                       if(mvert->mat_nr == (char)255) mvert->mat_nr= mface->mat_nr;
+                       if(mface->v4) {
+                               mvert= me->mvert+mface->v4;
+                               if(mvert->mat_nr == (char)255) mvert->mat_nr= mface->mat_nr;
+                       }
+               }
+                       
+               /* watch: efa->e1->f2==0 means loose edge */ 
+                       
+               if(efa->e1->f2==1) {
+                       efa->e1->f2= 2;
+               }                       
+               if(efa->e2->f2==1) {
+                       efa->e2->f2= 2;
+               }
+               if(efa->e3->f2==1) {
+                       efa->e3->f2= 2;
+               }
+               if(efa->e4 && efa->e4->f2==1) {
+                       efa->e4->f2= 2;
+               }
+
+               CustomData_from_em_block(&em->fdata, &me->fdata, efa->data, i);
+
+               /* no index '0' at location 3 or 4 */
+               test_index_face(mface, &me->fdata, i, efa->v4?4:3);
+               
+               if (efa_act == efa)
+                       me->act_face = a;
+
+               efa->tmp.l = a++;
+               i++;
+               efa= efa->next;
+       }
+
+       /* patch hook indices and vertex parents */
+       {
+               Object *ob;
+               ModifierData *md;
+               EditVert **vertMap = NULL;
+               int i,j;
+
+               for (ob=G.main->object.first; ob; ob=ob->id.next) {
+                       if (ob->parent==G.obedit && ELEM(ob->partype, PARVERT1,PARVERT3)) {
+                               
+                               /* duplicate code from below, make it function later...? */
+                               if (!vertMap) {
+                                       vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
+                                       
+                                       for (eve=em->verts.first; eve; eve=eve->next) {
+                                               if (eve->keyindex!=-1)
+                                                       vertMap[eve->keyindex] = eve;
+                                       }
+                               }
+                               if(ob->par1 < ototvert) {
+                                       eve = vertMap[ob->par1];
+                                       if(eve) ob->par1= eve->tmp.l;
+                               }
+                               if(ob->par2 < ototvert) {
+                                       eve = vertMap[ob->par2];
+                                       if(eve) ob->par2= eve->tmp.l;
+                               }
+                               if(ob->par3 < ototvert) {
+                                       eve = vertMap[ob->par3];
+                                       if(eve) ob->par3= eve->tmp.l;
+                               }
+                               
+                       }
+                       if (ob->data==me) {
+                               for (md=ob->modifiers.first; md; md=md->next) {
+                                       if (md->type==eModifierType_Hook) {
+                                               HookModifierData *hmd = (HookModifierData*) md;
+
+                                               if (!vertMap) {
+                                                       vertMap = MEM_callocN(sizeof(*vertMap)*ototvert, "vertMap");
+
+                                                       for (eve=em->verts.first; eve; eve=eve->next) {
+                                                               if (eve->keyindex!=-1)
+                                                                       vertMap[eve->keyindex] = eve;
+                                                       }
+                                               }
+                                               
+                                               for (i=j=0; i<hmd->totindex; i++) {
+                                                       if(hmd->indexar[i] < ototvert) {
+                                                               eve = vertMap[hmd->indexar[i]];
+                                                               
+                                                               if (eve) {
+                                                                       hmd->indexar[j++] = eve->tmp.l;
+                                                               }
+                                                       }
+                                                       else j++;
+                                               }
+
+                                               hmd->totindex = j;
+                                       }
+                               }
+                       }
+               }
+
+               if (vertMap) MEM_freeN(vertMap);
+       }
+
+       /* are there keys? */
+       if(me->key) {
+               KeyBlock *currkey, *actkey = ob_get_keyblock(G.obedit);
+
+               /* Lets reorder the key data so that things line up roughly
+                * with the way things were before editmode */
+               currkey = me->key->block.first;
+               while(currkey) {
+                       
+                       fp= newkey= MEM_callocN(me->key->elemsize*G.totvert,  "currkey->data");
+                       oldkey = currkey->data;
+
+                       eve= em->verts.first;
+
+                       i = 0;
+                       mvert = me->mvert;
+                       while(eve) {
+                               if (eve->keyindex >= 0 && eve->keyindex < currkey->totelem) { // valid old vertex
+                                       if(currkey == actkey) {
+                                               if (actkey == me->key->refkey) {
+                                                       VECCOPY(fp, mvert->co);
+                                               }
+                                               else {
+                                                       VECCOPY(fp, mvert->co);
+                                                       if(oldverts) {
+                                                               VECCOPY(mvert->co, oldverts[eve->keyindex].co);
+                                                       }
+                                               }
+                                       }
+                                       else {
+                                               if(oldkey) {
+                                                       VECCOPY(fp, oldkey + 3 * eve->keyindex);
+                                               }
+                                       }
+                               }
+                               else {
+                                       VECCOPY(fp, mvert->co);
+                               }
+                               fp+= 3;
+                               ++i;
+                               ++mvert;
+                               eve= eve->next;
+                       }
+                       currkey->totelem= G.totvert;
+                       if(currkey->data) MEM_freeN(currkey->data);
+                       currkey->data = newkey;
+                       
+                       currkey= currkey->next;
+               }
+       }
+
+       if(oldverts) MEM_freeN(oldverts);
+       
+       i = 0;
+       for(ese=em->selected.first; ese; ese=ese->next) i++;
+       me->totselect = i;
+       if(i==0) mselect= NULL;
+       else mselect= MEM_callocN(i*sizeof(MSelect), "loadeditMesh selections");
+       
+       if(me->mselect) MEM_freeN(me->mselect);
+       me->mselect= mselect;
+       
+       for(ese=em->selected.first; ese; ese=ese->next){
+               mselect->type = ese->type;
+               if(ese->type == EDITVERT) mselect->index = ((EditVert*)ese->data)->tmp.l;
+               else if(ese->type == EDITEDGE) mselect->index = ((EditEdge*)ese->data)->tmp.l;
+               else if(ese->type == EDITFACE) mselect->index = ((EditFace*)ese->data)->tmp.l;
+               mselect++;
+       }
+       
+       /* to be sure: clear ->tmp.l pointers */
+       eve= em->verts.first;
+       while(eve) {
+               eve->tmp.l = 0;
+               eve= eve->next;
+       }
+       
+       eed= em->edges.first;
+       while(eed) { 
+               eed->tmp.l = 0;
+               eed= eed->next;
+       }
+       
+       efa= em->faces.first;
+       while(efa) {
+               efa->tmp.l = 0;
+               efa= efa->next;
+       }
+       
+       /* remake softbody of all users */
+       if(me->id.us>1) {
+               Base *base;
+               for(base= scene->base.first; base; base= base->next)
+                       if(base->object->data==me)
+                               base->object->recalc |= OB_RECALC_DATA;
+       }
+
+       mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+}
+
+void remake_editMesh(Scene *scene, EditMesh *em)
+{
+       make_editMesh(scene, em);
+//     allqueue(REDRAWVIEW3D, 0);
+//     allqueue(REDRAWBUTSOBJECT, 0); /* needed to have nice cloth panels */
+       DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
+       BIF_undo_push("Undo all changes");
+}
+
+/* ***************             (partial exit editmode) *************/
+
+
+
+
+void separate_mesh(Scene *scene, EditMesh *em)
+{
+       EditMesh emcopy;
+       EditVert *eve, *v1;
+       EditEdge *eed, *e1;
+       EditFace *efa, *vl1;
+       Object *oldob;
+       Mesh *me, *men;
+       Base *base, *oldbase;
+       ListBase edve, eded, edvl;
+       
+       TEST_EDITMESH
+       if(multires_test()) return;
+
+       waitcursor(1);
+       
+       me= get_mesh(G.obedit);
+       if(me->key) {
+               error("Can't separate with vertex keys");
+               return;
+       }
+       
+       if(em->selected.first) BLI_freelistN(&(em->selected)); /* clear the selection order */
+               
+       EM_selectmode_set(em);  // enforce full consistant selection flags 
+       
+       /* we are going to abuse the system as follows:
+        * 1. add a duplicate object: this will be the new one, we remember old pointer
+        * 2: then do a split if needed.
+        * 3. put apart: all NOT selected verts, edges, faces
+        * 4. call load_editMesh(): this will be the new object
+        * 5. freelist and get back old verts, edges, facs
+        */
+       
+       /* make only obedit selected */
+       base= FIRSTBASE;
+       while(base) {
+//     XXX     if(base->lay & G.vd->lay) {
+                       if(base->object==G.obedit) base->flag |= SELECT;
+                       else base->flag &= ~SELECT;
+//             }
+               base= base->next;
+       }
+       
+       /* no test for split, split doesn't split when a loose part is selected */
+       /* SPLIT: first make duplicate */
+       adduplicateflag(em, SELECT);
+
+       /* SPLIT: old faces have 3x flag 128 set, delete these ones */
+       delfaceflag(em, 128);
+       
+       /* since we do tricky things with verts/edges/faces, this makes sure all is selected coherent */
+       EM_selectmode_set(em);
+       
+       /* set apart: everything that is not selected */
+       edve.first= edve.last= eded.first= eded.last= edvl.first= edvl.last= 0;
+       eve= em->verts.first;
+       while(eve) {
+               v1= eve->next;
+               if((eve->f & SELECT)==0) {
+                       BLI_remlink(&em->verts, eve);
+                       BLI_addtail(&edve, eve);
+               }
+               
+               eve= v1;
+       }
+       eed= em->edges.first;
+       while(eed) {
+               e1= eed->next;
+               if((eed->f & SELECT)==0) {
+                       BLI_remlink(&em->edges, eed);
+                       BLI_addtail(&eded, eed);
+               }
+               eed= e1;
+       }
+       efa= em->faces.first;
+       while(efa) {
+               vl1= efa->next;
+               if (efa == em->act_face && (efa->f & SELECT)) {
+                       EM_set_actFace(em, NULL);
+               }
+
+               if((efa->f & SELECT)==0) {
+                       BLI_remlink(&em->faces, efa);
+                       BLI_addtail(&edvl, efa);
+               }
+               efa= vl1;
+       }
+       
+       oldob= G.obedit;
+       oldbase= BASACT;
+       
+       adduplicate(1, 0); /* notrans and a linked duplicate */
+       
+       G.obedit= BASACT->object;       /* basact was set in adduplicate()  */
+       
+       men= copy_mesh(me);
+       set_mesh(G.obedit, men);
+       /* because new mesh is a copy: reduce user count */
+       men->id.us--;
+       
+       load_editMesh(scene, em);
+       
+       BASACT->flag &= ~SELECT;
+       
+       /* we cannot free the original buffer... */
+       emcopy= *em;
+       emcopy.allverts= NULL;
+       emcopy.alledges= NULL;
+       emcopy.allfaces= NULL;
+       emcopy.derivedFinal= emcopy.derivedCage= NULL;
+       memset(&emcopy.vdata, 0, sizeof(emcopy.vdata));
+       memset(&emcopy.fdata, 0, sizeof(emcopy.fdata));
+       free_editMesh(&emcopy);
+       
+       em->verts= edve;
+       em->edges= eded;
+       em->faces= edvl;
+       
+       /* hashedges are freed now, make new! */
+       editMesh_set_hash(em);
+
+       DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);       
+       G.obedit= oldob;
+       BASACT= oldbase;
+       BASACT->flag |= SELECT;
+       
+       waitcursor(0);
+
+//     allqueue(REDRAWVIEW3D, 0);
+       DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);       
+
+}
+
+void separate_material(Scene *scene, EditMesh *em)
+{
+       unsigned char curr_mat;
+       Mesh *me;
+       
+       if(multires_test()) return;
+       
+       me= get_mesh(G.obedit);
+       if(me->key) {
+               error("Can't separate with vertex keys");
+               return;
+       }
+       
+       if(G.obedit && em) {
+               if(G.obedit->type == OB_MESH) {
+                       for (curr_mat = 1; curr_mat < G.obedit->totcol; ++curr_mat) {
+                               /* clear selection, we're going to use that to select material group */
+                               EM_clear_flag_all(em, SELECT);
+                               /* select the material */
+                               editmesh_select_by_material(em, curr_mat);
+                               /* and now separate */
+                               separate_mesh(scene, em);
+                       }
+               }
+       }
+       
+       //      allqueue(REDRAWVIEW3D, 0);
+       DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);
+       
+}
+
+
+void separate_mesh_loose(Scene *scene, EditMesh *em)
+{
+       EditMesh emcopy;
+       EditVert *eve, *v1;
+       EditEdge *eed, *e1;
+       EditFace *efa, *vl1;
+       Object *oldob=NULL;
+       Mesh *me, *men;
+       Base *base, *oldbase;
+       ListBase edve, eded, edvl;
+       int vertsep=0;  
+       short done=0, check=1;
+                       
+       me= get_mesh(G.obedit);
+       if(me->key) {
+               error("Can't separate a mesh with vertex keys");
+               return;
+       }
+
+       TEST_EDITMESH
+       if(multires_test()) return;
+       waitcursor(1);  
+       
+       /* we are going to abuse the system as follows:
+        * 1. add a duplicate object: this will be the new one, we remember old pointer
+        * 2: then do a split if needed.
+        * 3. put apart: all NOT selected verts, edges, faces
+        * 4. call load_editMesh(): this will be the new object
+        * 5. freelist and get back old verts, edges, facs
+        */
+                       
+       while(!done){           
+               vertsep=check=1;
+               
+               /* make only obedit selected */
+               base= FIRSTBASE;
+               while(base) {
+// XXX                 if(base->lay & G.vd->lay) {
+                               if(base->object==G.obedit) base->flag |= SELECT;
+                               else base->flag &= ~SELECT;
+//                     }
+                       base= base->next;
+               }               
+               
+               /*--------- Select connected-----------*/               
+               
+               EM_clear_flag_all(em, SELECT);
+
+               /* Select a random vert to start with */
+               eve= em->verts.first;
+               eve->f |= SELECT;
+               
+               while(check==1) {
+                       check= 0;                       
+                       eed= em->edges.first;                   
+                       while(eed) {                            
+                               if(eed->h==0) {
+                                       if(eed->v1->f & SELECT) {
+                                               if( (eed->v2->f & SELECT)==0 ) {
+                                                       eed->v2->f |= SELECT;
+                                                       vertsep++;
+                                                       check= 1;
+                                               }
+                                       }
+                                       else if(eed->v2->f & SELECT) {
+                                               if( (eed->v1->f & SELECT)==0 ) {
+                                                       eed->v1->f |= SELECT;
+                                                       vertsep++;
+                                                       check= SELECT;
+                                               }
+                                       }
+                               }
+                               eed= eed->next;                         
+                       }
+               }               
+               /*----------End of select connected--------*/
+               
+               
+               /* If the amount of vertices that is about to be split == the total amount 
+                  of verts in the mesh, it means that there is only 1 unconnected object, so we don't have to separate
+               */
+               if(G.totvert==vertsep) done=1;                          
+               else{                   
+                       /* No splitting: select connected goes fine */
+                       
+                       EM_select_flush(em);    // from verts->edges->faces
+
+                       /* set apart: everything that is not selected */
+                       edve.first= edve.last= eded.first= eded.last= edvl.first= edvl.last= 0;
+                       eve= em->verts.first;
+                       while(eve) {
+                               v1= eve->next;
+                               if((eve->f & SELECT)==0) {
+                                       BLI_remlink(&em->verts, eve);
+                                       BLI_addtail(&edve, eve);
+                               }
+                               eve= v1;
+                       }
+                       eed= em->edges.first;
+                       while(eed) {
+                               e1= eed->next;
+                               if( (eed->f & SELECT)==0 ) {
+                                       BLI_remlink(&em->edges, eed);
+                                       BLI_addtail(&eded, eed);
+                               }
+                               eed= e1;
+                       }
+                       efa= em->faces.first;
+                       while(efa) {
+                               vl1= efa->next;
+                               if( (efa->f & SELECT)==0 ) {
+                                       BLI_remlink(&em->faces, efa);
+                                       BLI_addtail(&edvl, efa);
+                               }
+                               efa= vl1;
+                       }
+                       
+                       oldob= G.obedit;
+                       oldbase= BASACT;
+                       
+                       adduplicate(1, 0); /* notrans and a linked duplicate*/
+                       
+                       G.obedit= BASACT->object;       /* basact was set in adduplicate()  */
+
+                       men= copy_mesh(me);
+                       set_mesh(G.obedit, men);
+                       /* because new mesh is a copy: reduce user count */
+                       men->id.us--;
+                       
+                       load_editMesh(scene, em);
+                       
+                       BASACT->flag &= ~SELECT;
+                       
+                       /* we cannot free the original buffer... */
+                       emcopy= *em;
+                       emcopy.allverts= NULL;
+                       emcopy.alledges= NULL;
+                       emcopy.allfaces= NULL;
+                       emcopy.derivedFinal= emcopy.derivedCage= NULL;
+                       memset(&emcopy.vdata, 0, sizeof(emcopy.vdata));
+                       memset(&emcopy.fdata, 0, sizeof(emcopy.fdata));
+                       free_editMesh(&emcopy);
+                       
+                       em->verts= edve;
+                       em->edges= eded;
+                       em->faces= edvl;
+                       
+                       /* hashedges are freed now, make new! */
+                       editMesh_set_hash(em);
+                       
+                       G.obedit= oldob;
+                       BASACT= oldbase;
+                       BASACT->flag |= SELECT; 
+                                       
+               }               
+       }
+       
+       /* unselect the vertices that we (ab)used for the separation*/
+       EM_clear_flag_all(em, SELECT);
+               
+       waitcursor(0);
+//     allqueue(REDRAWVIEW3D, 0);
+       DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);       
+}
+
+void separatemenu(Scene *scene, EditMesh *em)
+{
+       short event;
+       
+       if(em->verts.first==NULL) return;
+          
+       event = pupmenu("Separate %t|Selected%x1|All Loose Parts%x2|By Material%x3");
+       
+       if (event==0) return;
+       waitcursor(1);
+       
+       switch (event) {
+               case 1: 
+                       separate_mesh(scene, em);                   
+                       break;
+               case 2:                     
+                       separate_mesh_loose(scene, em);             
+                       break;
+               case 3:
+                       separate_material(scene, em);
+                       break;
+       }
+       waitcursor(0);
+}
+
+
+/* ******************************************** */
+
+/* *************** UNDO ***************************** */
+/* new mesh undo, based on pushing editmesh data itself */
+/* reuses same code as for global and curve undo... unify that (ton) */
+
+/* only one 'hack', to save memory it doesn't store the first push, but does a remake editmesh */
+
+/* a compressed version of editmesh data */
+
+typedef struct EditVertC
+{
+       float no[3];
+       float co[3];
+       unsigned char f, h;
+       short bweight;
+       int keyindex;
+} EditVertC;
+
+typedef struct EditEdgeC
+{
+       int v1, v2;
+       unsigned char f, h, seam, sharp, pad;
+       short crease, bweight, fgoni;
+} EditEdgeC;
+
+typedef struct EditFaceC
+{
+       int v1, v2, v3, v4;
+       unsigned char mat_nr, flag, f, h, fgonf;
+       short pad1;
+} EditFaceC;
+
+typedef struct EditSelectionC{
+       short type;
+       int index;
+}EditSelectionC;
+
+typedef struct EM_MultiresUndo {
+       int users;
+       Multires *mr;
+} EM_MultiresUndo;
+
+typedef struct UndoMesh {
+       EditVertC *verts;
+       EditEdgeC *edges;
+       EditFaceC *faces;
+       EditSelectionC *selected;
+       int totvert, totedge, totface, totsel;
+       short selectmode;
+       RetopoPaintData *retopo_paint_data;
+       char retopo_mode;
+       CustomData vdata, edata, fdata;
+       EM_MultiresUndo *mru;
+} UndoMesh;
+
+/* for callbacks */
+
+static void free_undoMesh(void *umv)
+{
+       UndoMesh *um= umv;
+       
+       if(um->verts) MEM_freeN(um->verts);
+       if(um->edges) MEM_freeN(um->edges);
+       if(um->faces) MEM_freeN(um->faces);
+       if(um->selected) MEM_freeN(um->selected);
+// XXX if(um->retopo_paint_data) retopo_free_paint_data(um->retopo_paint_data);
+       CustomData_free(&um->vdata, um->totvert);
+       CustomData_free(&um->edata, um->totedge);
+       CustomData_free(&um->fdata, um->totface);
+       if(um->mru) {
+               --um->mru->users;
+               if(um->mru->users==0) {
+                       multires_free(um->mru->mr);
+                       um->mru->mr= NULL;
+                       MEM_freeN(um->mru);
+               }
+       }
+       MEM_freeN(um);
+}
+
+static void *editMesh_to_undoMesh(Scene *scene, EditMesh *em)
+{
+       UndoMesh *um;
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       EditSelection *ese;
+       EditVertC *evec=NULL;
+       EditEdgeC *eedc=NULL;
+       EditFaceC *efac=NULL;
+       EditSelectionC *esec=NULL;
+       int a;
+       
+       um= MEM_callocN(sizeof(UndoMesh), "undomesh");
+       
+       um->selectmode = scene->selectmode;
+       
+       for(eve=em->verts.first; eve; eve= eve->next) um->totvert++;
+       for(eed=em->edges.first; eed; eed= eed->next) um->totedge++;
+       for(efa=em->faces.first; efa; efa= efa->next) um->totface++;
+       for(ese=em->selected.first; ese; ese=ese->next) um->totsel++; 
+       /* malloc blocks */
+       
+       if(um->totvert) evec= um->verts= MEM_callocN(um->totvert*sizeof(EditVertC), "allvertsC");
+       if(um->totedge) eedc= um->edges= MEM_callocN(um->totedge*sizeof(EditEdgeC), "alledgesC");
+       if(um->totface) efac= um->faces= MEM_callocN(um->totface*sizeof(EditFaceC), "allfacesC");
+       if(um->totsel) esec= um->selected= MEM_callocN(um->totsel*sizeof(EditSelectionC), "allselections");
+
+       if(um->totvert) CustomData_copy(&em->vdata, &um->vdata, CD_MASK_EDITMESH, CD_CALLOC, um->totvert);
+       if(um->totedge) CustomData_copy(&em->edata, &um->edata, CD_MASK_EDITMESH, CD_CALLOC, um->totedge);
+       if(um->totface) CustomData_copy(&em->fdata, &um->fdata, CD_MASK_EDITMESH, CD_CALLOC, um->totface);
+       
+       /* now copy vertices */
+       a = 0;
+       for(eve=em->verts.first; eve; eve= eve->next, evec++, a++) {
+               VECCOPY(evec->co, eve->co);
+               VECCOPY(evec->no, eve->no);
+
+               evec->f= eve->f;
+               evec->h= eve->h;
+               evec->keyindex= eve->keyindex;
+               eve->tmp.l = a; /*store index*/
+               evec->bweight= (short)(eve->bweight*255.0);
+
+               CustomData_from_em_block(&em->vdata, &um->vdata, eve->data, a);
+       }
+       
+       /* copy edges */
+       a = 0;
+       for(eed=em->edges.first; eed; eed= eed->next, eedc++, a++)  {
+               eedc->v1= (int)eed->v1->tmp.l;
+               eedc->v2= (int)eed->v2->tmp.l;
+               eedc->f= eed->f;
+               eedc->h= eed->h;
+               eedc->seam= eed->seam;
+               eedc->sharp= eed->sharp;
+               eedc->crease= (short)(eed->crease*255.0);
+               eedc->bweight= (short)(eed->bweight*255.0);
+               eedc->fgoni= eed->fgoni;
+               eed->tmp.l = a; /*store index*/
+               CustomData_from_em_block(&em->edata, &um->edata, eed->data, a);
+       
+       }
+       
+       /* copy faces */
+       a = 0;
+       for(efa=em->faces.first; efa; efa= efa->next, efac++, a++) {
+               efac->v1= (int)efa->v1->tmp.l;
+               efac->v2= (int)efa->v2->tmp.l;
+               efac->v3= (int)efa->v3->tmp.l;
+               if(efa->v4) efac->v4= (int)efa->v4->tmp.l;
+               else efac->v4= -1;
+               
+               efac->mat_nr= efa->mat_nr;
+               efac->flag= efa->flag;
+               efac->f= efa->f;
+               efac->h= efa->h;
+               efac->fgonf= efa->fgonf;
+
+               efa->tmp.l = a; /*store index*/
+
+               CustomData_from_em_block(&em->fdata, &um->fdata, efa->data, a);
+       }
+       
+       a = 0;
+       for(ese=em->selected.first; ese; ese=ese->next, esec++){
+               esec->type = ese->type;
+               if(ese->type == EDITVERT) a = esec->index = ((EditVert*)ese->data)->tmp.l; 
+               else if(ese->type == EDITEDGE) a = esec->index = ((EditEdge*)ese->data)->tmp.l; 
+               else if(ese->type == EDITFACE) a = esec->index = ((EditFace*)ese->data)->tmp.l;
+       }
+
+// XXX um->retopo_paint_data= retopo_paint_data_copy(em->retopo_paint_data);
+       um->retopo_mode= scene->toolsettings->retopo_mode;
+       
+       {
+               Multires *mr= get_mesh(G.obedit)->mr;
+               UndoMesh *prev= undo_editmode_get_prev(G.obedit);
+               
+               um->mru= NULL;
+               
+               if(mr) {
+                       if(prev && prev->mru && prev->mru->mr && prev->mru->mr->current == mr->current) {
+                               um->mru= prev->mru;
+                               ++um->mru->users;
+                       }
+                       else {
+                               um->mru= MEM_callocN(sizeof(EM_MultiresUndo), "EM_MultiresUndo");
+                               um->mru->users= 1;
+                               um->mru->mr= multires_copy(mr);
+                       }
+               }
+       }
+       
+       return um;
+}
+
+static void undoMesh_to_editMesh(void *umv, EditMesh *em)
+{
+       UndoMesh *um= (UndoMesh*)umv;
+       EditVert *eve, **evar=NULL;
+       EditEdge *eed;
+       EditFace *efa;
+       EditSelection *ese;
+       EditVertC *evec;
+       EditEdgeC *eedc;
+       EditFaceC *efac;
+       EditSelectionC *esec;
+       int a=0;
+
+       em->selectmode = um->selectmode;
+       
+       free_editMesh(em);
+       
+       /* malloc blocks */
+       memset(em, 0, sizeof(EditMesh));
+               
+       init_editmesh_fastmalloc(em, um->totvert, um->totedge, um->totface);
+
+       CustomData_free(&em->vdata, 0);
+       CustomData_free(&em->edata, 0);
+       CustomData_free(&em->fdata, 0);
+
+       CustomData_copy(&um->vdata, &em->vdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       CustomData_copy(&um->edata, &em->edata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+       CustomData_copy(&um->fdata, &em->fdata, CD_MASK_EDITMESH, CD_CALLOC, 0);
+
+       /* now copy vertices */
+
+       if(um->totvert) evar= MEM_mallocN(um->totvert*sizeof(EditVert *), "vertex ar");
+       for(a=0, evec= um->verts; a<um->totvert; a++, evec++) {
+               eve= addvertlist(em, evec->co, NULL);
+               evar[a]= eve;
+
+               VECCOPY(eve->no, evec->no);
+               eve->f= evec->f;
+               eve->h= evec->h;
+               eve->keyindex= evec->keyindex;
+               eve->bweight= ((float)evec->bweight)/255.0f;
+
+               CustomData_to_em_block(&um->vdata, &em->vdata, a, &eve->data);
+       }
+
+       /* copy edges */
+       for(a=0, eedc= um->edges; a<um->totedge; a++, eedc++) {
+               eed= addedgelist(em, evar[eedc->v1], evar[eedc->v2], NULL);
+
+               eed->f= eedc->f;
+               eed->h= eedc->h;
+               eed->seam= eedc->seam;
+               eed->sharp= eedc->sharp;
+               eed->fgoni= eedc->fgoni;
+               eed->crease= ((float)eedc->crease)/255.0f;
+               eed->bweight= ((float)eedc->bweight)/255.0f;
+               CustomData_to_em_block(&um->edata, &em->edata, a, &eed->data);
+       }
+       
+       /* copy faces */
+       for(a=0, efac= um->faces; a<um->totface; a++, efac++) {
+               if(efac->v4 != -1)
+                       efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], evar[efac->v4], NULL, NULL);
+               else 
+                       efa= addfacelist(em, evar[efac->v1], evar[efac->v2], evar[efac->v3], NULL, NULL ,NULL);
+
+               efa->mat_nr= efac->mat_nr;
+               efa->flag= efac->flag;
+               efa->f= efac->f;
+               efa->h= efac->h;
+               efa->fgonf= efac->fgonf;
+               
+               CustomData_to_em_block(&um->fdata, &em->fdata, a, &efa->data);
+       }
+       
+       end_editmesh_fastmalloc();
+       if(evar) MEM_freeN(evar);
+       
+       G.totvert = um->totvert;
+       G.totedge = um->totedge;
+       G.totface = um->totface;
+       /*restore stored editselections*/
+       if(um->totsel){
+               EM_init_index_arrays(em, 1,1,1);
+               for(a=0, esec= um->selected; a<um->totsel; a++, esec++){
+                       ese = MEM_callocN(sizeof(EditSelection), "Edit Selection");
+                       ese->type = esec->type;
+                       if(ese->type == EDITVERT) ese->data = EM_get_vert_for_index(esec->index); else
+                       if(ese->type == EDITEDGE) ese->data = EM_get_edge_for_index(esec->index); else
+                       if(ese->type == EDITFACE) ese->data = EM_get_face_for_index(esec->index);
+                       BLI_addtail(&(em->selected),ese);
+               }
+               EM_free_index_arrays();
+       }
+
+// XXX retopo_free_paint();
+//     em->retopo_paint_data= retopo_paint_data_copy(um->retopo_paint_data);
+//     scene->toolsettings->retopo_mode= um->retopo_mode;
+//     if(scene->toolsettings->retopo_mode) {
+// XXX         if(G.vd->depths) G.vd->depths->damaged= 1;
+//             retopo_queue_updates(G.vd);
+//             retopo_paint_view_update(G.vd);
+//     }
+       
+       {
+               Mesh *me= get_mesh(G.obedit);
+               multires_free(me->mr);
+               me->mr= NULL;
+               if(um->mru && um->mru->mr) me->mr= multires_copy(um->mru->mr);
+       }
+}
+
+
+/* and this is all the undo system needs to know */
+void undo_push_mesh(char *name)
+{
+       undo_editmode_push(name, free_undoMesh, undoMesh_to_editMesh, editMesh_to_undoMesh, NULL);
+}
+
+
+
+/* *************** END UNDO *************/
+
+static EditVert **g_em_vert_array = NULL;
+static EditEdge **g_em_edge_array = NULL;
+static EditFace **g_em_face_array = NULL;
+
+void EM_init_index_arrays(EditMesh *em, int forVert, int forEdge, int forFace)
+{
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       int i;
+
+       if (forVert) {
+               g_em_vert_array = MEM_mallocN(sizeof(*g_em_vert_array)*G.totvert, "em_v_arr");
+
+               for (i=0,eve=em->verts.first; eve; i++,eve=eve->next)
+                       g_em_vert_array[i] = eve;
+       }
+
+       if (forEdge) {
+               g_em_edge_array = MEM_mallocN(sizeof(*g_em_edge_array)*G.totedge, "em_e_arr");
+
+               for (i=0,eed=em->edges.first; eed; i++,eed=eed->next)
+                       g_em_edge_array[i] = eed;
+       }
+
+       if (forFace) {
+               g_em_face_array = MEM_mallocN(sizeof(*g_em_face_array)*G.totface, "em_f_arr");
+
+               for (i=0,efa=em->faces.first; efa; i++,efa=efa->next)
+                       g_em_face_array[i] = efa;
+       }
+}
+
+void EM_free_index_arrays(void)
+{
+       if (g_em_vert_array) MEM_freeN(g_em_vert_array);
+       if (g_em_edge_array) MEM_freeN(g_em_edge_array);
+       if (g_em_face_array) MEM_freeN(g_em_face_array);
+       g_em_vert_array = NULL;
+       g_em_edge_array = NULL;
+       g_em_face_array = NULL;
+}
+
+EditVert *EM_get_vert_for_index(int index)
+{
+       return g_em_vert_array?g_em_vert_array[index]:NULL;
+}
+
+EditEdge *EM_get_edge_for_index(int index)
+{
+       return g_em_edge_array?g_em_edge_array[index]:NULL;
+}
+
+EditFace *EM_get_face_for_index(int index)
+{
+       return g_em_face_array?g_em_face_array[index]:NULL;
+}
+
+/* can we edit UV's for this mesh?*/
+int EM_texFaceCheck(EditMesh *em)
+{
+       /* some of these checks could be a touch overkill */
+       if (    (G.obedit) &&
+                       (G.obedit->type == OB_MESH) &&
+                       (em) &&
+                       (em->faces.first) &&
+                       (CustomData_has_layer(&em->fdata, CD_MTFACE)))
+               return 1;
+       return 0;
+}
+
+/* can we edit colors for this mesh?*/
+int EM_vertColorCheck(EditMesh *em)
+{
+       /* some of these checks could be a touch overkill */
+       if (    (G.obedit) &&
+                       (G.obedit->type == OB_MESH) &&
+                       (em) &&
+                       (em->faces.first) &&
+                       (CustomData_has_layer(&em->fdata, CD_MCOL)))
+               return 1;
+       return 0;
+}
+
diff --git a/source/blender/editors/mesh/editmesh.h b/source/blender/editors/mesh/editmesh.h
new file mode 100644 (file)
index 0000000..a57408b
--- /dev/null
@@ -0,0 +1,202 @@
+/**
+ * $Id: 
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* Internal for editmesh_xxxx.c functions */
+
+#ifndef EDITMESH_H
+#define EDITMESH_H
+
+struct View3D;
+
+#define TEST_EDITMESH  if(G.obedit==0) return; /* layer test XXX */
+
+#define UVCOPY(t, s) memcpy(t, s, 2 * sizeof(float));
+
+/* ******************** editface.c */
+
+int edgetag_context_check(Scene *scene, EditEdge *eed);
+void edgetag_context_set(Scene *scene, EditEdge *eed, int val);
+int edgetag_shortest_path(Scene *scene, EditMesh *em, EditEdge *source, EditEdge *target);
+
+/* ******************* meshtools.c */
+
+intptr_t mesh_octree_table(Object *ob, EditMesh *em, float *co, char mode);
+EditVert *editmesh_get_x_mirror_vert(Object *ob, EditMesh *em, float *co);
+int mesh_get_x_mirror_vert(Object *ob, int index);
+
+/* XXX move to uv editor? */
+enum {
+       B_UVAUTO_REDRAW = 3301,
+       B_UVAUTO_SPHERE,
+       B_UVAUTO_CYLINDER,
+       B_UVAUTO_CYLRADIUS,
+       B_UVAUTO_WINDOW,
+       B_UVAUTO_CUBE,
+       B_UVAUTO_CUBESIZE,
+       B_UVAUTO_RESET,
+       B_UVAUTO_BOUNDS,
+       B_UVAUTO_TOP,
+       B_UVAUTO_FACE,
+       B_UVAUTO_OBJECT,
+       B_UVAUTO_ALIGNX,
+       B_UVAUTO_ALIGNY,
+       B_UVAUTO_UNWRAP,
+       B_UVAUTO_DRAWFACES
+};
+
+
+/* ******************* editmesh.c */
+void make_editMesh(Scene *scene, EditMesh *em);
+void load_editMesh(Scene *scene, EditMesh *em);
+void remake_editMesh(Scene *scene, EditMesh *em);
+
+extern void free_editvert(EditMesh *em, EditVert *eve);
+extern void free_editedge(EditMesh *em, EditEdge *eed);
+extern void free_editface(EditMesh *em, EditFace *efa);
+void free_editMesh(EditMesh *em);
+
+extern void free_vertlist(EditMesh *em, ListBase *edve);
+extern void free_edgelist(EditMesh *em, ListBase *lb);
+extern void free_facelist(EditMesh *em, ListBase *lb);
+
+extern void remedge(EditMesh *em, EditEdge *eed);
+
+extern struct EditVert *addvertlist(EditMesh *em, float *vec, struct EditVert *example);
+extern struct EditEdge *addedgelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2, struct EditEdge *example);
+extern struct EditFace *addfacelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2, struct EditVert *v3, struct EditVert *v4, struct EditFace *example, struct EditFace *exampleEdges);
+extern struct EditEdge *findedgelist(EditMesh *em, struct EditVert *v1, struct EditVert *v2);
+
+EditVert *editedge_getOtherVert(EditEdge *eed, EditVert *eve);
+EditVert *editedge_getSharedVert(EditEdge *eed, EditEdge *eed2);
+int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve);
+int editface_containsVert(struct EditFace *efa, struct EditVert *eve);
+int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed);
+
+/* ******************* editmesh_add.c */
+
+
+/* ******************* editmesh_lib.c */
+extern void EM_fgon_flags(EditMesh *em);
+extern void EM_hide_reset(EditMesh *em);
+
+extern int faceselectedOR(EditFace *efa, int flag);
+extern int faceselectedAND(EditFace *efa, int flag);
+
+void EM_remove_selection(EditMesh *em, void *data, int type);
+void EM_set_actFace(EditMesh *em, EditFace *efa);
+void EM_select_face(EditFace *efa, int sel);
+void EM_selectmode_set(EditMesh *em);
+void EM_clear_flag_all(EditMesh *em, int flag);
+void EM_select_flush(EditMesh *em);
+void EM_set_flag_all(EditMesh *em, int flag);
+void EM_convertsel(EditMesh *em, short oldmode, short selectmode);
+
+void EM_add_data_layer(EditMesh *em, CustomData *data, int type);
+
+void EM_data_interp_from_verts(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *eve, float fac);
+void EM_data_interp_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, EditFace *efan, int i1, int i2, int i3, int i4);
+
+int EM_nvertices_selected(EditMesh *em);
+int EM_nfaces_selected(EditMesh *em);
+float EM_face_area(EditFace *efa);
+float EM_face_perimeter(EditFace *efa);
+
+void EM_store_selection(EditMesh *em, void *data, int type);
+
+extern EditFace *exist_face(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4);
+extern void flipface(EditMesh *em, EditFace *efa); // flips for normal direction
+extern int compareface(EditFace *vl1, EditFace *vl2);
+
+void recalc_editnormals(EditMesh *em);
+
+/* flag for selection bits, *nor will be filled with normal for extrusion constraint */
+/* return value defines if such normal was set */
+extern short extrudeflag_face_indiv(EditMesh *em, short flag, float *nor);
+extern short extrudeflag_verts_indiv(EditMesh *em, short flag, float *nor);
+extern short extrudeflag_edges_indiv(EditMesh *em, short flag, float *nor);
+extern short extrudeflag_vert(EditMesh *em, short flag, float *nor);
+extern short extrudeflag(EditMesh *em, short flag, float *nor);
+
+extern void adduplicateflag(EditMesh *em, int flag);
+extern void delfaceflag(EditMesh *em, int flag);
+
+extern void rotateflag(EditMesh *em, short flag, float *cent, float rotmat[][3]);
+extern void translateflag(EditMesh *em, short flag, float *vec);
+
+extern int convex(float *v1, float *v2, float *v3, float *v4);
+
+extern struct EditFace *EM_face_from_faces(EditMesh *em, struct EditFace *efa1,
+                                                                                  struct EditFace *efa2, int i1, int i2, int i3, int i4);
+
+
+/* ******************* editmesh_loop.c */
+
+#define KNIFE_PROMPT 0
+#define KNIFE_EXACT 1
+#define KNIFE_MIDPOINT 2
+#define KNIFE_MULTICUT 3
+
+#define LOOP_SELECT    1
+#define LOOP_CUT       2
+
+
+/* ******************* editmesh_mods.c */
+extern EditEdge *findnearestedge(struct View3D *v3d, EditMesh *em, int *dist);
+extern void EM_automerge(int update);
+void editmesh_select_by_material(EditMesh *em, int index);
+void righthandfaces(EditMesh *em, int select); /* makes faces righthand turning */
+void EM_select_more(EditMesh *em);
+
+/**
+ * findnearestvert
+ * 
+ * dist (in/out): minimal distance to the nearest and at the end, actual distance
+ * sel: selection bias
+ *             if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
+ *             if 0, unselected vertice are given the bias
+ * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased 
+ */
+extern EditVert *findnearestvert(struct View3D *v3d, EditMesh *em, int *dist, short sel, short strict);
+
+
+/* ******************* editmesh_tools.c */
+
+#define SUBDIV_SELECT_ORIG      0
+#define SUBDIV_SELECT_INNER     1
+#define SUBDIV_SELECT_INNER_SEL 2
+#define SUBDIV_SELECT_LOOPCUT 3
+
+void join_triangles(EditMesh *em);
+int removedoublesflag(EditMesh *em, short flag, short automerge, float limit);         /* return amount */
+void esubdivideflag(EditMesh *em, int flag, float rad, int beauty, int numcuts, int seltype);
+int EdgeSlide(EditMesh *em, short immediate, float imperc);
+
+
+#endif
+
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
new file mode 100644 (file)
index 0000000..1e72efd
--- /dev/null
@@ -0,0 +1,1413 @@
+/**
+ * $Id: 
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_space_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_userdef_types.h"
+#include "DNA_view3d_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_global.h"
+#include "BKE_library.h"
+#include "BKE_mesh.h"
+#include "BKE_object.h"
+#include "BKE_utildefines.h"
+
+#include "BIF_retopo.h"
+
+#include "ED_mesh.h"
+#include "ED_multires.h"
+#include "ED_view3d.h"
+
+#include "editmesh.h"
+
+/* bpymenu removed XXX */
+
+/* XXX */
+static void BIF_undo_push() {}
+static void waitcursor() {}
+static void error() {}
+static int pupmenu() {return 0;}
+#define add_numbut(a, b, c, d, e, f, g) {}
+static int do_clever_numbuts() {return 0;}
+static void check_editmode() {}
+static void exit_editmode() {}
+/* XXX */
+
+static float icovert[12][3] = {
+       {0,0,-200}, 
+       {144.72, -105.144,-89.443},
+       {-55.277, -170.128,-89.443}, 
+       {-178.885,0,-89.443},
+       {-55.277,170.128,-89.443}, 
+       {144.72,105.144,-89.443},
+       {55.277,-170.128,89.443},
+       {-144.72,-105.144,89.443},
+       {-144.72,105.144,89.443},
+       {55.277,170.128,89.443},
+       {178.885,0,89.443},
+       {0,0,200}
+};
+static short icoface[20][3] = {
+       {1,0,2},
+       {1,0,5},
+       {2,0,3},
+       {3,0,4},
+       {4,0,5},
+       {1,5,10},
+       {2,1,6},
+       {3,2,7},
+       {4,3,8},
+       {5,4,9},
+       {10,1,6},
+       {6,2,7},
+       {7,3,8},
+       {8,4,9},
+       {9,5,10},
+       {6,10,11},
+       {7,6,11},
+       {8,7,11},
+       {9,8,11},
+       {10,9,11}
+};
+
+static void get_view_aligned_coordinate(float *fp, short mval[2])
+{
+//     float dvec[3];
+//     short mx, my;
+       
+//     mx= mval[0];
+//     my= mval[1];
+       
+// XXX project_short_noclip(ar, v3d, fp, mval);
+       
+// XXX initgrabz(fp[0], fp[1], fp[2]);
+       
+//     if(mval[0]!=IS_CLIPPED) {
+//             window_to_3d(dvec, mval[0]-mx, mval[1]-my);
+//             VecSubf(fp, fp, dvec);
+//     }
+}
+
+void add_click_mesh(Scene *scene, EditMesh *em)
+{
+       View3D *v3d= NULL; // XXX
+       EditVert *eve, *v1;
+       float min[3], max[3];
+       int done= 0;
+       
+       TEST_EDITMESH
+       if(multires_test()) return;
+       
+       INIT_MINMAX(min, max);
+       
+       for(v1= em->verts.first;v1; v1=v1->next) {
+               if(v1->f & SELECT) {
+                       DO_MINMAX(v1->co, min, max);
+                       done= 1;
+               }
+       }
+
+       /* call extrude? */
+       if(done) {
+               EditEdge *eed;
+               float vec[3], cent[3], mat[3][3];
+               float nor[3]= {0.0, 0.0, 0.0};
+               short mval[2];
+               
+               /* check for edges that are half selected, use for rotation */
+               done= 0;
+               for(eed= em->edges.first; eed; eed= eed->next) {
+                       if( (eed->v1->f & SELECT)+(eed->v2->f & SELECT) == SELECT ) {
+                               if(eed->v1->f & SELECT) VecSubf(vec, eed->v1->co, eed->v2->co);
+                               else VecSubf(vec, eed->v2->co, eed->v1->co);
+                               VecAddf(nor, nor, vec);
+                               done= 1;
+                       }
+               }
+               if(done) Normalize(nor);
+               
+               /* center */
+               VecAddf(cent, min, max);
+               VecMulf(cent, 0.5f);
+               VECCOPY(min, cent);
+               
+               Mat4MulVecfl(G.obedit->obmat, min);     // view space
+               get_view_aligned_coordinate(min, mval);
+               Mat4Invert(G.obedit->imat, G.obedit->obmat); 
+               Mat4MulVecfl(G.obedit->imat, min); // back in object space
+               
+               VecSubf(min, min, cent);
+               
+               /* calculate rotation */
+               Mat3One(mat);
+               if(done) {
+                       float dot;
+                       
+                       VECCOPY(vec, min);
+                       Normalize(vec);
+                       dot= INPR(vec, nor);
+
+                       if( fabs(dot)<0.999) {
+                               float cross[3], si, q1[4];
+                               
+                               Crossf(cross, nor, vec);
+                               Normalize(cross);
+                               dot= 0.5f*saacos(dot);
+                               si= (float)sin(dot);
+                               q1[0]= (float)cos(dot);
+                               q1[1]= cross[0]*si;
+                               q1[2]= cross[1]*si;
+                               q1[3]= cross[2]*si;
+                               
+                               QuatToMat3(q1, mat);
+                       }
+               }
+               
+               extrudeflag(em, SELECT, nor);
+               rotateflag(em, SELECT, cent, mat);
+               translateflag(em, SELECT, min);
+               
+               recalc_editnormals(em);
+       }
+       else {
+               float mat[3][3],imat[3][3];
+               float *curs= give_cursor(scene, v3d);
+               
+               eve= addvertlist(em, 0, NULL);
+
+               Mat3CpyMat4(mat, G.obedit->obmat);
+               Mat3Inv(imat, mat);
+               
+               VECCOPY(eve->co, curs);
+               VecSubf(eve->co, eve->co, G.obedit->obmat[3]);
+
+               Mat3MulVecfl(imat, eve->co);
+               
+               eve->f= SELECT;
+       }
+       
+       retopo_do_all();
+       
+       BIF_undo_push("Add vertex/edge/face");
+// XXX DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);       
+       
+       while(0); // XXX get_mbut()&R_MOUSE);
+
+}
+
+/* selected faces get hidden edges */
+static void make_fgon(EditMesh *em, int make)
+{
+       EditFace *efa;
+       EditEdge *eed;
+       EditVert *eve;
+       float *nor=NULL;        // reference
+       int done=0;
+       
+       if(!make) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->f & SELECT) {
+                               efa->fgonf= 0;
+                               efa->e1->h &= ~EM_FGON;
+                               efa->e2->h &= ~EM_FGON;
+                               efa->e3->h &= ~EM_FGON;
+                               if(efa->e4) efa->e4->h &= ~EM_FGON;
+                       }
+               }
+               EM_fgon_flags(em);      // redo flags and indices for fgons
+// XXX         DAG_object_flush_update(scene, G.obedit, OB_RECALC_DATA);       
+               BIF_undo_push("Clear FGon");
+               return;
+       }
+
+       /* tagging edges. rule is:
+          - edge used by exactly 2 selected faces
+          - no vertices allowed with only tagged edges (return)
+          - face normals are allowed to difffer
+        
+       */
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               eed->f1= 0;     // amount of selected
+               eed->f2= 0; // amount of unselected
+       }
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if(efa->f & SELECT) {
+                       if(nor==NULL) nor= efa->n;
+                       if(efa->e1->f1 < 3) efa->e1->f1++;
+                       if(efa->e2->f1 < 3) efa->e2->f1++;
+                       if(efa->e3->f1 < 3) efa->e3->f1++;
+                       if(efa->e4 && efa->e4->f1 < 3) efa->e4->f1++;
+               }
+               else {
+                       if(efa->e1->f2 < 3) efa->e1->f2++;
+                       if(efa->e2->f2 < 3) efa->e2->f2++;
+                       if(efa->e3->f2 < 3) efa->e3->f2++;
+                       if(efa->e4 && efa->e4->f2 < 3) efa->e4->f2++;
+               }
+       }
+       // now eed->f1 becomes tagged edge
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->f1==2 && eed->f2==0) eed->f1= 1;
+               else eed->f1= 0;
+       }
+       
+       // no vertices allowed with only tagged edges
+       for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->f1) {
+                       eed->v1->f1 |= 1;
+                       eed->v2->f1 |= 1;
+               }
+               else {
+                       eed->v1->f1 |= 2;
+                       eed->v2->f1 |= 2;
+               }
+       }
+       for(eve= em->verts.first; eve; eve= eve->next) {
+               if(eve->f1==1) break;
+       }
+       if(eve) {
+               error("Cannot make polygon with interior vertices");
+               return;
+       }
+       
+       // check for faces
+       if(nor==NULL) {
+               error("No faces selected to make FGon");
+               return;
+       }
+
+       // and there we go
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->f1) {
+                       eed->h |= EM_FGON;
+                       done= 1;
+               }
+       }
+       
+       if(done==0) {
+               error("Didn't find FGon to create");
+       }
+       else {
+               EM_fgon_flags(em);      // redo flags and indices for fgons
+
+// XXX         DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
+               BIF_undo_push("Make FGon");
+       }
+}
+
+/* precondition; 4 vertices selected, check for 4 edges and create face */
+static EditFace *addface_from_edges(EditMesh *em)
+{
+       EditEdge *eed, *eedar[4]={NULL, NULL, NULL, NULL};
+       EditVert *v1=NULL, *v2=NULL, *v3=NULL, *v4=NULL;
+       int a;
+       
+       /* find the 4 edges */
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if( (eed->f & SELECT) || (eed->v1->f & eed->v2->f & SELECT) ) {
+                       if(eedar[0]==NULL) eedar[0]= eed;
+                       else if(eedar[1]==NULL) eedar[1]= eed;
+                       else if(eedar[2]==NULL) eedar[2]= eed;
+                       else eedar[3]= eed;
+                       
+               }
+       }
+       
+       
+       if(eedar[3]) {
+               /* first 2 points */
+               v1= eedar[0]->v1;
+               v2= eedar[0]->v2;
+               
+               /* find the 2 edges connected to first edge */
+               for(a=1; a<4; a++) {
+                       if( eedar[a]->v1 == v2) v3= eedar[a]->v2;
+                       else if(eedar[a]->v2 == v2) v3= eedar[a]->v1;
+                       else if( eedar[a]->v1 == v1) v4= eedar[a]->v2;
+                       else if(eedar[a]->v2 == v1) v4= eedar[a]->v1;
+               }
+               
+               /* verify if last edge exists */
+               if(v3 && v4) {
+                       for(a=1; a<4; a++) {
+                               if( eedar[a]->v1==v3 && eedar[a]->v2==v4) break;
+                               if( eedar[a]->v2==v3 && eedar[a]->v1==v4) break;
+                       }
+                       if(a!=4) {
+                               return addfacelist(em, v1, v2, v3, v4, NULL, NULL);
+                       }
+               }
+       }
+       return NULL;
+}
+
+/* this also allows to prevent triangles being made in quads */
+static int compareface_overlaps(EditFace *vl1, EditFace *vl2)
+{
+       EditVert *v1, *v2, *v3, *v4;
+       int equal= 0;
+       
+       v1= vl2->v1;
+       v2= vl2->v2;
+       v3= vl2->v3;
+       v4= vl2->v4;
+       
+       if(vl1==vl2) return 0;
+       
+       if(v4==NULL && vl1->v4==NULL) {
+               if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1) equal++;
+               if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2) equal++;
+               if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3) equal++;
+       }
+       else {
+               if(vl1->v1==v1 || vl1->v2==v1 || vl1->v3==v1 || vl1->v4==v1) equal++;
+               if(vl1->v1==v2 || vl1->v2==v2 || vl1->v3==v2 || vl1->v4==v2) equal++;
+               if(vl1->v1==v3 || vl1->v2==v3 || vl1->v3==v3 || vl1->v4==v3) equal++;
+               if(vl1->v1==v4 || vl1->v2==v4 || vl1->v3==v4 || vl1->v4==v4) equal++;
+       }
+
+       if(v4 && vl1->v4) {
+               if(equal==4) return 1;
+       }
+       else 
+               if(equal>=3) return 1;
+       
+       return 0;
+}
+
+/* checks for existance, and for tria overlapping inside quad */
+static EditFace *exist_face_overlaps(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *v3, EditVert *v4)
+{
+       EditFace *efa, efatest;
+       
+       efatest.v1= v1;
+       efatest.v2= v2;
+       efatest.v3= v3;
+       efatest.v4= v4;
+       
+       efa= em->faces.first;
+       while(efa) {
+               if(compareface_overlaps(&efatest, efa)) return efa;
+               efa= efa->next;
+       }
+       return NULL;
+}
+
+/* will be new face smooth or solid? depends on smoothness of face neighbours
+ * of new face, if function return 1, then new face will be smooth, when functio
+ * will return zero, then new face will be solid */
+static void fix_new_face(EditMesh *em, EditFace *eface)
+{
+       struct EditFace *efa;
+       struct EditEdge *eed=NULL;
+       struct EditVert *v1 = eface->v1, *v2 = eface->v2, *v3 = eface->v3, *v4 = eface->v4;
+       struct EditVert *ev1=NULL, *ev2=NULL;
+       short smooth=0; /* "total smoothnes" of faces in neighbourhood */
+       short coef;     /* "weight" of smoothness */
+       short count=0;  /* number of edges with same direction as eface */
+       short vi00=0, vi01=0, vi10=0, vi11=0; /* vertex indexes */
+
+       efa = em->faces.first;
+
+       while(efa) {
+
+               if(efa==eface) {
+                       efa = efa->next;
+                       continue;
+               }
+
+               coef = 0;
+               ev1 = ev2 = NULL;
+               eed = NULL;
+
+               if(efa->v1==v1 || efa->v2==v1 || efa->v3==v1 || efa->v4==v1) {
+                       ev1 = v1;
+                       coef++;
+               }
+               if(efa->v1==v2 || efa->v2==v2 || efa->v3==v2 || efa->v4==v2) {
+                       if(ev1) ev2 = v2;
+                       else ev1 = v2;
+                       coef++;
+               }
+               if(efa->v1==v3 || efa->v2==v3 || efa->v3==v3 || efa->v4==v3) {
+                       if(coef<2) {
+                               if(ev1) ev2 = v3;
+                               else ev1 = v3;
+                       }
+                       coef++;
+               }
+               if((v4) && (efa->v1==v4 || efa->v2==v4 || efa->v3==v4 || efa->v4==v4)) {
+                       if(ev1 && coef<2) ev2 = v4;
+                       coef++;
+               }
+
+               /* "democracy" of smoothness */
+               if(efa->flag & ME_SMOOTH)
+                       smooth += coef;
+               else
+                       smooth -= coef;
+
+               /* try to find edge using vertexes ev1 and ev2 */
+               if((ev1) && (ev2) && (ev1!=ev2)) eed = findedgelist(em, ev1, ev2);
+
+               /* has bordering edge of efa same direction as edge of eface ? */
+               if(eed) {
+                       if(eed->v1==v1) vi00 = 1;
+                       else if(eed->v1==v2) vi00 = 2;
+                       else if(eed->v1==v3) vi00 = 3;
+                       else if(v4 && eed->v1==v4) vi00 = 4;
+
+                       if(eed->v2==v1) vi01 = 1;
+                       else if(eed->v2==v2) vi01 = 2;
+                       else if(eed->v2==v3) vi01 = 3;
+                       else if(v4 && eed->v2==v4) vi01 = 4;
+
+                       if(v4) {
+                               if(vi01==1 && vi00==4) vi00 = 0;
+                               if(vi01==4 && vi00==1) vi01 = 0;
+                       }
+                       else {
+                               if(vi01==1 && vi00==3) vi00 = 0;
+                               if(vi01==3 && vi00==1) vi01 = 0;
+                       }
+
+                       if(eed->v1==efa->v1) vi10 = 1;
+                       else if(eed->v1==efa->v2) vi10 = 2;
+                       else if(eed->v1==efa->v3) vi10 = 3;
+                       else if(efa->v4 && eed->v1==efa->v4) vi10 = 4;
+
+                       if(eed->v2==efa->v1) vi11 = 1;
+                       else if(eed->v2==efa->v2) vi11 = 2;
+                       else if(eed->v2==efa->v3) vi11 = 3;
+                       else if(efa->v4 && eed->v2==efa->v4) vi11 = 4;
+
+                       if(efa->v4) {
+                               if(vi11==1 && vi10==4) vi10 = 0;
+                               if(vi11==4 && vi10==1) vi11 = 0;
+                       }
+                       else {
+                               if(vi11==1 && vi10==3) vi10 = 0;
+                               if(vi11==3 && vi10==1) vi11 = 0;
+                       }
+
+                       if(((vi00>vi01) && (vi10>vi11)) ||
+                               ((vi00<vi01) && (vi10<vi11)))
+                               count++;
+                       else
+                               count--;
+               }
+
+               efa = efa->next;
+       }
+
+       /* set up smoothness according voting of face in neighbourhood */
+       if(smooth >= 0)
+               eface->flag |= ME_SMOOTH;
+       else
+               eface->flag &= ~ME_SMOOTH;
+
+       /* flip face, when too much "face normals" in neighbourhood is different */
+       if(count > 0) {
+               flipface(em, eface);
+       }
+}
+
+void addfaces_from_edgenet(EditMesh *em)
+{
+       EditVert *eve1, *eve2, *eve3, *eve4;
+       
+       for(eve1= em->verts.first; eve1; eve1= eve1->next) {
+               for(eve2= em->verts.first; (eve1->f & 1) && eve2; eve2= eve2->next) {
+                       if(findedgelist(em, eve1,eve2)) {
+                               for(eve3= em->verts.first; (eve2->f & 1) && eve3; eve3= eve3->next) {
+                                       if((eve2!=eve3 && (eve3->f & 1) && findedgelist(em, eve1,eve3))) {
+                                               EditEdge *sh_edge= NULL;
+                                               EditVert *sh_vert= NULL;
+                                               
+                                               sh_edge= findedgelist(em, eve2,eve3);
+                                               
+                                               if(sh_edge) { /* Add a triangle */
+                                                       if(!exist_face_overlaps(em, eve1,eve2,eve3,NULL))
+                                                               fix_new_face(em, addfacelist(em, eve1,eve2,eve3,NULL,NULL,NULL));
+                                               }
+                                               else { /* Check for a shared vertex */
+                                                       for(eve4= em->verts.first; eve4; eve4= eve4->next) {
+                                                               if(eve4!=eve1 && eve4!=eve2 && eve4!=eve3 && (eve4->f & 1) &&
+                                                                  !findedgelist(em, eve1,eve4) && findedgelist(em, eve2,eve4) &&
+                                                                  findedgelist(em, eve3,eve4)) {
+                                                                       sh_vert= eve4;
+                                                                       break;
+                                                               }
+                                                       }
+                                                       
+                                                       if(sh_vert) {
+                                                               if(sh_vert) {
+                                                                       if(!exist_face_overlaps(em, eve1,eve2,eve4,eve3))
+                                                                               fix_new_face(em, addfacelist(em, eve1,eve2,eve4,eve3,NULL,NULL));
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+
+       EM_select_flush(em);
+       
+       BIF_undo_push("Add faces");
+// XXX DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+}
+
+void addedgeface_mesh(EditMesh *em)
+{
+       EditVert *eve, *neweve[4];
+       EditEdge *eed;
+       EditFace *efa;
+       short amount=0;
+
+       if(multires_test()) return;
+
+       /* how many selected ? */
+       if(em->selectmode & SCE_SELECT_EDGE) {
+               /* in edge mode finding selected vertices means flushing down edge codes... */
+               /* can't make face with only edge selection info... */
+               EM_selectmode_set(em);
+       }
+       
+       for(eve= em->verts.first; eve; eve= eve->next) {
+               if(eve->f & SELECT) {
+                       amount++;
+                       if(amount>4) break;                     
+                       neweve[amount-1]= eve;
+               }
+       }
+
+       if(amount==2) {
+               eed= addedgelist(em, neweve[0], neweve[1], NULL);
+               EM_select_edge(eed, 1);
+               BIF_undo_push("Add edge");
+
+               // XXX          DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
+               return;
+       }
+       else if(amount > 4) {
+               
+               /* Python Menu removed XXX */
+               int ret;
+               
+               /* facemenu, will add python items */
+               char facemenu[4096]= "Make Faces%t|Auto%x1|Make FGon%x2|Clear FGon%x3";
+               
+               ret= pupmenu(facemenu);
+               
+               if(ret==1) addfaces_from_edgenet(em);
+               else if(ret==2) make_fgon(em, 1);
+               else if(ret==3) make_fgon(em, 0);
+               
+               return;
+       }
+       else if(amount<2) {
+               error("Incorrect number of vertices to make edge/face");
+               return;
+       }
+
+       efa= NULL; // check later
+
+       if(amount==3) {
+               
+               if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], NULL)==0) {
+                       efa= addfacelist(em, neweve[0], neweve[1], neweve[2], 0, NULL, NULL);
+                       EM_select_face(efa, 1);
+               }
+               else error("The selected vertices already form a face");
+       }
+       else if(amount==4) {
+               /* this test survives when theres 2 triangles */
+               if(exist_face(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+                       int tria= 0;
+                       
+                       /* remove trias if they exist, 4 cases.... */
+                       if(exist_face(em, neweve[0], neweve[1], neweve[2], NULL)) tria++;
+                       if(exist_face(em, neweve[0], neweve[1], neweve[3], NULL)) tria++;
+                       if(exist_face(em, neweve[0], neweve[2], neweve[3], NULL)) tria++;
+                       if(exist_face(em, neweve[1], neweve[2], neweve[3], NULL)) tria++;
+               
+                       if(tria==2) join_triangles(em);
+                       else if(exist_face_overlaps(em, neweve[0], neweve[1], neweve[2], neweve[3])==0) {
+                                /* If there are 4 Verts, But more selected edges, we need to call addfaces_from_edgenet */
+                                       EditEdge *eedcheck;
+                                       int count;
+                                       count = 0;
+                                       for(eedcheck= em->edges.first; eedcheck; eedcheck= eedcheck->next) {
+                                               if(eedcheck->f & SELECT) {
+                                                       count++;
+                                               }
+                                       }       
+                               
+                               if(count++ > 4){
+                                       addfaces_from_edgenet(em);
+                                       return;
+                               } else {
+                               /* if 4 edges exist, we just create the face, convex or not */
+                                       efa= addface_from_edges(em);
+                                       if(efa==NULL) {
+                                               
+                                               /* the order of vertices can be anything, 6 cases to check */
+                                               if( convex(neweve[0]->co, neweve[1]->co, neweve[2]->co, neweve[3]->co) ) {
+                                                       efa= addfacelist(em, neweve[0], neweve[1], neweve[2], neweve[3], NULL, NULL);
+                                               }
+                                               else if( convex(neweve[0]->co, neweve[2]->co, neweve[3]->co, neweve[1]->co) ) {
+                                                       efa= addfacelist(em, neweve[0], neweve[2], neweve[3], neweve[1], NULL, NULL);
+                                               }
+                                               else if( convex(neweve[0]->co, neweve[2]->co, neweve[1]->co, neweve[3]->co) ) {
+                                                       efa= addfacelist(em, neweve[0], neweve[2], neweve[1], neweve[3], NULL, NULL);
+                                               }
+                                               else if( convex(neweve[0]->co, neweve[1]->co, neweve[3]->co, neweve[2]->co) ) {
+                                                       efa= addfacelist(em, neweve[0], neweve[1], neweve[3], neweve[2], NULL, NULL);
+                                               }
+                                               else if( convex(neweve[0]->co, neweve[3]->co, neweve[2]->co, neweve[1]->co) ) {
+                                                       efa= addfacelist(em, neweve[0], neweve[3], neweve[2], neweve[1], NULL, NULL);
+                                               }
+                                               else if( convex(neweve[0]->co, neweve[3]->co, neweve[1]->co, neweve[2]->co) ) {
+                                                       efa= addfacelist(em, neweve[0], neweve[3], neweve[1], neweve[2], NULL, NULL);
+                                               }
+                                               else printf("cannot find nice quad from concave set of vertices\n");
+                                       }
+                               }
+                       }
+                       else error("The selected vertices already form a face");
+               }
+               else error("The selected vertices already form a face");
+       }
+       
+       if(efa) {
+               EM_select_face(efa, 1);
+
+               fix_new_face(em, efa);
+               
+               recalc_editnormals(em);
+               BIF_undo_push("Add face");
+       }
+       
+// XXX DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
+}
+
+
+void adduplicate_mesh(EditMesh *em)
+{
+
+       TEST_EDITMESH
+       if(multires_test()) return;
+
+       waitcursor(1);
+
+       adduplicateflag(em, SELECT);
+
+       waitcursor(0);
+
+               /* We need to force immediate calculation here because 
+               * transform may use derived objects (which are now stale).
+               *
+               * This shouldn't be necessary, derived queries should be
+               * automatically building this data if invalid. Or something.
+               */
+// XXX DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);     
+       object_handle_update(G.obedit);
+
+// XXX BIF_TransformSetUndo("Add Duplicate");
+//     initTransform(TFM_TRANSLATION, CTX_NO_PET);
+//     Transform();
+}
+
+/* check whether an object to add mesh to exists, if not, create one
+* returns 1 if new object created, else 0 */
+static int confirm_objectExists(EditMesh *em, Mesh **me, float mat[][3] )
+{
+       Scene *scene= NULL; // XXX
+       int newob = 0;
+       
+       /* deselectall */
+       EM_clear_flag_all(em, SELECT);
+       
+       /* if no obedit: new object and enter editmode */
+       if(G.obedit==NULL) {
+               /* add_object actually returns an object ! :-)
+               But it also stores the added object struct in
+               G.scene->basact->object (BASACT->object) */
+
+// XXX         add_object_draw(OB_MESH);
+
+               G.obedit= BASACT->object;
+               
+               where_is_object(G.obedit);
+               
+               make_editMesh(NULL, em); // XXX
+               newob= 1;
+       }
+       *me = G.obedit->data;
+       
+       /* imat and center and size */
+       Mat3CpyMat4(mat, G.obedit->obmat);
+       
+       return newob;
+}
+
+// HACK: these can also be found in cmoview.tga.c, but are here so that they can be found by linker
+// this hack is only used so that scons+mingw + split-sources hack works
+       // ------------------------------- start copied code
+/* these are not the monkeys you are looking for */
+int monkeyo= 4;
+int monkeynv= 271;
+int monkeynf= 250;
+signed char monkeyv[271][3]= {
+{-71,21,98},{-63,12,88},{-57,7,74},{-82,-3,79},{-82,4,92},
+{-82,17,100},{-92,21,102},{-101,12,95},{-107,7,83},
+{-117,31,84},{-109,31,95},{-96,31,102},{-92,42,102},
+{-101,50,95},{-107,56,83},{-82,66,79},{-82,58,92},
+{-82,46,100},{-71,42,98},{-63,50,88},{-57,56,74},
+{-47,31,72},{-55,31,86},{-67,31,97},{-66,31,99},
+{-70,43,100},{-82,48,103},{-93,43,105},{-98,31,105},
+{-93,20,105},{-82,31,106},{-82,15,103},{-70,20,100},
+{-127,55,95},{-127,45,105},{-127,-87,94},{-127,-41,100},
+{-127,-24,102},{-127,-99,92},{-127,52,77},{-127,73,73},
+{-127,115,-70},{-127,72,-109},{-127,9,-106},{-127,-49,-45},
+{-101,-24,72},{-87,-56,73},{-82,-89,73},{-80,-114,68},
+{-85,-121,67},{-104,-124,71},{-127,-126,74},{-71,-18,68},
+{-46,-5,69},{-21,19,57},{-17,55,76},{-36,62,80},
+{-64,77,88},{-86,97,94},{-107,92,97},{-119,63,96},
+{-106,53,99},{-111,39,98},{-101,12,95},{-79,2,90},
+{-64,8,86},{-47,24,83},{-45,38,83},{-50,48,85},
+{-72,56,92},{-95,60,97},{-127,-98,94},{-113,-92,94},
+{-112,-107,91},{-119,-113,89},{-127,-114,88},{-127,-25,96},
+{-127,-18,95},{-114,-19,95},{-111,-29,96},{-116,-37,95},
+{-76,-6,86},{-48,7,80},{-34,26,77},{-32,48,84},
+{-39,53,93},{-71,70,102},{-87,82,107},{-101,79,109},
+{-114,55,108},{-111,-13,104},{-100,-57,91},{-95,-90,88},
+{-93,-105,85},{-97,-117,81},{-106,-119,81},{-127,-121,82},
+{-127,6,93},{-127,27,98},{-85,61,95},{-106,18,96},
+{-110,27,97},{-112,-88,94},{-117,-57,96},{-127,-57,96},
+{-127,-42,95},{-115,-35,100},{-110,-29,102},{-113,-17,100},
+{-122,-16,100},{-127,-26,106},{-121,-19,104},{-115,-20,104},
+{-113,-29,106},{-117,-32,103},{-127,-37,103},{-94,-40,71},
+{-106,-31,91},{-104,-40,91},{-97,-32,71},{-127,-112,88},
+{-121,-111,88},{-115,-105,91},{-115,-95,93},{-127,-100,84},
+{-115,-96,85},{-115,-104,82},{-121,-109,81},{-127,-110,81},
+{-105,28,100},{-103,20,99},{-84,55,97},{-92,54,99},
+{-73,51,99},{-55,45,89},{-52,37,88},{-53,25,87},
+{-66,13,92},{-79,8,95},{-98,14,100},{-104,38,100},
+{-100,48,100},{-97,46,97},{-102,38,97},{-96,16,97},
+{-79,11,93},{-68,15,90},{-57,27,86},{-56,36,86},
+{-59,43,87},{-74,50,96},{-91,51,98},{-84,52,96},
+{-101,22,96},{-102,29,96},{-113,59,78},{-102,85,79},
+{-84,88,76},{-65,71,71},{-40,58,63},{-25,52,59},
+{-28,21,48},{-50,0,53},{-71,-12,60},{-127,115,37},
+{-127,126,-10},{-127,-25,-86},{-127,-59,24},{-127,-125,59},
+{-127,-103,44},{-127,-73,41},{-127,-62,36},{-18,30,7},
+{-17,41,-6},{-28,34,-56},{-68,56,-90},{-33,-6,9},
+{-51,-16,-21},{-45,-1,-55},{-84,7,-85},{-97,-45,52},
+{-104,-53,33},{-90,-91,49},{-95,-64,50},{-85,-117,51},
+{-109,-97,47},{-111,-69,46},{-106,-121,56},{-99,-36,55},
+{-100,-29,60},{-101,-22,64},{-100,-50,21},{-89,-40,-34},
+{-83,-19,-69},{-69,111,-49},{-69,119,-9},{-69,109,30},
+{-68,67,55},{-34,52,43},{-46,58,36},{-45,90,7},
+{-25,72,16},{-25,79,-15},{-45,96,-25},{-45,87,-57},
+{-25,69,-46},{-48,42,-75},{-65,3,-70},{-22,42,-26},
+{-75,-22,19},{-72,-25,-27},{-13,52,-30},{-28,-18,-16},
+{6,-13,-42},{37,7,-55},{46,41,-54},{31,65,-54},
+{4,61,-40},{3,53,-37},{25,56,-50},{35,37,-52},
+{28,10,-52},{5,-5,-39},{-21,-9,-17},{-9,46,-28},
+{-6,39,-37},{-14,-3,-27},{6,0,-47},{25,12,-57},
+{31,32,-57},{23,46,-56},{4,44,-46},{-19,37,-27},
+{-20,22,-35},{-30,12,-35},{-22,11,-35},{-19,2,-35},
+{-23,-2,-35},{-34,0,-9},{-35,-3,-22},{-35,5,-24},
+{-25,26,-27},{-13,31,-34},{-13,30,-41},{-23,-2,-41},
+{-18,2,-41},{-21,10,-41},{-29,12,-41},{-19,22,-41},
+{6,42,-53},{25,44,-62},{34,31,-63},{28,11,-62},
+{7,0,-54},{-14,-2,-34},{-5,37,-44},{-13,14,-42},
+{-7,8,-43},{1,16,-47},{-4,22,-45},{3,30,-48},
+{8,24,-49},{15,27,-50},{12,35,-50},{4,56,-62},
+{33,60,-70},{48,38,-64},{41,7,-68},{6,-11,-63},
+{-26,-16,-42},{-17,49,-49},
+};
+
+signed char monkeyf[250][4]= {
+{27,4,5,26}, {25,4,5,24}, {3,6,5,4}, {1,6,5,2}, {5,6,7,4}, 
+{3,6,7,2}, {5,8,7,6}, {3,8,7,4}, {7,8,9,6}, 
+{5,8,9,4}, {7,10,9,8}, {5,10,9,6}, {9,10,11,8}, 
+{7,10,11,6}, {9,12,11,10}, {7,12,11,8}, {11,6,13,12}, 
+{5,4,13,12}, {3,-2,13,12}, {-3,-4,13,12}, {-5,-10,13,12}, 
+{-11,-12,14,12}, {-13,-18,14,13}, {-19,4,5,13}, {10,12,4,4}, 
+{10,11,9,9}, {8,7,9,9}, {7,5,6,6}, {6,3,4,4}, 
+{5,1,2,2}, {4,-1,0,0}, {3,-3,-2,-2}, {22,67,68,23}, 
+{20,65,66,21}, {18,63,64,19}, {16,61,62,17}, {14,59,60,15}, 
+{12,19,48,57}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47}, 
+{18,19,48,47}, {18,19,48,47}, {18,19,48,47}, {18,19,48,47}, 
+{18,19,48,47}, {18,-9,-8,47}, {18,27,45,46}, {26,55,43,44}, 
+{24,41,42,54}, {22,39,40,23}, {20,37,38,21}, {18,35,36,19}, 
+{16,33,34,17}, {14,31,32,15}, {12,39,30,13}, {11,48,45,38}, 
+{8,36,-19,9}, {8,-20,44,47}, {42,45,46,43}, {18,19,40,39}, 
+{16,17,38,37}, {14,15,36,35}, {32,44,43,33}, {12,33,32,42}, 
+{19,44,43,42}, {40,41,42,-27}, {8,9,39,-28}, {15,43,42,16}, 
+{13,43,42,14}, {11,43,42,12}, {9,-30,42,10}, {37,12,38,-32}, 
+{-33,37,45,46}, {-33,40,41,39}, {38,40,41,37}, {36,40,41,35}, 
+{34,40,41,33}, {36,39,38,37}, {35,40,39,38}, {1,2,14,21}, 
+{1,2,40,13}, {1,2,40,39}, {1,24,12,39}, {-34,36,38,11}, 
+{35,38,36,37}, {-37,8,35,37}, {-11,-12,-45,40}, {-11,-12,39,38}, 
+{-11,-12,37,36}, {-11,-12,35,34}, {33,34,40,41}, {33,34,38,39}, 
+{33,34,36,37}, {33,-52,34,35}, {33,37,36,34}, {33,35,34,34}, 
+{8,7,37,36}, {-32,7,35,46}, {-34,-33,45,46}, {4,-33,43,34}, 
+{-34,-33,41,42}, {-34,-33,39,40}, {-34,-33,37,38}, {-34,-33,35,36}, 
+{-34,-33,33,34}, {-34,-33,31,32}, {-34,-4,28,30}, {-5,-34,28,27}, 
+{-35,-44,36,27}, {26,35,36,45}, {24,25,44,45}, {25,23,44,42}, 
+{25,24,41,40}, {25,24,39,38}, {25,24,37,36}, {25,24,35,34}, 
+{25,24,33,32}, {25,24,31,30}, {15,24,29,38}, {25,24,27,26}, 
+{23,12,37,26}, {11,12,35,36}, {-86,-59,36,-80}, {-60,-61,36,35}, 
+{-62,-63,36,35}, {-64,-65,36,35}, {-66,-67,36,35}, {-68,-69,36,35}, 
+{-70,-71,36,35}, {-72,-73,36,35}, {-74,-75,36,35}, {42,43,53,58}, 
+{40,41,57,56}, {38,39,55,57}, {-81,-80,37,56}, {-83,-82,55,52}, 
+{-85,-84,51,49}, {-87,-86,48,49}, {47,50,51,48}, {46,48,51,49}, 
+{43,46,49,44}, {-92,-91,45,42}, {-23,49,50,-20}, {-94,40,48,-24}, 
+{-96,-22,48,49}, {-97,48,21,-90}, {-100,36,50,23}, {22,49,48,-100}, 
+{-101,47,46,22}, {21,45,35,25}, {33,34,44,41}, {13,14,28,24}, 
+{-107,26,30,-106}, {14,46,45,15}, {14,44,43,-110}, {-111,42,23,-110}, 
+{6,7,45,46}, {45,44,47,46}, {45,46,47,48}, {47,46,49,48}, 
+{17,49,47,48}, {17,36,46,48}, {35,36,44,45}, {35,36,40,43}, 
+{35,36,38,39}, {-4,-3,37,35}, {-123,34,33,1}, {-9,-8,-7,-6}, 
+{-10,-7,32,-125}, {-127,-11,-126,-126}, {-7,-6,5,31}, {4,5,33,30}, 
+{4,39,33,32}, {4,35,32,38}, {20,21,39,38}, {4,37,38,5}, 
+{-11,-10,36,3}, {-11,15,14,35}, {13,16,34,34}, {-13,14,13,13}, 
+{-3,1,30,29}, {-3,28,29,1}, {-2,31,28,-1}, {12,13,27,30}, 
+{-2,26,12,12}, {35,29,42,36}, {34,35,36,33}, {32,35,36,31}, 
+{30,35,36,29}, {28,35,36,27}, {26,35,36,25}, {34,39,38,35}, 
+{32,39,38,33}, {30,39,38,31}, {28,39,38,29}, {26,39,38,27}, 
+{25,31,32,38}, {-18,-17,45,44}, {-18,17,28,44}, {-24,-20,42,-23}, 
+{11,35,27,14}, {25,28,39,41}, {37,41,40,38}, {34,40,36,35}, 
+{32,40,39,33}, {30,39,31,40}, {21,29,39,22}, {-31,37,28,4}, 
+{-32,33,35,36}, {32,33,34,34}, {18,35,36,48}, {34,25,40,35}, 
+{24,25,38,39}, {24,25,36,37}, {24,25,34,35}, {24,25,32,33}, 
+{24,13,41,31}, {17,11,41,35}, {15,16,34,35}, {13,14,34,35}, 
+{11,12,34,35}, {9,10,34,35}, {7,8,34,35}, {26,25,37,36}, 
+{35,36,37,38}, {37,36,39,38}, {37,38,39,40}, {25,31,36,39}, 
+{18,34,35,30}, {17,22,30,33}, {19,29,21,20}, {16,26,29,17}, 
+{24,29,28,25}, {22,31,28,23}, {20,31,30,21}, {18,31,30,19}, 
+{16,30,17,17}, {-21,-22,35,34}, {-21,-22,33,32}, {-21,-22,31,30}, 
+{-21,-22,29,28}, {-21,-22,27,26}, {-28,-22,25,31}, {24,28,29,30}, 
+{23,24,26,27}, {23,24,25,25}, {-69,-35,-32,27}, {-70,26,25,-66}, 
+{-68,-67,24,-33}, 
+};
+       // ------------------------------- end copied code
+
+
+void make_prim(EditMesh *em, int type, float imat[3][3], int tot, int seg,
+               int subdiv, float dia, float d, int ext, int fill,
+        float cent[3])
+{
+       /*
+        * type - for the type of shape
+        * dia - the radius for cone,sphere cylinder etc.
+        * d - depth for the cone
+        * ext - ?
+        * fill - end capping, and option to fill in circle
+        * cent[3] - center of the data. 
+        * */
+       
+       EditVert *eve, *v1=NULL, *v2, *v3, *v4=NULL, *vtop, *vdown;
+       float phi, phid, vec[3];
+       float q[4], cmat[3][3], nor[3]= {0.0, 0.0, 0.0};
+       short a, b;
+
+       phid= 2*M_PI/tot;
+       phi= .25*M_PI;
+
+       switch(type) {
+       case 10: /*  grid */
+               /* clear flags */
+               eve= em->verts.first;
+               while(eve) {
+                       eve->f= 0;
+                       eve= eve->next;
+               }
+               /* one segment first: the X axis */
+               phi= 1.0; 
+               phid= 2.0/((float)tot-1);
+               for(a=0;a<tot;a++) {
+                       vec[0]= cent[0]+dia*phi;
+                       vec[1]= cent[1]- dia;
+                       vec[2]= cent[2];
+                       Mat3MulVecfl(imat,vec);
+                       eve= addvertlist(em, vec, NULL);
+                       eve->f= 1+2+4;
+                       if (a) {
+                               addedgelist(em, eve->prev, eve, NULL);
+                       }
+                       phi-=phid;
+               }
+               /* extrude and translate */
+               vec[0]= vec[2]= 0.0;
+               vec[1]= dia*phid;
+               Mat3MulVecfl(imat, vec);
+               for(a=0;a<seg-1;a++) {
+                       extrudeflag_vert(em, 2, nor);   // nor unused
+                       translateflag(em, 2, vec);
+               }
+               break;
+       case 11: /*  UVsphere */
+               
+               /* clear all flags */
+               eve= em->verts.first;
+               while(eve) {
+                       eve->f= 0;
+                       eve= eve->next;
+               }
+               
+               /* one segment first */
+               phi= 0; 
+               phid/=2;
+               for(a=0; a<=tot; a++) {
+                       vec[0]= dia*sin(phi);
+                       vec[1]= 0.0;
+                       vec[2]= dia*cos(phi);
+                       eve= addvertlist(em, vec, NULL);
+                       eve->f= 1+2+4;
+                       if(a==0) v1= eve;
+                       else addedgelist(em, eve->prev, eve, NULL);
+                       phi+= phid;
+               }
+               
+               /* extrude and rotate */
+               phi= M_PI/seg;
+               q[0]= cos(phi);
+               q[3]= sin(phi);
+               q[1]=q[2]= 0;
+               QuatToMat3(q, cmat);
+               
+               for(a=0; a<seg; a++) {
+                       extrudeflag_vert(em, 2, nor); // nor unused
+                       rotateflag(em, 2, v1->co, cmat);
+               }
+
+               removedoublesflag(em, 4, 0, 0.0001);
+
+               /* and now do imat */
+               eve= em->verts.first;
+               while(eve) {
+                       if(eve->f & SELECT) {
+                               VecAddf(eve->co,eve->co,cent);
+                               Mat3MulVecfl(imat,eve->co);
+                       }
+                       eve= eve->next;
+               }
+               break;
+       case 12: /* Icosphere */
+               {
+                       EditVert *eva[12];
+                       EditEdge *eed;
+                       
+                       /* clear all flags */
+                       eve= em->verts.first;
+                       while(eve) {
+                               eve->f= 0;
+                               eve= eve->next;
+                       }
+                       dia/=200;
+                       for(a=0;a<12;a++) {
+                               vec[0]= dia*icovert[a][0];
+                               vec[1]= dia*icovert[a][1];
+                               vec[2]= dia*icovert[a][2];
+                               eva[a]= addvertlist(em, vec, NULL);
+                               eva[a]->f= 1+2;
+                       }
+                       for(a=0;a<20;a++) {
+                               EditFace *evtemp;
+                               v1= eva[ icoface[a][0] ];
+                               v2= eva[ icoface[a][1] ];
+                               v3= eva[ icoface[a][2] ];
+                               evtemp = addfacelist(em, v1, v2, v3, 0, NULL, NULL);
+                               evtemp->e1->f = 1+2;
+                               evtemp->e2->f = 1+2;
+                               evtemp->e3->f = 1+2;
+                       }
+
+                       dia*=200;
+                       for(a=1; a<subdiv; a++) esubdivideflag(em, 2, dia, 0,1,0);
+                       /* and now do imat */
+                       eve= em->verts.first;
+                       while(eve) {
+                               if(eve->f & 2) {
+                                       VecAddf(eve->co,eve->co,cent);
+                                       Mat3MulVecfl(imat,eve->co);
+                               }
+                               eve= eve->next;
+                       }
+                       
+                       // Clear the flag 2 from the edges
+                       for(eed=em->edges.first;eed;eed=eed->next){
+                               if(eed->f & 2){
+                                          eed->f &= !2;
+                               }   
+                       }
+               }
+               break;
+       case 13: /* Monkey */
+               {
+                       //extern int monkeyo, monkeynv, monkeynf;
+                       //extern signed char monkeyf[][4];
+                       //extern signed char monkeyv[][3];
+                       EditVert **tv= MEM_mallocN(sizeof(*tv)*monkeynv*2, "tv");
+                       int i;
+
+                       for (i=0; i<monkeynv; i++) {
+                               float v[3];
+                               v[0]= (monkeyv[i][0]+127)/128.0, v[1]= monkeyv[i][1]/128.0, v[2]= monkeyv[i][2]/128.0;
+                               tv[i]= addvertlist(em, v, NULL);
+                               tv[i]->f |= SELECT;
+                               tv[monkeynv+i]= (fabs(v[0]= -v[0])<0.001)?tv[i]:addvertlist(em, v, NULL);
+                               tv[monkeynv+i]->f |= SELECT;
+                       }
+                       for (i=0; i<monkeynf; i++) {
+                               addfacelist(em, tv[monkeyf[i][0]+i-monkeyo], tv[monkeyf[i][1]+i-monkeyo], tv[monkeyf[i][2]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
+                               addfacelist(em, tv[monkeynv+monkeyf[i][2]+i-monkeyo], tv[monkeynv+monkeyf[i][1]+i-monkeyo], tv[monkeynv+monkeyf[i][0]+i-monkeyo], (monkeyf[i][3]!=monkeyf[i][2])?tv[monkeynv+monkeyf[i][3]+i-monkeyo]:NULL, NULL, NULL);
+                       }
+
+                       MEM_freeN(tv);
+
+                       /* and now do imat */
+                       for(eve= em->verts.first; eve; eve= eve->next) {
+                               if(eve->f & SELECT) {
+                                       VecAddf(eve->co,eve->co,cent);
+                                       Mat3MulVecfl(imat,eve->co);
+                               }
+                       }
+                       recalc_editnormals(em);
+               }
+               break;
+       default: /* all types except grid, sphere... */
+               if(ext==0 && type!=7) d= 0;
+       
+               /* vertices */
+               vtop= vdown= v1= v2= 0;
+               for(b=0; b<=ext; b++) {
+                       for(a=0; a<tot; a++) {
+                               
+                               vec[0]= cent[0]+dia*sin(phi);
+                               vec[1]= cent[1]+dia*cos(phi);
+                               vec[2]= cent[2]+d;
+                               
+                               Mat3MulVecfl(imat, vec);
+                               eve= addvertlist(em, vec, NULL);
+                               eve->f= SELECT;
+                               if(a==0) {
+                                       if(b==0) v1= eve;
+                                       else v2= eve;
+                               }
+                               phi+=phid;
+                       }
+                       d= -d;
+               }
+               /* center vertices */
+               /* type 7, a cone can only have 1 one side filled
+                * if the cone has no capping, dont add vtop */
+               if((fill && type>1) || type == 7) {
+                       VECCOPY(vec,cent);
+                       vec[2]-= -d;
+                       Mat3MulVecfl(imat,vec);
+                       vdown= addvertlist(em, vec, NULL);
+                       if((ext || type==7) && fill) {
+                               VECCOPY(vec,cent);
+                               vec[2]-= d;
+                               Mat3MulVecfl(imat,vec);
+                               vtop= addvertlist(em, vec, NULL);
+                       }
+               } else {
+                       vdown= v1;
+                       vtop= v2;
+               }
+               if(vtop) vtop->f= SELECT;
+               if(vdown) vdown->f= SELECT;
+       
+               /* top and bottom face */
+               if(fill || type==7) {
+                       if(tot==4 && (type==0 || type==1)) {
+                               v3= v1->next->next;
+                               if(ext) v4= v2->next->next;
+                               
+                               addfacelist(em, v3, v1->next, v1, v3->next, NULL, NULL);
+                               if(ext) addfacelist(em, v2, v2->next, v4, v4->next, NULL, NULL);
+                               
+                       }
+                       else {
+                               v3= v1;
+                               v4= v2;
+                               for(a=1; a<tot; a++) {
+                                       addfacelist(em, vdown, v3, v3->next, 0, NULL, NULL);
+                                       v3= v3->next;
+                                       if(ext && fill) {
+                                               addfacelist(em, vtop, v4, v4->next, 0, NULL, NULL);
+                                               v4= v4->next;
+                                       }
+                               }
+                               if(type>1) {
+                                       addfacelist(em, vdown, v3, v1, 0, NULL, NULL);
+                                       if(ext) addfacelist(em, vtop, v4, v2, 0, NULL, NULL);
+                               }
+                       }
+               }
+               else if(type==4) {  /* we need edges for a circle */
+                       v3= v1;
+                       for(a=1;a<tot;a++) {
+                               addedgelist(em, v3, v3->next, NULL);
+                               v3= v3->next;
+                       }
+                       addedgelist(em, v3, v1, NULL);
+               }
+               /* side faces */
+               if(ext) {
+                       v3= v1;
+                       v4= v2;
+                       for(a=1; a<tot; a++) {
+                               addfacelist(em, v3, v3->next, v4->next, v4, NULL, NULL);
+                               v3= v3->next;
+                               v4= v4->next;
+                       }
+                       addfacelist(em, v3, v1, v2, v4, NULL, NULL);
+               }
+               else if(type==7 && fill) {
+                       /* add the bottom flat area of the cone
+                        * if capping is disabled dont bother */
+                       v3= v1;
+                       for(a=1; a<tot; a++) {
+                               addfacelist(em, vtop, v3->next, v3, 0, NULL, NULL);
+                               v3= v3->next;
+                       }
+                       addfacelist(em, vtop, v1, v3, 0, NULL, NULL);
+               }
+       }
+       /* simple selection flush OK, based on fact it's a single model */
+       EM_select_flush(em); /* flushes vertex -> edge -> face selection */
+       
+       if(type!=0 && type!=13)
+               righthandfaces(em, 1);  /* otherwise monkey has eyes in wrong direction */
+}
+
+void add_primitiveMesh(Scene *scene, View3D *v3d, EditMesh *em, int type)
+{
+       Mesh *me;
+       float *curs, d, dia, phi, phid, cent[3], imat[3][3], mat[3][3];
+       float cmat[3][3];
+       static int tot=32, seg=32, subdiv=2,
+               /* so each type remembers its fill setting */
+               fill_circle=0, fill_cone=1, fill_cylinder=1;
+       
+       int ext=0, fill=0, totoud, newob=0;
+       char *undostr="Add Primitive";
+       char *name=NULL;
+       
+//     if(G.scene->id.lib) return;
+       
+       /* this function also comes from an info window */
+// XXX if ELEM(curarea->spacetype, SPACE_VIEW3D, SPACE_INFO); else return;
+
+       if (G.obedit && G.obedit->type==OB_MESH && multires_test()) return;
+       
+       /* if editmode exists for other type, it exits */
+       check_editmode(OB_MESH);
+       
+       if(G.f & (G_VERTEXPAINT+G_TEXTUREPAINT)) {
+               G.f &= ~(G_VERTEXPAINT+G_TEXTUREPAINT);
+       }
+
+       totoud= tot; /* store, and restore when cube/plane */
+       
+       dia= v3d->grid;
+       d= v3d->grid;
+       
+       /* ext==extrudeflag, tot==amount of vertices in basis */
+       switch(type) {
+       case 0:         /* plane */
+               tot= 4;
+               ext= 0;
+               fill= 1;
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) name = "Plane";
+               undostr="Add Plane";
+               break;
+       case 1:         /* cube  */
+               tot= 4;
+               ext= 1;
+               fill= 1;
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) name = "Cube";
+               undostr="Add Cube";
+               break;
+       case 4:         /* circle  */
+               add_numbut(0, NUM|INT, "Vertices:", 3, 500, &tot, NULL);
+               add_numbut(1, NUM|FLO, "Radius:", 0.001*v3d->grid, 100*v3d->grid, &dia, NULL);
+               add_numbut(2, TOG|INT, "Fill", 0, 0, &(fill_circle), NULL);
+               if (!(do_clever_numbuts("Add Circle", 3, 0))) return;
+               ext= 0;
+               fill = fill_circle;
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) name = "Circle";
+               undostr="Add Circle";
+               break;
+       case 5:         /* cylinder  */
+               d*=2;
+               add_numbut(0, NUM|INT, "Vertices:", 2, 500, &tot, NULL);
+               add_numbut(1, NUM|FLO, "Radius:", 0.001*v3d->grid, 100*v3d->grid, &dia, NULL);
+               add_numbut(2, NUM|FLO, "Depth:", 0.001*v3d->grid, 100*v3d->grid, &d, NULL);
+               add_numbut(3, TOG|INT, "Cap Ends", 0, 0, &(fill_cylinder), NULL);
+               if (!(do_clever_numbuts("Add Cylinder", 4, 0))) return;
+               ext= 1;
+               fill = fill_cylinder;
+               d/=2;
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) {
+                       if (fill)       name = "Cylinder";
+                       else            name = "Tube";
+               }
+               undostr="Add Cylinder";
+               break;
+       case 7:         /* cone  */
+               d*=2;
+               add_numbut(0, NUM|INT, "Vertices:", 2, 500, &tot, NULL);
+               add_numbut(1, NUM|FLO, "Radius:", 0.001*v3d->grid, 100*v3d->grid, &dia, NULL);
+               add_numbut(2, NUM|FLO, "Depth:", 0.001*v3d->grid, 100*v3d->grid, &d, NULL);
+               add_numbut(3, TOG|INT, "Cap End", 0, 0, &(fill_cone), NULL);
+               if (!(do_clever_numbuts("Add Cone", 4, 0))) return;
+               d/=2;
+               ext= 0;
+               fill = fill_cone;
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) name = "Cone";
+               undostr="Add Cone";
+               break;
+       case 10:        /* grid */
+               add_numbut(0, NUM|INT, "X res:", 3, 1000, &tot, NULL);
+               add_numbut(1, NUM|INT, "Y res:", 3, 1000, &seg, NULL);
+               if (!(do_clever_numbuts("Add Grid", 2, 0))) return; 
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) name = "Grid";
+               undostr="Add Grid";
+               break;
+       case 11:        /* UVsphere */
+               add_numbut(0, NUM|INT, "Segments:", 3, 500, &seg, NULL);
+               add_numbut(1, NUM|INT, "Rings:", 3, 500, &tot, NULL);
+               add_numbut(2, NUM|FLO, "Radius:", 0.001*v3d->grid, 100*v3d->grid, &dia, NULL);
+               
+               if (!(do_clever_numbuts("Add UV Sphere", 3, 0))) return;
+               
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) name = "Sphere";
+               undostr="Add UV Sphere";
+               break;
+       case 12:        /* Icosphere */
+               add_numbut(0, NUM|INT, "Subdivision:", 1, 8, &subdiv, NULL);
+               add_numbut(1, NUM|FLO, "Radius:", 0.001*v3d->grid, 100*v3d->grid, &dia, NULL);
+               if (!(do_clever_numbuts("Add Ico Sphere", 2, 0))) return;
+               
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) name = "Sphere";
+               undostr="Add Ico Sphere";
+               break;
+       case 13:        /* Monkey */
+               newob = confirm_objectExists(em, &me, mat );
+               if(newob) name = "Suzanne";
+               undostr="Add Monkey";
+               break;
+       default:
+               newob = confirm_objectExists(em, &me, mat );
+               break;
+       }
+
+       if( name!=NULL ) {
+               rename_id((ID *)G.obedit, name );
+               rename_id((ID *)me, name );
+       }
+       
+       d = -d;
+       curs= give_cursor(scene, v3d);
+       VECCOPY(cent, curs);
+       cent[0]-= G.obedit->obmat[3][0];
+       cent[1]-= G.obedit->obmat[3][1];
+       cent[2]-= G.obedit->obmat[3][2];
+
+       if ( !(newob) || U.flag & USER_ADD_VIEWALIGNED) Mat3CpyMat4(imat, v3d->viewmat);
+       else Mat3One(imat);
+       Mat3MulVecfl(imat, cent);
+       Mat3MulMat3(cmat, imat, mat);
+       Mat3Inv(imat,cmat);
+       
+       
+       if(type == 0 || type == 1) /* plane, cube (diameter of 1.41 makes it unit size) */
+               dia *= sqrt(2.0);
+
+       phid= 2*M_PI/tot;
+       phi= .25*M_PI;
+
+       make_prim(em, type, imat, tot, seg, subdiv, dia, d, ext, fill, cent);
+
+       if(type<2) tot = totoud;
+
+       /* simple selection flush OK, based on fact it's a single model */
+       EM_select_flush(em); // flushes vertex -> edge -> face selection
+       
+       if(type!=0 && type!=13) righthandfaces(em, 1);  /* otherwise monkey has eyes in wrong direction... */
+
+// XXX DAG_object_flush_update(G.scene, G.obedit, OB_RECALC_DATA);
+       
+       /* if a new object was created, it stores it in Mesh, for reload original data and undo */
+       if ( !(newob) || U.flag & USER_ADD_EDITMODE) {
+               if(newob) load_editMesh(scene, em);
+       } else {
+               exit_editmode(2);
+       }
+       
+       BIF_undo_push(undostr);
+}
+
diff --git a/source/blender/editors/mesh/editmesh_lib.c b/source/blender/editors/mesh/editmesh_lib.c
new file mode 100644 (file)
index 0000000..667c8d5
--- /dev/null
@@ -0,0 +1,2266 @@
+/**
+ * $Id: 
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2004 by Blender Foundation
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): none yet.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/*
+
+editmesh_lib: generic (no UI, no menus) operations/evaluators for editmesh data
+
+*/
+
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_object_types.h"
+#include "DNA_scene_types.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_arithb.h"
+#include "BLI_editVert.h"
+
+#include "BKE_customdata.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_utildefines.h"
+
+#include "ED_mesh.h"
+
+#include "editmesh.h"
+
+/* this replaces the active flag used in uv/face mode */
+void EM_set_actFace(EditMesh *em, EditFace *efa)
+{
+       em->act_face = efa;
+}
+
+EditFace *EM_get_actFace(EditMesh *em, int sloppy)
+{
+       if (em->act_face) {
+               return em->act_face;
+       } else if (sloppy) {
+               EditFace *efa= NULL;
+               EditSelection *ese;
+               
+               ese = em->selected.last;
+               for (; ese; ese=ese->prev){
+                       if(ese->type == EDITFACE) {
+                               efa = (EditFace *)ese->data;
+                               
+                               if (efa->h)     efa= NULL;
+                               else            break;
+                       }
+               }
+               if (efa==NULL) {
+                       for (efa= em->faces.first; efa; efa= efa->next) {
+                               if (efa->f & SELECT)
+                                       break;
+                       }
+               }
+               return efa; /* can still be null */
+       }
+       return NULL;
+}
+
+int EM_get_actSelection(EditMesh *em, EditSelection *ese)
+{
+       EditSelection *ese_last = em->selected.last;
+       EditFace *efa = EM_get_actFace(em, 0);
+
+       ese->next = ese->prev = NULL;
+       
+       if (ese_last) {
+               if (ese_last->type == EDITFACE) { /* if there is an active face, use it over the last selected face */
+                       if (efa) {
+                               ese->data = (void *)efa;
+                       } else {
+                               ese->data = ese_last->data;
+                       }
+                       ese->type = EDITFACE;
+               } else {
+                       ese->data = ese_last->data;
+                       ese->type = ese_last->type;
+               }
+       } else if (efa) { /* no */
+               ese->data = (void *)efa;
+               ese->type = EDITFACE;
+       } else {
+               ese->data = NULL;
+               return 0;
+       }
+       return 1;
+}
+
+/* ********* Selection History ************ */
+static int EM_check_selection(EditMesh *em, void *data)
+{
+       EditSelection *ese;
+       
+       for(ese = em->selected.first; ese; ese = ese->next){
+               if(ese->data == data) return 1;
+               }
+       
+       return 0;
+}
+
+void EM_remove_selection(EditMesh *em, void *data, int type)
+{
+       EditSelection *ese;
+       for(ese=em->selected.first; ese; ese = ese->next){
+               if(ese->data == data){
+                       BLI_freelinkN(&(em->selected),ese);
+                       break;
+               }
+       }
+}
+
+void EM_store_selection(EditMesh *em, void *data, int type)
+{
+       EditSelection *ese;
+       if(!EM_check_selection(em, data)){
+               ese = (EditSelection*) MEM_callocN( sizeof(EditSelection), "Edit Selection");
+               ese->type = type;
+               ese->data = data;
+               BLI_addtail(&(em->selected),ese);
+       }
+}
+
+void EM_validate_selections(EditMesh *em)
+{
+       EditSelection *ese, *nextese;
+
+       ese = em->selected.first;
+       while(ese){
+               nextese = ese->next;
+               if(ese->type == EDITVERT && !(((EditVert*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
+               else if(ese->type == EDITEDGE && !(((EditEdge*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
+               else if(ese->type == EDITFACE && !(((EditFace*)ese->data)->f & SELECT)) BLI_freelinkN(&(em->selected), ese);
+               ese = nextese;
+       }
+}
+
+static void EM_strip_selections(EditMesh *em)
+{
+       EditSelection *ese, *nextese;
+       if(!(em->selectmode & SCE_SELECT_VERTEX)){
+               ese = em->selected.first;
+               while(ese){
+                       nextese = ese->next; 
+                       if(ese->type == EDITVERT) BLI_freelinkN(&(em->selected),ese);
+                       ese = nextese;
+               }
+       }
+       if(!(em->selectmode & SCE_SELECT_EDGE)){
+               ese=em->selected.first;
+               while(ese){
+                       nextese = ese->next;
+                       if(ese->type == EDITEDGE) BLI_freelinkN(&(em->selected), ese);
+                       ese = nextese;
+               }
+       }
+       if(!(em->selectmode & SCE_SELECT_FACE)){
+               ese=em->selected.first;
+               while(ese){
+                       nextese = ese->next;
+                       if(ese->type == EDITFACE) BLI_freelinkN(&(em->selected), ese);
+                       ese = nextese;
+               }
+       }
+}
+
+/* generic way to get data from an EditSelection type 
+These functions were written to be used by the Modifier widget when in Rotate about active mode,
+but can be used anywhere.
+EM_editselection_center
+EM_editselection_normal
+EM_editselection_plane
+*/
+void EM_editselection_center(float *center, EditSelection *ese)
+{
+       if (ese->type==EDITVERT) {
+               EditVert *eve= ese->data;
+               VecCopyf(center, eve->co);
+       } else if (ese->type==EDITEDGE) {
+               EditEdge *eed= ese->data;
+               VecAddf(center, eed->v1->co, eed->v2->co);
+               VecMulf(center, 0.5);
+       } else if (ese->type==EDITFACE) {
+               EditFace *efa= ese->data;
+               VecCopyf(center, efa->cent);
+       }
+}
+
+void EM_editselection_normal(float *normal, EditSelection *ese)
+{
+       if (ese->type==EDITVERT) {
+               EditVert *eve= ese->data;
+               VecCopyf(normal, eve->no);
+       } else if (ese->type==EDITEDGE) {
+               EditEdge *eed= ese->data;
+               float plane[3]; /* need a plane to correct the normal */
+               float vec[3]; /* temp vec storage */
+               
+               VecAddf(normal, eed->v1->no, eed->v2->no);
+               VecSubf(plane, eed->v2->co, eed->v1->co);
+               
+               /* the 2 vertex normals will be close but not at rightangles to the edge
+               for rotate about edge we want them to be at right angles, so we need to
+               do some extra colculation to correct the vert normals,
+               we need the plane for this */
+               Crossf(vec, normal, plane);
+               Crossf(normal, plane, vec); 
+               Normalize(normal);
+               
+       } else if (ese->type==EDITFACE) {
+               EditFace *efa= ese->data;
+               VecCopyf(normal, efa->n);
+       }
+}
+
+/* Calculate a plane that is rightangles to the edge/vert/faces normal
+also make the plane run allong an axis that is related to the geometry,
+because this is used for the manipulators Y axis.*/
+void EM_editselection_plane(float *plane, EditSelection *ese)
+{
+       if (ese->type==EDITVERT) {
+               EditVert *eve= ese->data;
+               float vec[3]={0,0,0};
+               
+               if (ese->prev) { /*use previously selected data to make a usefull vertex plane */
+                       EM_editselection_center(vec, ese->prev);
+                       VecSubf(plane, vec, eve->co);
+               } else {
+                       /* make a fake  plane thats at rightangles to the normal
+                       we cant make a crossvec from a vec thats the same as the vec
+                       unlikely but possible, so make sure if the normal is (0,0,1)
+                       that vec isnt the same or in the same direction even.*/
+                       if (eve->no[0]<0.5)                     vec[0]=1;
+                       else if (eve->no[1]<0.5)        vec[1]=1;
+                       else                                            vec[2]=1;
+                       Crossf(plane, eve->no, vec);
+               }
+       } else if (ese->type==EDITEDGE) {
+               EditEdge *eed= ese->data;
+
+               /*the plane is simple, it runs allong the edge
+               however selecting different edges can swap the direction of the y axis.
+               this makes it less likely for the y axis of the manipulator
+               (running along the edge).. to flip less often.
+               at least its more pradictable */
+               if (eed->v2->co[1] > eed->v1->co[1]) /*check which to do first */
+                       VecSubf(plane, eed->v2->co, eed->v1->co);
+               else
+                       VecSubf(plane, eed->v1->co, eed->v2->co);
+               
+       } else if (ese->type==EDITFACE) {
+               EditFace *efa= ese->data;
+               float vec[3];
+               if (efa->v4) { /*if its a quad- set the plane along the 2 longest edges.*/
+                       float vecA[3], vecB[3];
+                       VecSubf(vecA, efa->v4->co, efa->v3->co);
+                       VecSubf(vecB, efa->v1->co, efa->v2->co);
+                       VecAddf(plane, vecA, vecB);
+                       
+                       VecSubf(vecA, efa->v1->co, efa->v4->co);
+                       VecSubf(vecB, efa->v2->co, efa->v3->co);
+                       VecAddf(vec, vecA, vecB);                                               
+                       /*use the biggest edge length*/
+                       if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+                               VecCopyf(plane, vec);
+               } else {
+                       /*start with v1-2 */
+                       VecSubf(plane, efa->v1->co, efa->v2->co);
+                       
+                       /*test the edge between v2-3, use if longer */
+                       VecSubf(vec, efa->v2->co, efa->v3->co);
+                       if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+                               VecCopyf(plane, vec);
+                       
+                       /*test the edge between v1-3, use if longer */
+                       VecSubf(vec, efa->v3->co, efa->v1->co);
+                       if (plane[0]*plane[0]+plane[1]*plane[1]+plane[2]*plane[2] < vec[0]*vec[0]+vec[1]*vec[1]+vec[2]*vec[2])
+                               VecCopyf(plane, vec);
+               }
+       }
+       Normalize(plane);
+}
+
+
+
+void EM_select_face(EditFace *efa, int sel)
+{
+       if(sel) {
+               efa->f |= SELECT;
+               efa->e1->f |= SELECT;
+               efa->e2->f |= SELECT;
+               efa->e3->f |= SELECT;
+               if(efa->e4) efa->e4->f |= SELECT;
+               efa->v1->f |= SELECT;
+               efa->v2->f |= SELECT;
+               efa->v3->f |= SELECT;
+               if(efa->v4) efa->v4->f |= SELECT;
+       }
+       else {
+               efa->f &= ~SELECT;
+               efa->e1->f &= ~SELECT;
+               efa->e2->f &= ~SELECT;
+               efa->e3->f &= ~SELECT;
+               if(efa->e4) efa->e4->f &= ~SELECT;
+               efa->v1->f &= ~SELECT;
+               efa->v2->f &= ~SELECT;
+               efa->v3->f &= ~SELECT;
+               if(efa->v4) efa->v4->f &= ~SELECT;
+       }
+}
+
+void EM_select_edge(EditEdge *eed, int sel)
+{
+       if(sel) {
+               eed->f |= SELECT;
+               eed->v1->f |= SELECT;
+               eed->v2->f |= SELECT;
+       }
+       else {
+               eed->f &= ~SELECT;
+               eed->v1->f &= ~SELECT;
+               eed->v2->f &= ~SELECT;
+       }
+}
+
+void EM_select_face_fgon(EditMesh *em, EditFace *efa, int val)
+{
+       short index=0;
+       
+       if(efa->fgonf==0) EM_select_face(efa, val);
+       else {
+               if(efa->e1->fgoni) index= efa->e1->fgoni;
+               if(efa->e2->fgoni) index= efa->e2->fgoni;
+               if(efa->e3->fgoni) index= efa->e3->fgoni;
+               if(efa->v4 && efa->e4->fgoni) index= efa->e4->fgoni;
+               
+               if(index==0) printf("wrong fgon select\n");
+               
+               // select all ngon faces with index
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->fgonf) {
+                               if(efa->e1->fgoni==index || efa->e2->fgoni==index || 
+                                  efa->e3->fgoni==index || (efa->e4 && efa->e4->fgoni==index) ) {
+                                       EM_select_face(efa, val);
+                               }
+                       }
+               }
+       }
+}
+
+
+/* only vertices */
+int faceselectedOR(EditFace *efa, int flag)
+{
+       if ((efa->v1->f | efa->v2->f | efa->v3->f | (efa->v4?efa->v4->f:0))&flag) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+// replace with (efa->f & SELECT)
+int faceselectedAND(EditFace *efa, int flag)
+{
+       if ((efa->v1->f & efa->v2->f & efa->v3->f & (efa->v4?efa->v4->f:flag))&flag) {
+               return 1;
+       } else {
+               return 0;
+       }
+}
+
+int EM_nfaces_selected(EditMesh *em)
+{
+       EditFace *efa;
+       int count= 0;
+
+       for (efa= em->faces.first; efa; efa= efa->next)
+               if (efa->f & SELECT)
+                       count++;
+
+       return count;
+}
+
+#if 0
+static int EM_nedges(EditMesh *em)
+{
+       EditEdge *eed;
+       int count= 0;
+
+       for (eed= em->edges.first; eed; eed= eed->next) count++;
+       return count;
+}
+#endif
+
+int EM_nvertices_selected(EditMesh *em)
+{
+       EditVert *eve;
+       int count= 0;
+
+       for (eve= em->verts.first; eve; eve= eve->next)
+               if (eve->f & SELECT)
+                       count++;
+
+       return count;
+}
+
+void EM_clear_flag_all(EditMesh *em, int flag)
+{
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       
+       for (eve= em->verts.first; eve; eve= eve->next) eve->f &= ~flag;
+       for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~flag;
+       for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~flag;
+       
+       if(flag & SELECT) BLI_freelistN(&(em->selected));
+}
+
+void EM_set_flag_all(EditMesh *em, int flag)
+{
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       
+       for (eve= em->verts.first; eve; eve= eve->next) if(eve->h==0) eve->f |= flag;
+       for (eed= em->edges.first; eed; eed= eed->next) if(eed->h==0) eed->f |= flag;
+       for (efa= em->faces.first; efa; efa= efa->next) if(efa->h==0) efa->f |= flag;
+       
+}
+
+/* flush for changes in vertices only */
+void EM_deselect_flush(EditMesh *em)
+{
+       EditEdge *eed;
+       EditFace *efa;
+       
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->v1->f & eed->v2->f & SELECT);
+               else eed->f &= ~SELECT;
+       }
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if(efa->v4) {
+                       if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT );
+                       else efa->f &= ~SELECT;
+               }
+               else {
+                       if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT );
+                       else efa->f &= ~SELECT;
+               }
+       }
+}
+
+
+/* flush selection to edges & faces */
+
+/*  this only based on coherent selected vertices, for example when adding new
+    objects. call clear_flag_all() before you select vertices to be sure it ends OK!
+       
+*/
+
+void EM_select_flush(EditMesh *em)
+{
+       EditEdge *eed;
+       EditFace *efa;
+       
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
+       }
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if(efa->v4) {
+                       if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT ) efa->f |= SELECT;
+               }
+               else {
+                       if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT ) efa->f |= SELECT;
+               }
+       }
+}
+
+/* when vertices or edges can be selected, also make fgon consistant */
+static void check_fgons_selection(EditMesh *em)
+{
+       EditFace *efa, *efan;
+       EditEdge *eed;
+       ListBase *lbar;
+       int sel, desel, index, totfgon= 0;
+       
+       /* count amount of fgons */
+       for(eed= em->edges.first; eed; eed= eed->next) 
+               if(eed->fgoni>totfgon) totfgon= eed->fgoni;
+       
+       if(totfgon==0) return;
+       
+       lbar= MEM_callocN((totfgon+1)*sizeof(ListBase), "listbase array");
+       
+       /* put all fgons in lbar */
+       for(efa= em->faces.first; efa; efa= efan) {
+               efan= efa->next;
+               index= efa->e1->fgoni;
+               if(index==0) index= efa->e2->fgoni;
+               if(index==0) index= efa->e3->fgoni;
+               if(index==0 && efa->e4) index= efa->e4->fgoni;
+               if(index) {
+                       BLI_remlink(&em->faces, efa);
+                       BLI_addtail(&lbar[index], efa);
+               }
+       }
+       
+       /* now check the fgons */
+       for(index=1; index<=totfgon; index++) {
+               /* we count on vertices/faces/edges being set OK, so we only have to set ngon itself */
+               sel= desel= 0;
+               for(efa= lbar[index].first; efa; efa= efa->next) {
+                       if(efa->e1->fgoni==0) {
+                               if(efa->e1->f & SELECT) sel++;
+                               else desel++;
+                       }
+                       if(efa->e2->fgoni==0) {
+                               if(efa->e2->f & SELECT) sel++;
+                               else desel++;
+                       }
+                       if(efa->e3->fgoni==0) {
+                               if(efa->e3->f & SELECT) sel++;
+                               else desel++;
+                       }
+                       if(efa->e4 && efa->e4->fgoni==0) {
+                               if(efa->e4->f & SELECT) sel++;
+                               else desel++;
+                       }
+                       
+                       if(sel && desel) break;
+               }
+
+               if(sel && desel) sel= 0;
+               else if(sel) sel= 1;
+               else sel= 0;
+               
+               /* select/deselect and put back */
+               for(efa= lbar[index].first; efa; efa= efa->next) {
+                       if(sel) efa->f |= SELECT;
+                       else efa->f &= ~SELECT;
+               }
+               addlisttolist(&em->faces, &lbar[index]);
+       }
+       
+       MEM_freeN(lbar);
+}
+
+
+/* flush to edges & faces */
+
+/* based on select mode it selects edges/faces 
+   assumed is that verts/edges/faces were properly selected themselves
+   with the calls above
+*/
+
+void EM_selectmode_flush(EditMesh *em)
+{
+       EditEdge *eed;
+       EditFace *efa;
+       
+       // flush to edges & faces
+       if(em->selectmode & SCE_SELECT_VERTEX) {
+               for(eed= em->edges.first; eed; eed= eed->next) {
+                       if(eed->v1->f & eed->v2->f & SELECT) eed->f |= SELECT;
+                       else eed->f &= ~SELECT;
+               }
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->v4) {
+                               if(efa->v1->f & efa->v2->f & efa->v3->f & efa->v4->f & SELECT) efa->f |= SELECT;
+                               else efa->f &= ~SELECT;
+                       }
+                       else {
+                               if(efa->v1->f & efa->v2->f & efa->v3->f & SELECT) efa->f |= SELECT;
+                               else efa->f &= ~SELECT;
+                       }
+               }
+       }
+       // flush to faces
+       else if(em->selectmode & SCE_SELECT_EDGE) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->e4) {
+                               if(efa->e1->f & efa->e2->f & efa->e3->f & efa->e4->f & SELECT) efa->f |= SELECT;
+                               else efa->f &= ~SELECT;
+                       }
+                       else {
+                               if(efa->e1->f & efa->e2->f & efa->e3->f & SELECT) efa->f |= SELECT;
+                               else efa->f &= ~SELECT;
+                       }
+               }
+       }       
+       // make sure selected faces have selected edges too, for extrude (hack?)
+       else if(em->selectmode & SCE_SELECT_FACE) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->f & SELECT) EM_select_face(efa, 1);
+               }
+       }
+       
+       if(!(em->selectmode & SCE_SELECT_FACE))
+               check_fgons_selection(em);
+
+}
+
+void EM_convertsel(EditMesh *em, short oldmode, short selectmode)
+{
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       /*clear flags*/
+       for(eve= em->verts.first; eve; eve= eve->next) eve->f1 = 0;
+       for(eed= em->edges.first; eed; eed= eed->next) eed->f1 = 0;
+       for(efa= em->faces.first; efa; efa= efa->next) efa->f1 = 0;
+       
+       /*have to find out what the selectionmode was previously*/
+       if(oldmode == SCE_SELECT_VERTEX) {
+               if(selectmode == SCE_SELECT_EDGE){
+                       /*select all edges associated with every selected vertex*/
+                       for(eed= em->edges.first; eed; eed= eed->next){
+                               if(eed->v1->f&SELECT) eed->f1 = 1;
+                               else if(eed->v2->f&SELECT) eed->f1 = 1;
+                       }
+                       
+                       for(eed= em->edges.first; eed; eed= eed->next){
+                               if(eed->f1 == 1) EM_select_edge(eed,1); 
+                       }
+               }               
+               else if(selectmode == SCE_SELECT_FACE){
+                       /*select all faces associated with every selected vertex*/
+                       for(efa= em->faces.first; efa; efa= efa->next){
+                               if(efa->v1->f&SELECT) efa->f1 = 1;
+                               else if(efa->v2->f&SELECT) efa->f1 = 1;
+                               else if(efa->v3->f&SELECT) efa->f1 = 1;
+                               else{ 
+                                       if(efa->v4){
+                                               if(efa->v4->f&SELECT) efa->f1 =1;
+                                       }
+                               }
+                       }
+                       for(efa= em->faces.first; efa; efa= efa->next){
+                               if(efa->f1 == 1) EM_select_face(efa,1);
+                       }
+               }
+       }
+       
+       if(oldmode == SCE_SELECT_EDGE){
+               if(selectmode == SCE_SELECT_FACE){
+                       for(efa= em->faces.first; efa; efa= efa->next){
+                               if(efa->e1->f&SELECT) efa->f1 = 1;
+                               else if(efa->e2->f&SELECT) efa->f1 = 1;
+                               else if(efa->e3->f&SELECT) efa->f1 = 1;
+                               else if(efa->e4){
+                                       if(efa->e4->f&SELECT) efa->f1 = 1;
+                               }
+                       }
+                       for(efa= em->faces.first; efa; efa= efa->next){
+                               if(efa->f1 == 1) EM_select_face(efa,1);
+                       }
+               }
+       }
+       
+       check_fgons_selection(em);
+}
+
+/* when switching select mode, makes sure selection is consistant for editing */
+/* also for paranoia checks to make sure edge or face mode works */
+void EM_selectmode_set(EditMesh *em)
+{
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       
+       EM_strip_selections(em); /*strip EditSelections from em->selected that are not relevant to new mode*/
+       
+       if(em->selectmode & SCE_SELECT_VERTEX) {
+               /* vertices -> edges -> faces */
+               for (eed= em->edges.first; eed; eed= eed->next) eed->f &= ~SELECT;
+               for (efa= em->faces.first; efa; efa= efa->next) efa->f &= ~SELECT;
+               
+               EM_select_flush(em);
+       }
+       else if(em->selectmode & SCE_SELECT_EDGE) {
+               /* deselect vertices, and select again based on edge select */
+               for(eve= em->verts.first; eve; eve= eve->next) eve->f &= ~SELECT;
+               for(eed= em->edges.first; eed; eed= eed->next) 
+                       if(eed->f & SELECT) EM_select_edge(eed, 1);
+               /* selects faces based on edge status */
+               EM_selectmode_flush(em);
+       }
+       else if(em->selectmode & SCE_SELECT_FACE) {
+               /* deselect eges, and select again based on face select */
+               for(eed= em->edges.first; eed; eed= eed->next) EM_select_edge(eed, 0);
+               
+               for(efa= em->faces.first; efa; efa= efa->next) 
+                       if(efa->f & SELECT) EM_select_face(efa, 1);
+       }
+}
+
+/* paranoia check, actually only for entering editmode. rule:
+- vertex hidden, always means edge is hidden too
+- edge hidden, always means face is hidden too
+- face hidden, dont change anything
+*/
+void EM_hide_reset(EditMesh *em)
+{
+       EditEdge *eed;
+       EditFace *efa;
+       
+       for(eed= em->edges.first; eed; eed= eed->next) 
+               if(eed->v1->h || eed->v2->h) eed->h |= 1;
+               
+       for(efa= em->faces.first; efa; efa= efa->next) 
+               if((efa->e1->h & 1) || (efa->e2->h & 1) || (efa->e3->h & 1) || (efa->e4 && (efa->e4->h & 1)))
+                       efa->h= 1;
+               
+}
+
+void EM_data_interp_from_verts(EditMesh *em, EditVert *v1, EditVert *v2, EditVert *eve, float fac)
+{
+       void *src[2];
+       float w[2];
+
+       if (v1->data && v2->data) {
+               src[0]= v1->data;
+               src[1]= v2->data;
+               w[0] = 1.0f-fac;
+               w[1] = fac;
+
+               CustomData_em_interp(&em->vdata, src, w, NULL, 2, eve->data);
+       }
+}
+
+void EM_data_interp_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, EditFace *efan, int i1, int i2, int i3, int i4)
+{
+       float w[2][4][4];
+       void *src[2];
+       int count = (efa2)? 2: 1;
+
+       if (efa1->data) {
+               /* set weights for copying from corners directly to other corners */
+               memset(w, 0, sizeof(w));
+
+               w[i1/4][0][i1%4]= 1.0f;
+               w[i2/4][1][i2%4]= 1.0f;
+               w[i3/4][2][i3%4]= 1.0f;
+               if (i4 != -1)
+                       w[i4/4][3][i4%4]= 1.0f;
+
+               src[0]= efa1->data;
+               src[1]= (efa2)? efa2->data: NULL;
+
+               CustomData_em_interp(&em->fdata, src, NULL, (float*)w, count, efan->data);
+       }
+}
+
+EditFace *EM_face_from_faces(EditMesh *em, EditFace *efa1, EditFace *efa2, int i1, int i2, int i3, int i4)
+{
+       EditFace *efan;
+       EditVert **v[2];
+       
+       v[0]= &efa1->v1;
+       v[1]= (efa2)? &efa2->v1: NULL;
+
+       efan= addfacelist(em, v[i1/4][i1%4], v[i2/4][i2%4], v[i3/4][i3%4],
+               (i4 == -1)? 0: v[i4/4][i4%4], efa1, NULL);
+
+       EM_data_interp_from_faces(em, efa1, efa2, efan, i1, i2, i3, i4);
+       
+       return efan;
+}
+
+static void update_data_blocks(EditMesh *em, CustomData *olddata, CustomData *data)
+{
+       EditFace *efa;
+       EditVert *eve;
+       void *block;
+
+       if (data == &em->vdata) {
+               for(eve= em->verts.first; eve; eve= eve->next) {
+                       block = NULL;
+                       CustomData_em_set_default(data, &block);
+                       CustomData_em_copy_data(olddata, data, eve->data, &block);
+                       CustomData_em_free_block(olddata, &eve->data);
+                       eve->data= block;
+               }
+       }
+       else if (data == &em->fdata) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       block = NULL;
+                       CustomData_em_set_default(data, &block);
+                       CustomData_em_copy_data(olddata, data, efa->data, &block);
+                       CustomData_em_free_block(olddata, &efa->data);
+                       efa->data= block;
+               }
+       }
+}
+
+void EM_add_data_layer(EditMesh *em, CustomData *data, int type)
+{
+       CustomData olddata;
+
+       olddata= *data;
+       olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+       CustomData_add_layer(data, type, CD_CALLOC, NULL, 0);
+
+       update_data_blocks(em, &olddata, data);
+       if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+void EM_free_data_layer(EditMesh *em, CustomData *data, int type)
+{
+       CustomData olddata;
+
+       olddata= *data;
+       olddata.layers= (olddata.layers)? MEM_dupallocN(olddata.layers): NULL;
+       CustomData_free_layer_active(data, type, 0);
+
+       update_data_blocks(em, &olddata, data);
+       if (olddata.layers) MEM_freeN(olddata.layers);
+}
+
+/* ********  EXTRUDE ********* */
+
+static void add_normal_aligned(float *nor, float *add)
+{
+       if( INPR(nor, add) < -0.9999f)
+               VecSubf(nor, nor, add);
+       else
+               VecAddf(nor, nor, add);
+}
+
+static void set_edge_directions_f2(EditMesh *em, int val)
+{
+       EditFace *efa;
+       int do_all= 1;
+       
+       /* edge directions are used for extrude, to detect direction of edges that make new faces */
+       /* we have set 'f2' flags in edges that need to get a direction set (e.g. get new face) */
+       /* the val argument differs... so we need it as arg */
+       
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if(efa->f & SELECT) {
+                       do_all= 0;
+                       if(efa->e1->f2<val) {
+                               if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
+                               else efa->e1->dir= 1;
+                       }
+                       if(efa->e2->f2<val) {
+                               if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
+                               else efa->e2->dir= 1;
+                       }
+                       if(efa->e3->f2<val) {
+                               if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
+                               else efa->e3->dir= 1;
+                       }
+                       if(efa->e4 && efa->e4->f2<val) {
+                               if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
+                               else efa->e4->dir= 1;
+                       }
+               }
+       }       
+       /* ok, no faces done... then we at least set it for exterior edges */
+       if(do_all) {
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       if(efa->e1->v1 == efa->v1) efa->e1->dir= 0;
+                       else efa->e1->dir= 1;
+                       if(efa->e2->v1 == efa->v2) efa->e2->dir= 0;
+                       else efa->e2->dir= 1;
+                       if(efa->e3->v1 == efa->v3) efa->e3->dir= 0;
+                       else efa->e3->dir= 1;
+                       if(efa->e4) {
+                               if(efa->e4->v1 == efa->v4) efa->e4->dir= 0;
+                               else efa->e4->dir= 1;
+                       }
+               }       
+       }
+}
+
+/* individual face extrude */
+/* will use vertex normals for extrusion directions, so *nor is unaffected */
+short extrudeflag_face_indiv(EditMesh *em, short flag, float *nor)
+{
+       EditVert *eve, *v1, *v2, *v3, *v4;
+       EditEdge *eed;
+       EditFace *efa, *nextfa;
+       
+       if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
+       
+       /* selected edges with 1 or more selected face become faces */
+       /* selected faces each makes new faces */
+       /* always remove old faces, keeps volumes manifold */
+       /* select the new extrusion, deselect old */
+       
+       /* step 1; init, count faces in edges */
+       recalc_editnormals(em);
+       
+       for(eve= em->verts.first; eve; eve= eve->next) eve->f1= 0;      // new select flag
+
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               eed->f2= 0; // amount of unselected faces
+       }
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if(efa->f & SELECT);
+               else {
+                       efa->e1->f2++;
+                       efa->e2->f2++;
+                       efa->e3->f2++;
+                       if(efa->e4) efa->e4->f2++;
+               }
+       }
+
+       /* step 2: make new faces from faces */
+       for(efa= em->faces.last; efa; efa= efa->prev) {
+               if(efa->f & SELECT) {
+                       v1= addvertlist(em, efa->v1->co, efa->v1);
+                       v2= addvertlist(em, efa->v2->co, efa->v2);
+                       v3= addvertlist(em, efa->v3->co, efa->v3);
+                       
+                       v1->f1= v2->f1= v3->f1= 1;
+                       VECCOPY(v1->no, efa->n);
+                       VECCOPY(v2->no, efa->n);
+                       VECCOPY(v3->no, efa->n);
+                       if(efa->v4) {
+                               v4= addvertlist(em, efa->v4->co, efa->v4); 
+                               v4->f1= 1;
+                               VECCOPY(v4->no, efa->n);
+                       }
+                       else v4= NULL;
+                       
+                       /* side faces, clockwise */
+                       addfacelist(em, efa->v2, v2, v1, efa->v1, efa, NULL);
+                       addfacelist(em, efa->v3, v3, v2, efa->v2, efa, NULL);
+                       if(efa->v4) {
+                               addfacelist(em, efa->v4, v4, v3, efa->v3, efa, NULL);
+                               addfacelist(em, efa->v1, v1, v4, efa->v4, efa, NULL);
+                       }
+                       else {
+                               addfacelist(em, efa->v1, v1, v3, efa->v3, efa, NULL);
+                       }
+                       /* top face */
+                       addfacelist(em, v1, v2, v3, v4, efa, NULL);
+               }
+       }
+       
+       /* step 3: remove old faces */
+       efa= em->faces.first;
+       while(efa) {
+               nextfa= efa->next;
+               if(efa->f & SELECT) {
+                       BLI_remlink(&em->faces, efa);
+                       free_editface(em, efa);
+               }
+               efa= nextfa;
+       }
+
+       /* step 4: redo selection */
+       EM_clear_flag_all(em, SELECT);
+       
+       for(eve= em->verts.first; eve; eve= eve->next) {
+               if(eve->f1)  eve->f |= SELECT;
+       }
+       
+       EM_select_flush(em);
+       
+       return 'n';
+}
+
+
+/* extrudes individual edges */
+/* nor is filled with constraint vector */
+short extrudeflag_edges_indiv(EditMesh *em, short flag, float *nor) 
+{
+       EditVert *eve;
+       EditEdge *eed;
+       EditFace *efa;
+       
+       for(eve= em->verts.first; eve; eve= eve->next) eve->tmp.v = NULL;
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               eed->tmp.f = NULL;
+               eed->f2= ((eed->f & flag)!=0);
+       }
+       
+       set_edge_directions_f2(em, 2);
+
+       /* sample for next loop */
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               efa->e1->tmp.f = efa;
+               efa->e2->tmp.f = efa;
+               efa->e3->tmp.f = efa;
+               if(efa->e4) efa->e4->tmp.f = efa;
+       }
+       /* make the faces */
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->f & flag) {
+                       if(eed->v1->tmp.v == NULL)
+                               eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
+                       if(eed->v2->tmp.v == NULL)
+                               eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
+
+                       if(eed->dir==1) 
+                               addfacelist(em, eed->v1, eed->v2, 
+                                                       eed->v2->tmp.v, eed->v1->tmp.v, 
+                                                       eed->tmp.f, NULL);
+                       else 
+                               addfacelist(em, eed->v2, eed->v1, 
+                                                       eed->v1->tmp.v, eed->v2->tmp.v, 
+                                                       eed->tmp.f, NULL);
+
+                       /* for transform */
+                       if(eed->tmp.f) {
+                               efa = eed->tmp.f;
+                               if (efa->f & SELECT) add_normal_aligned(nor, efa->n);
+                       }
+               }
+       }
+       Normalize(nor);
+       
+       /* set correct selection */
+       EM_clear_flag_all(em, SELECT);
+       for(eve= em->verts.last; eve; eve= eve->prev) {
+               if(eve->tmp.v) {
+                       eve->tmp.v->f |= flag;
+               }
+       }
+
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               if(eed->v1->f & eed->v2->f & flag) eed->f |= flag;
+       }
+       
+       if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab
+       return 'n';  // n is for normal constraint
+}
+
+/* extrudes individual vertices */
+short extrudeflag_verts_indiv(EditMesh *em, short flag, float *nor) 
+{
+       EditVert *eve;
+       
+       /* make the edges */
+       for(eve= em->verts.first; eve; eve= eve->next) {
+               if(eve->f & flag) {
+                       eve->tmp.v = addvertlist(em, eve->co, eve);
+                       addedgelist(em, eve, eve->tmp.v, NULL);
+               }
+               else eve->tmp.v = NULL;
+       }
+       
+       /* set correct selection */
+       EM_clear_flag_all(em, SELECT);
+
+       for(eve= em->verts.last; eve; eve= eve->prev) 
+               if (eve->tmp.v) 
+                       eve->tmp.v->f |= flag;
+
+       return 'g';     // g is grab
+}
+
+
+/* this is actually a recode of extrudeflag(), using proper edge/face select */
+/* hurms, doesnt use 'flag' yet, but its not called by primitive making stuff anyway */
+static short extrudeflag_edge(EditMesh *em, short flag, float *nor)
+{
+       /* all select edges/faces: extrude */
+       /* old select is cleared, in new ones it is set */
+       EditVert *eve, *nextve;
+       EditEdge *eed, *nexted;
+       EditFace *efa, *nextfa, *efan;
+       short del_old= 0;
+       ModifierData *md;
+       
+       if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
+
+       md = G.obedit->modifiers.first;
+       
+       /* selected edges with 0 or 1 selected face become faces */
+       /* selected faces generate new faces */
+
+       /* if *one* selected face has edge with unselected face; remove old selected faces */
+       
+       /* if selected edge is not used anymore; remove */
+       /* if selected vertex is not used anymore: remove */
+       
+       /* select the new extrusion, deselect old */
+       
+       
+       /* step 1; init, count faces in edges */
+       recalc_editnormals(em);
+       
+       for(eve= em->verts.first; eve; eve= eve->next) {
+               eve->tmp.v = NULL;
+               eve->f1= 0;
+       }
+
+       for(eed= em->edges.first; eed; eed= eed->next) {
+               eed->f1= 0; // amount of unselected faces
+               eed->f2= 0; // amount of selected faces
+               if(eed->f & SELECT) {
+                       eed->v1->f1= 1; // we call this 'selected vertex' now
+                       eed->v2->f1= 1;
+               }
+               eed->tmp.f = NULL;              // here we tuck face pointer, as sample
+       }
+       for(efa= em->faces.first; efa; efa= efa->next) {
+               if(efa->f & SELECT) {
+                       efa->e1->f2++;
+                       efa->e2->f2++;
+                       efa->e3->f2++;
+                       if(efa->e4) efa->e4->f2++;
+                       
+                       // sample for next loop
+                       efa->e1->tmp.f = efa;
+                       efa->e2->tmp.f = efa;
+                       efa->e3->tmp.f = efa;
+                       if(efa->e4) efa->e4->tmp.f = efa;
+               }
+               else {
+                       efa->e1->f1++;
+                       efa->e2->f1++;
+                       efa->e3->f1++;
+                       if(efa->e4) efa->e4->f1++;
+               }
+       }
+       
+       /* If a mirror modifier with clipping is on, we need to adjust some 
+        * of the cases above to handle edges on the line of symmetry.
+        */
+       for (; md; md=md->next) {
+               if (md->type==eModifierType_Mirror) {
+                       MirrorModifierData *mmd = (MirrorModifierData*) md;     
+               
+                       if(mmd->flag & MOD_MIR_CLIPPING) {
+                               float mtx[4][4];
+                               if (mmd->mirror_ob) {
+                                       float imtx[4][4];
+                                       Mat4Invert(imtx, mmd->mirror_ob->obmat);
+                                       Mat4MulMat4(mtx, G.obedit->obmat, imtx);
+                               }
+
+                               for (eed= em->edges.first; eed; eed= eed->next) {
+                                       if(eed->f2 == 1) {
+                                               float co1[3], co2[3];
+
+                                               VecCopyf(co1, eed->v1->co);
+                                               VecCopyf(co2, eed->v2->co);
+
+                                               if (mmd->mirror_ob) {
+                                                       VecMat4MulVecfl(co1, mtx, co1);
+                                                       VecMat4MulVecfl(co2, mtx, co2);
+                                               }
+
+                                               if (mmd->flag & MOD_MIR_AXIS_X)
+                                                       if ( (fabs(co1[0]) < mmd->tolerance) &&
+                                                                (fabs(co2[0]) < mmd->tolerance) )
+                                                               ++eed->f2;
+
+                                               if (mmd->flag & MOD_MIR_AXIS_Y)
+                                                       if ( (fabs(co1[1]) < mmd->tolerance) &&
+                                                                (fabs(co2[1]) < mmd->tolerance) )
+                                                               ++eed->f2;
+
+                                               if (mmd->flag & MOD_MIR_AXIS_Z)
+                                                       if ( (fabs(co1[2]) < mmd->tolerance) &&
+                                                                (fabs(co2[2]) < mmd->tolerance) )
+                                                               ++eed->f2;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       set_edge_directions_f2(em, 2);
+       
+       /* step 1.5: if *one* selected face has edge with unselected face; remove old selected faces */
+       for(efa= em->faces.last; efa; efa= efa->prev) {
+               if(efa->f & SELECT) {
+                       if(efa->e1->f1 || efa->e2->f1 || efa->e3->f1 || (efa->e4 && efa->e4->f1)) {
+                               del_old= 1;
+                               break;
+                       }
+               }
+       }
+                               
+       /* step 2: make new faces from edges */
+       for(eed= em->edges.last; eed; eed= eed->prev) {
+               if(eed->f & SELECT) {
+                       if(eed->f2<2) {
+                               if(eed->v1->tmp.v == NULL)
+                                       eed->v1->tmp.v = addvertlist(em, eed->v1->co, eed->v1);
+                               if(eed->v2->tmp.v == NULL)
+                                       eed->v2->tmp.v = addvertlist(em, eed->v2->co, eed->v2);
+
+                               /* if del_old, the preferred normal direction is exact 
+                                * opposite as for keep old faces
+                                */
+                               if(eed->dir!=del_old) 
+                                       addfacelist(em, eed->v1, eed->v2, 
+                                                               eed->v2->tmp.v, eed->v1->tmp.v, 
+                                                               eed->tmp.f, NULL);
+                               else 
+                                       addfacelist(em, eed->v2, eed->v1, 
+                                                               eed->v1->tmp.v, eed->v2->tmp.v,
+                                                               eed->tmp.f, NULL);
+                       }
+               }
+       }
+       
+       /* step 3: make new faces from faces */
+       for(efa= em->faces.last; efa; efa= efa->prev) {
+               if(efa->f & SELECT) {
+                       if (efa->v1->tmp.v == NULL)
+                               efa->v1->tmp.v = addvertlist(em, efa->v1->co, efa->v1);
+                       if (efa->v2->tmp.v ==NULL)
+                               efa->v2->tmp.v = addvertlist(em, efa->v2->co, efa->v2);
+                       if (efa->v3->tmp.v ==NULL)
+                               efa->v3->tmp.v = addvertlist(em, efa->v3->co, efa->v3);
+                       if (efa->v4 && (efa->v4->tmp.v == NULL))
+                               efa->v4->tmp.v = addvertlist(em, efa->v4->co, efa->v4);
+                       
+                       if(del_old==0) {        // keep old faces means flipping normal
+                               if(efa->v4)
+                                       efan = addfacelist(em, efa->v4->tmp.v, efa->v3->tmp.v, 
+                                                               efa->v2->tmp.v, efa->v1->tmp.v, efa, efa);
+                               else
+                                       efan = addfacelist(em, efa->v3->tmp.v, efa->v2->tmp.v, 
+                                                               efa->v1->tmp.v, NULL, efa, efa);
+                       }
+                       else {
+                               if(efa->v4)
+                                       efan = addfacelist(em, efa->v1->tmp.v, efa->v2->tmp.v, 
+                                                               efa->v3->tmp.v, efa->v4->tmp.v, efa, efa);
+                               else
+                                       efan = addfacelist(em, efa->v1->tmp.v, efa->v2->tmp.v, 
+                                                               efa->v3->tmp.v, NULL, efa, efa);
+                       }
+                       
+                       if (em->act_face == efa) {
+                               em->act_face = efan; 
+                       }
+                       
+                       /* for transform */
+                       add_normal_aligned(nor, efa->n);
+               }
+       }
+       
+       if(del_old) {
+               
+               /* step 4: remove old faces, if del_old */
+               efa= em->faces.first;
+               while(efa) {
+                       nextfa= efa->next;
+                       if(efa->f & SELECT) {
+                               BLI_remlink(&em->faces, efa);
+                               free_editface(em, efa);
+                       }
+                       efa= nextfa;
+               }
+               
+               
+               /* step 5: remove selected unused edges */
+               /* start tagging again */
+               for(eed= em->edges.first; eed; eed= eed->next) eed->f1=0;
+               for(efa= em->faces.first; efa; efa= efa->next) {
+                       efa->e1->f1= 1;
+                       efa->e2->f1= 1;
+                       efa->e3->f1= 1;
+                       if(efa->e4) efa->e4->f1= 1;
+               }
+               /* remove */
+               eed= em->edges.first; 
+               while(eed) {
+                       nexted= eed->next;
+                       if(eed->f & SELECT) {
+                               if(eed->f1==0) {
+                                       remedge(em, eed);
+                                       free_editedge(em, eed);
+                               }
+                       }
+                       eed= nexted;
+               }
+       
+               /* step 6: remove selected unused vertices */
+               for(eed= em->edges.first; eed; eed= eed->next) 
+                       eed->v1->f1= eed->v2->f1= 0;
+               
+               eve= em->verts.first;
+               while(eve) {
+                       nextve= eve->next;
+                       if(eve->f1) {
+                               // hack... but we need it for step 7, redoing selection
+                               if(eve->tmp.v) eve->tmp.v->tmp.v= eve->tmp.v;
+                               
+                               BLI_remlink(&em->verts, eve);
+                               free_editvert(em, eve);
+                       }
+                       eve= nextve;
+               }
+       }
+       
+       Normalize(nor); // translation normal grab
+       
+       /* step 7: redo selection */
+       EM_clear_flag_all(em, SELECT);
+
+       for(eve= em->verts.first; eve; eve= eve->next) {
+               if(eve->tmp.v) {
+                       eve->tmp.v->f |= SELECT;
+               }
+       }
+
+       EM_select_flush(em);
+
+       if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // grab
+       return 'n'; // normal constraint 
+}
+
+short extrudeflag_vert(EditMesh *em, short flag, float *nor)
+{
+       /* all verts/edges/faces with (f & 'flag'): extrude */
+       /* from old verts, 'flag' is cleared, in new ones it is set */
+       EditVert *eve, *v1, *v2, *v3, *v4, *nextve;
+       EditEdge *eed, *e1, *e2, *e3, *e4, *nexted;
+       EditFace *efa, *efa2, *nextvl;
+       short sel=0, del_old= 0, is_face_sel=0;
+       ModifierData *md;
+
+       if(G.obedit==0 || get_mesh(G.obedit)==0) return 0;
+
+       md = G.obedit->modifiers.first;
+
+       /* clear vert flag f1, we use this to detect a loose selected vertice */
+       eve= em->verts.first;
+       while(eve) {
+               if(eve->f & flag) eve->f1= 1;
+               else eve->f1= 0;
+               eve= eve->next;
+       }
+       /* clear edges counter flag, if selected we set it at 1 */
+       eed= em->edges.first;
+       while(eed) {
+               if( (eed->v1->f & flag) && (eed->v2->f & flag) ) {
+                       eed->f2= 1;
+                       eed->v1->f1= 0;
+                       eed->v2->f1= 0;
+               }
+               else eed->f2= 0;
+               
+               eed->f1= 1;             /* this indicates it is an 'old' edge (in this routine we make new ones) */
+               eed->tmp.f = NULL;      /* used as sample */
+               
+               eed= eed->next;
+       }
+
+       /* we set a flag in all selected faces, and increase the associated edge counters */
+
+       efa= em->faces.first;
+       while(efa) {
+               efa->f1= 0;
+
+               if(faceselectedAND(efa, flag)) {
+                       e1= efa->e1;
+                       e2= efa->e2;
+                       e3= efa->e3;
+                       e4= efa->e4;
+
+                       if(e1->f2 < 3) e1->f2++;
+                       if(e2->f2 < 3) e2->f2++;
+                       if(e3->f2 < 3) e3->f2++;
+                       if(e4 && e4->f2 < 3) e4->f2++;
+                       
+                       efa->f1= 1;
+                       is_face_sel= 1; // for del_old
+               }
+               else if(faceselectedOR(efa, flag)) {
+                       e1= efa->e1;
+                       e2= efa->e2;
+                       e3= efa->e3;
+                       e4= efa->e4;
+                       
+                       if( (e1->v1->f & flag) && (e1->v2->f & flag) ) e1->f1= 2;
+                       if( (e2->v1->f & flag) && (e2->v2->f & flag) ) e2->f1= 2;
+                       if( (e3->v1->f & flag) && (e3->v2->f & flag) ) e3->f1= 2;
+                       if( e4 && (e4->v1->f & flag) && (e4->v2->f & flag) ) e4->f1= 2;
+               }
+               
+               // sample for next loop
+               efa->e1->tmp.f = efa;
+               efa->e2->tmp.f = efa;
+               efa->e3->tmp.f = efa;
+               if(efa->e4) efa->e4->tmp.f = efa;
+
+               efa= efa->next;
+       }
+
+       set_edge_directions_f2(em, 3);
+
+       /* the current state now is:
+               eve->f1==1: loose selected vertex 
+
+               eed->f2==0 : edge is not selected, no extrude
+               eed->f2==1 : edge selected, is not part of a face, extrude
+               eed->f2==2 : edge selected, is part of 1 face, extrude
+               eed->f2==3 : edge selected, is part of more faces, no extrude
+               
+               eed->f1==0: new edge
+               eed->f1==1: edge selected, is part of selected face, when eed->f==3: remove
+               eed->f1==2: edge selected, part of a partially selected face
+                                       
+               efa->f1==1 : duplicate this face
+       */
+
+       /* If a mirror modifier with clipping is on, we need to adjust some 
+        * of the cases above to handle edges on the line of symmetry.
+        */
+       for (; md; md=md->next) {
+               if (md->type==eModifierType_Mirror) {
+                       MirrorModifierData *mmd = (MirrorModifierData*) md;     
+               
+                       if(mmd->flag & MOD_MIR_CLIPPING) {
+                               float mtx[4][4];
+                               if (mmd->mirror_ob) {
+                                       float imtx[4][4];
+                                       Mat4Invert(imtx, mmd->mirror_ob->obmat);
+                                       Mat4MulMat4(mtx, G.obedit->obmat, imtx);
+                               }
+
+                               for (eed= em->edges.first; eed; eed= eed->next) {
+                                       if(eed->f2 == 2) {
+                                               float co1[3], co2[3];
+
+                                               VecCopyf(co1, eed->v1->co);
+                                               VecCopyf(co2, eed->v2->co);
+
+                                               if (mmd->mirror_ob) {
+                                                       VecMat4MulVecfl(co1, mtx, co1);
+                                                       VecMat4MulVecfl(co2, mtx, co2);
+                                               }
+
+                                               if (mmd->flag & MOD_MIR_AXIS_X)
+                                                       if ( (fabs(co1[0]) < mmd->tolerance) &&
+                                                                (fabs(co2[0]) < mmd->tolerance) )
+                                                               ++eed->f2;
+
+                                               if (mmd->flag & MOD_MIR_AXIS_Y)
+                                                       if ( (fabs(co1[1]) < mmd->tolerance) &&
+                                                                (fabs(co2[1]) < mmd->tolerance) )
+                                                               ++eed->f2;
+                                               if (mmd->flag & MOD_MIR_AXIS_Z)
+                                                       if ( (fabs(co1[2]) < mmd->tolerance) &&
+                                                                (fabs(co2[2]) < mmd->tolerance) )
+                                                               ++eed->f2;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       /* copy all selected vertices, */
+       /* write pointer to new vert in old struct at eve->tmp.v */
+       eve= em->verts.last;
+       while(eve) {
+               eve->f &= ~128;  /* clear, for later test for loose verts */
+               if(eve->f & flag) {
+                       sel= 1;
+                       v1= addvertlist(em, 0, NULL);
+                       
+                       VECCOPY(v1->co, eve->co);
+                       v1->f= eve->f;
+                       eve->f-= flag;
+                       eve->tmp.v = v1;
+               }
+               else eve->tmp.v = 0;
+               eve= eve->prev;
+       }
+
+       if(sel==0) return 0;
+
+       /* all edges with eed->f2==1 or eed->f2==2 become faces */
+       
+       /* if del_old==1 then extrude is in partial geometry, to keep it manifold.
+                                        verts with f1==0 and (eve->f & 128)==0) are removed
+                        edges with eed->f2>2 are removed
+                                        faces with efa->f1 are removed
+          if del_old==0 the extrude creates a volume.
+       */
+       
+        /* find if we delete old faces */
+       if(is_face_sel) {
+               for(eed= em->edges.first; eed; eed= eed->next) {
+                       if( (eed->f2==1 || eed->f2==2) ) {
+                               if(eed->f1==2) {
+                                       del_old= 1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       
+       eed= em->edges.last;
+       while(eed) {
+               nexted= eed->prev;
+               if( eed->f2<3) {
+                       eed->v1->f |= 128;  /* = no loose vert! */
+                       eed->v2->f |= 128;
+               }
+               if( (eed->f2==1 || eed->f2==2) ) {
+       
+                       /* if del_old, the preferred normal direction is exact opposite as for keep old faces */
+                       if(eed->dir != del_old) 
+                               efa2 = addfacelist(em, eed->v1, eed->v2, 
+                                                                 eed->v2->tmp.v, eed->v1->tmp.v, 
+                                                                 eed->tmp.f, NULL);
+                       else 
+                               efa2 = addfacelist(em, eed->v2, eed->v1, 
+                                                                  eed->v1->tmp.v, eed->v2->tmp.v, 
+                                                                  eed->tmp.f, NULL);
+                       
+                       /* Needs smarter adaption of existing creases.
+                        * If addedgelist is used, make sure seams are set to 0 on these
+                        * new edges, since we do not want to add any seams on extrusion.
+                        */
+                       efa2->e1->crease= eed->crease;
+                       efa2->e2->crease= eed->crease;
+                       efa2->e3->crease= eed->crease;
+                       if(efa2->e4) efa2->e4->crease= eed->crease;
+               }
+
+               eed= nexted;
+       }
+       if(del_old) {
+               eed= em->edges.first;
+               while(eed) {
+                       nexted= eed->next;
+                       if(eed->f2==3 && eed->f1==1) {
+                               remedge(em, eed);
+                               free_editedge(em, eed);
+                       }
+                       eed= nexted;
+               }
+       }
+       /* duplicate faces, if necessary remove old ones  */
+       efa= em->faces.first;
+       while(efa) {
+               nextvl= efa->next;
+               if(efa->f1 & 1) {
+               
+                       v1 = efa->v1->tmp.v;
+                       v2 = efa->v2->tmp.v;
+                       v3 = efa->v3->tmp.v;
+                       if(efa->v4) 
+                               v4 = efa->v4->tmp.v; 
+                       else
+                               v4= 0;
+
+                       /* hmm .. not sure about edges here */
+                       if(del_old==0)  // if we keep old, we flip normal
+                               efa2= addfacelist(em, v3, v2, v1, v4, efa, efa); 
+                       else
+                               efa2= addfacelist(em, v1, v2, v3, v4, efa, efa);
+                       
+                       /* for transform */
+                       add_normal_aligned(nor, efa->n);
+
+                       if(del_old) {
+                               BLI_remlink(&em->faces, efa);
+                               free_editface(em, efa);
+                       }
+               }
+               efa= nextvl;
+       }
+       
+       Normalize(nor); // for grab
+       
+       /* for all vertices with eve->tmp.v!=0 
+               if eve->f1==1: make edge
+               if flag!=128 : if del_old==1: remove
+       */
+       eve= em->verts.last;
+       while(eve) {
+               nextve= eve->prev;
+               if(eve->tmp.v) {
+                       if(eve->f1==1) addedgelist(em, eve, eve->tmp.v, NULL);
+                       else if( (eve->f & 128)==0) {
+                               if(del_old) {
+                                       BLI_remlink(&em->verts,eve);
+                                       free_editvert(em, eve);
+                                       eve= NULL;
+                               }
+                       }
+               }
+               if(eve) {
+                       eve->f &= ~128;
+               }
+               eve= nextve;
+       }
+       // since its vertex select mode now, it also deselects higher order
+       EM_selectmode_flush(em);
+
+       if(nor[0]==0.0 && nor[1]==0.0 && nor[2]==0.0) return 'g'; // g is grab, for correct undo print
+       return 'n';
+}
+
+/* generic extrude */
+short extrudeflag(EditMesh *em, short flag, float *nor)
+{
+       if(em->selectmode & SCE_SELECT_VERTEX)
+               return extrudeflag_vert(em, flag, nor);
+       else 
+               return extrudeflag_edge(em, flag, nor);
+               
+}
+
+void rotateflag(EditMesh *em, short flag, float *cent, float rotmat[][3])
+{
+       /* all verts with (flag & 'flag') rotate */
+       EditVert *eve;
+
+       eve= em->verts.first;
+       while(eve) {
+               if(eve->f & flag) {
+                       eve->co[0]-=cent[0];
+                       eve->co[1]-=cent[1];
+                       eve->co[2]-=cent[2];
+                       Mat3MulVecfl(rotmat,eve->co);
+                       eve->co[0]+=cent[0];
+                       eve->co[1]+=cent[1];
+                       eve->co[2]+=cent[2];
+               }
+               eve= eve->next;
+       }
+}
+
+void translateflag(EditMesh *em, short flag, float *vec)
+{
+       /* all verts with (flag & 'flag') translate */
+       EditVert *eve;
+
+       eve= em->verts.first;
+       while(eve) {
+   &