svn merge ^/trunk/blender -r43461:43472
authorCampbell Barton <ideasman42@gmail.com>
Tue, 17 Jan 2012 21:08:25 +0000 (21:08 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 17 Jan 2012 21:08:25 +0000 (21:08 +0000)
26 files changed:
1  2 
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenkernel/BKE_mesh.h
source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/intern/math_vector_inline.c
source/blender/blenloader/intern/readfile.c
source/blender/blenloader/intern/writefile.c
source/blender/editors/include/ED_mesh.h
source/blender/editors/include/ED_uvedit.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/mesh/bmeshutils.c
source/blender/editors/object/object_edit.c
source/blender/editors/sculpt_paint/CMakeLists.txt
source/blender/editors/sculpt_paint/SConscript
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/sculpt_uv.c
source/blender/editors/space_image/space_image.c
source/blender/editors/uvedit/CMakeLists.txt
source/blender/editors/uvedit/uvedit_draw.c
source/blender/editors/uvedit/uvedit_intern.h
source/blender/editors/uvedit/uvedit_ops.c
source/blender/editors/uvedit/uvedit_parametrizer.c
source/blender/editors/uvedit/uvedit_smart_stitch.c
source/blender/editors/uvedit/uvedit_unwrap_ops.c
source/blender/makesrna/RNA_access.h
source/blender/makesrna/intern/rna_scene.c
source/blenderplayer/bad_level_call_stubs/stubs.c

@@@ -180,7 -129,40 +183,39 @@@ typedef struct UvMapVert 
        unsigned char tfindex, separate, flag;
  } UvMapVert;
  
 -      struct EditFace *face;
+ typedef struct UvElementMap {
+       /* address UvElements by their vertex */
+       struct UvElement **vert;
+       /* UvElement Store */
+       struct UvElement *buf;
+       /* Total number of UVs in the layer. Useful to know */
+       int totalUVs;
+       /* Number of Islands in the mesh */
+       int totalIslands;
+       /* Stores the starting index in buf where each island begins */
+       int *islandIndices;
+ } UvElementMap;
+ typedef struct UvElement {
+       /* Next UvElement corresponding to same vertex */
+       struct UvElement *next;
+       /* Face the element belongs to */
 -
 -UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit);
++      struct BMFace *face;
+       /* Index in the editFace of the uv */
+       unsigned char tfindex;
+       /* Whether this element is the first of coincident elements */
+       unsigned char separate;
+       /* general use flag */
+       unsigned char flag;
+       /* If generating element map with island sorting, this stores the island index */
+       unsigned short island;
+ } UvElement;
+ /* invalid island index is max short. If any one has the patience
+  * to make that many islands, he can bite me :p */
+ #define INVALID_ISLAND 0xFFFF
 +UvVertMap *make_uv_vert_map(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, unsigned int totpoly, unsigned int totvert, int selected, float *limit);
  UvMapVert *get_uv_map_vert(UvVertMap *vmap, unsigned int v);
  void free_uv_vert_map(UvVertMap *vmap);
  
@@@ -94,138 -82,110 +94,144 @@@ struct ToolSettings
  #define B_JOINTRIA_VCOL               0X400
  #define B_JOINTRIA_SHARP      0X800
  #define B_JOINTRIA_MAT                0X1000
 -#define B_FRACTAL                     0x2000
 -#define B_SPHERE                      0x4000
 -
 -/* meshtools.c */
 +#define B_FRACTAL             0x2000
 +#define B_SPHERE              0x4000
  
 -intptr_t   mesh_octree_table(struct Object *ob, struct EditMesh *em, float *co, char mode);
 -int        mesh_mirrtopo_table(struct Object *ob, char mode);
 +float *bm_get_cd_float(struct CustomData *cdata, void *data, int type);
  
 -struct EditVert   *editmesh_get_x_mirror_vert(struct Object *ob, struct EditMesh *em, struct EditVert *eve, float *co, int index);
 -int                   mesh_get_x_mirror_vert(struct Object *ob, int index);
 -int                   *mesh_get_x_mirror_faces(struct Object *ob, struct EditMesh *em);
 +intptr_t    mesh_octree_table(struct Object *ob, struct BMEditMesh *em, float *co, char mode);
 +int         mesh_mirrtopo_table(struct Object *ob, char mode);
  
 -int                   join_mesh_exec(struct bContext *C, struct wmOperator *op);
 -int                   join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
 -
 -/* mesh_ops.c */
 -void          ED_operatortypes_mesh(void);
 -void          ED_operatormacros_mesh(void);
 -void          ED_keymap_mesh(struct wmKeyConfig *keyconf);
 +/* bmeshutils.c */
  
 +/*
 + [note: I've decided to use ideasman's code for non-editmode stuff, but since
 +  it has a big "not for editmode!" disclaimer, I'm going to keep what I have here
 +  - joeedh]
 +  
 + x-mirror editing api.  usage:
 +  
 +  EDBM_CacheMirrorVerts(em);
 +  ...
 +  ...
 +  BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
 +     mirrorv = EDBM_GetMirrorVert(em, v);
 +  }
 +  ...
 +  ...
 +  EDBM_EndMirrorCache(em);
 + 
 +  note: why do we only allow x axis mirror editing?
 +  */
 +void EDBM_CacheMirrorVerts(struct BMEditMesh *em, const short use_select); /* note, replaces EM_cache_x_mirror_vert in trunk */
 +
 +/*retrieves mirrored cache vert, or NULL if there isn't one.
 +  note: calling this without ensuring the mirror cache state
 +  is bad.*/
 +struct BMVert *EDBM_GetMirrorVert(struct BMEditMesh *em, struct BMVert *v);
 +void           EDBM_ClearMirrorVert(struct BMEditMesh *em, struct BMVert *v);
 +void EDBM_EndMirrorCache(struct BMEditMesh *em);
 +void EDBM_ApplyMirrorCache(struct BMEditMesh *em, const int sel_from, const int sel_to);
 +
 +void EDBM_RecalcNormals(struct BMEditMesh *em);
 +
 +void EDBM_MakeEditBMesh(struct ToolSettings *ts, struct Scene *scene, struct Object *ob);
 +void EDBM_FreeEditBMesh(struct BMEditMesh *tm);
 +void EDBM_LoadEditBMesh(struct Scene *scene, struct Object *ob);
 +
 +void EDBM_init_index_arrays(struct BMEditMesh *em, int forvert, int foredge, int forface);
 +void EDBM_free_index_arrays(struct BMEditMesh *em);
 +struct BMVert *EDBM_get_vert_for_index(struct BMEditMesh *em, int index);
 +struct BMEdge *EDBM_get_edge_for_index(struct BMEditMesh *em, int index);
 +struct BMFace *EDBM_get_face_for_index(struct BMEditMesh *em, int index);
 +
 +int EDBM_CallAndSelectOpf(struct BMEditMesh *em, struct wmOperator *op, 
 +                                                const char *selectslot, const char *fmt, ...);
 +
 +/*flushes based on the current select mode.  if in vertex select mode,
 +  verts select/deselect edges and faces, if in edge select mode,
 +  edges select/deselect faces and vertices, and in face select mode faces select/deselect
 +  edges and vertices.*/
 +void EDBM_selectmode_flush(struct BMEditMesh *em);
 +
 +int EDBM_get_actSelection(struct BMEditMesh *em, struct BMEditSelection *ese);
 +
 +/*exactly the same as EDBM_selectmode_flush, but you pass in the selectmode
 +  instead of using the current one*/
 +void EDBM_select_flush(struct BMEditMesh *em, int selectmode);
 +void EDBM_deselect_flush(struct BMEditMesh *em);
 +
 +void EDBM_selectmode_set(struct BMEditMesh *em);
 +void EDBM_convertsel(struct BMEditMesh *em, short oldmode, short selectmode);
 +void          undo_push_mesh(struct bContext *C, const char *name);
  
 -/* editmesh.c */
 -void          make_editMesh(struct Scene *scene, struct Object *ob);
 -void          load_editMesh(struct Scene *scene, struct Object *ob);
 -void          remake_editMesh(struct Scene *scene, struct Object *ob);
 -void          free_editMesh(struct EditMesh *em);
 +void EDBM_editselection_center(struct BMEditMesh *em, float *center, struct BMEditSelection *ese);
 +void EDBM_editselection_plane(struct BMEditMesh *em, float *plane, struct BMEditSelection *ese);
 +void EDBM_editselection_normal(float *normal, struct BMEditSelection *ese);
 +int EDBM_vertColorCheck(struct BMEditMesh *em);
 +void EDBM_validate_selections(struct BMEditMesh *em);
  
 -void          recalc_editnormals(struct EditMesh *em);
 +void EDBM_hide_mesh(struct BMEditMesh *em, int swap);
 +void EDBM_reveal_mesh(struct BMEditMesh *em);
  
 -void          EM_init_index_arrays(struct EditMesh *em, int forVert, int forEdge, int forFace);
 -void          EM_free_index_arrays(void);
 -struct EditVert       *EM_get_vert_for_index(int index);
 -struct EditEdge       *EM_get_edge_for_index(int index);
 -struct EditFace       *EM_get_face_for_index(int index);
 -int                   EM_texFaceCheck(struct EditMesh *em);
 -int                   EM_vertColorCheck(struct EditMesh *em);
 +int                   EDBM_check_backbuf(unsigned int index);
 +int                   EDBM_mask_init_backbuf_border(struct ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax);
 +void          EDBM_free_backbuf(void);
 +int                   EDBM_init_backbuf_border(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
 +int                   EDBM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short rads);
  
 -void          undo_push_mesh(struct bContext *C, const char *name);
 +void EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const short select);
  
 -void          paintvert_flush_flags(struct Object *ob);
 -void          paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags);
++struct UvElementMap *EDBM_make_uv_element_map(struct BMEditMesh *em, int selected, int doIslands);
++void          EDBM_free_uv_element_map(struct UvElementMap *vmap);
 -/* editmesh_lib.c */
++void          EDBM_add_data_layer(struct BMEditMesh *em, struct CustomData *data, int type, const char *name);
++void          EDBM_free_data_layer(struct BMEditMesh *em, struct CustomData *data, int type);
 -struct EditFace       *EM_get_actFace(struct EditMesh *em, int sloppy);
 -void             EM_set_actFace(struct EditMesh *em, struct EditFace *efa);
 -float            EM_face_area(struct EditFace *efa);
 +void EDBM_select_swap(struct BMEditMesh *em); /* exported for UV */
  
 -void          EM_select_edge(struct EditEdge *eed, int sel);
 -void          EM_select_face(struct EditFace *efa, int sel);
 -void          EM_select_face_fgon(struct EditMesh *em, struct EditFace *efa, int val);
 -void          EM_select_swap(struct EditMesh *em);
 -void          EM_toggle_select_all(struct EditMesh *em);
 -void          EM_select_all(struct EditMesh *em);
 -void          EM_deselect_all(struct EditMesh *em);
 -void          EM_selectmode_flush(struct EditMesh *em);
 -void          EM_deselect_flush(struct EditMesh *em);
 -void          EM_selectmode_set(struct EditMesh *em);
 -void          EM_select_flush(struct EditMesh *em);
 -void          EM_convertsel(struct EditMesh *em, short oldmode, short selectmode);
 -void          EM_validate_selections(struct EditMesh *em);
 -void          EM_selectmode_to_scene(struct Scene *scene, struct Object *obedit);
 +int EDBM_texFaceCheck(struct BMEditMesh *em);
 +struct MTexPoly *EDBM_get_active_mtexpoly(struct BMEditMesh *em, struct BMFace **act_efa, int sloppy);
  
 -                      /* exported to transform */
 -int                   EM_get_actSelection(struct EditMesh *em, struct EditSelection *ese);
 -void          EM_editselection_normal(float *normal, struct EditSelection *ese);
 -void          EM_editselection_plane(float *plane, struct EditSelection *ese);
 -void          EM_editselection_center(float *center, struct EditSelection *ese);                      
 +void EDBM_free_uv_vert_map(struct UvVertMap *vmap);
 +struct UvMapVert *EDBM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v);
 +struct UvVertMap *EDBM_make_uv_vert_map(struct BMEditMesh *em, int selected, int do_face_idx_array, float *limit);
 +void          EM_add_data_layer(struct BMEditMesh *em, struct CustomData *data, int type, const char *name);
 +void          EM_free_data_layer(struct BMEditMesh *em, struct CustomData *data, int type);
  
 -struct UvVertMap *EM_make_uv_vert_map(struct EditMesh *em, int selected, int do_face_idx_array, float *limit);
 -struct UvMapVert *EM_get_uv_map_vert(struct UvVertMap *vmap, unsigned int v);
 -void              EM_free_uv_vert_map(struct UvVertMap *vmap);
 +void EDBM_toggle_select_all(struct BMEditMesh *em);
 +void EDBM_set_flag_all(struct BMEditMesh *em, const char hflag);
 +void EDBM_clear_flag_all(struct BMEditMesh *em, const char hflag);
 +void EDBM_automerge(struct Scene *scene, struct Object *ob, int update);
  
 -struct UvElementMap *EM_make_uv_element_map(struct EditMesh *em, int selected, int doIslands);
 -void          EM_free_uv_element_map(struct UvElementMap *vmap);
 +/* editmesh_mods.c */
 +extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs;
  
 -void          EM_add_data_layer(struct EditMesh *em, struct CustomData *data, int type, const char *name);
 -void          EM_free_data_layer(struct EditMesh *em, struct CustomData *data, int type);
 +int                   mouse_mesh(struct bContext *C, const int mval[2], short extend);
  
 -void          EM_make_hq_normals(struct EditMesh *em);
 -void          EM_solidify(struct EditMesh *em, float dist);
 +struct BMVert   *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, float *co, int index);
 +int                   mesh_get_x_mirror_vert(struct Object *ob, int index);
 +int                   *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em);
  
 -int                   EM_deselect_nth(struct EditMesh *em, int nth);
 +int                   join_mesh_exec(struct bContext *C, struct wmOperator *op);
 +int                   join_mesh_shapes_exec(struct bContext *C, struct wmOperator *op);
  
 -void EM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct Object *obedit, struct EditMesh *em);
 +/* mesh_ops.c */
 +void          ED_operatortypes_mesh(void);
 +void          ED_operatormacros_mesh(void);
 +void          ED_keymap_mesh(struct wmKeyConfig *keyconf);
  
 -/* editmesh_mods.c */
 -extern unsigned int em_vertoffs, em_solidoffs, em_wireoffs;
  
 -void          EM_cache_x_mirror_vert(struct Object *ob, struct EditMesh *em);
 -int                   mouse_mesh(struct bContext *C, const int mval[2], short extend);
 -int                   EM_check_backbuf(unsigned int index);
 -int                   EM_mask_init_backbuf_border(struct ViewContext *vc, int mcords[][2], short tot, short xmin, short ymin, short xmax, short ymax);
 -void          EM_free_backbuf(void);
 -int                   EM_init_backbuf_border(struct ViewContext *vc, short xmin, short ymin, short xmax, short ymax);
 -int                   EM_init_backbuf_circle(struct ViewContext *vc, short xs, short ys, short rads);
 +/* editmesh.c */
  
 -void          EM_hide_mesh(struct EditMesh *em, int swap);
 -void          EM_reveal_mesh(struct EditMesh *em);
 +void          ED_spacetypes_init(void);
 +void          ED_keymap_mesh(struct wmKeyConfig *keyconf);
  
 -void          EM_select_by_material(struct EditMesh *em, int index);
 -void          EM_deselect_by_material(struct EditMesh *em, int index); 
 +/* bmesh_mods.c */
 +extern unsigned int bm_vertoffs, bm_solidoffs, bm_wireoffs;
  
 -void          EM_automerge(struct Scene *scene, struct Object *obedit, int update);
 +/* bmesh_tools.c (could be moved) */
 +void EMBM_project_snap_verts(struct bContext *C, struct ARegion *ar, struct Object *obedit, struct BMEditMesh *em);
  
  /* editface.c */
  void paintface_flush_flags(struct Object *ob);
index 6defe21,0000000..1d3851b
mode 100644,000000..100644
--- /dev/null
@@@ -1,946 -1,0 +1,1179 @@@
 +/*
 + * ***** 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): Joseph Eagar
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +#include <stdlib.h>
 +#include <stdarg.h>
 +#include <string.h>
 +#include <math.h>
 +#include <float.h>
 +
 +#include "MEM_guardedalloc.h"
 +#include "PIL_time.h"
 +
 +#include "BLO_sys_types.h" // for intptr_t support
 +
 +#include "DNA_mesh_types.h"
 +#include "DNA_material_types.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_modifier_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_scene_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_view3d_types.h"
 +#include "DNA_key_types.h"
 +
 +#include "RNA_types.h"
 +#include "RNA_define.h"
 +#include "RNA_access.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_math.h"
 +#include "BLI_editVert.h"
 +#include "BLI_rand.h"
 +#include "BLI_ghash.h"
 +#include "BLI_linklist.h"
 +#include "BLI_heap.h"
 +#include "BLI_array.h"
 +
 +#include "BKE_context.h"
 +#include "BKE_customdata.h"
 +#include "BKE_depsgraph.h"
 +#include "BKE_global.h"
 +#include "BKE_library.h"
 +#include "BKE_key.h"
 +#include "BKE_mesh.h"
 +#include "BKE_object.h"
 +#include "BKE_bmesh.h"
 +#include "BKE_report.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "bmesh.h"
 +
 +#include "BIF_gl.h"
 +#include "BIF_glutil.h"
 +
 +#include "WM_api.h"
 +#include "WM_types.h"
 +
 +#include "ED_mesh.h"
 +#include "ED_view3d.h"
 +#include "ED_util.h"
 +#include "ED_screen.h"
 +
 +#include "UI_interface.h"
 +
 +#include "editbmesh_bvh.h"
 +#include "mesh_intern.h"
 +
 +void EDBM_RecalcNormals(BMEditMesh *em)
 +{
 +      BM_Compute_Normals(em->bm);
 +}
 +
 +void EDBM_ClearMesh(BMEditMesh *em)
 +{
 +      /*clear bmesh*/
 +      BM_Clear_Mesh(em->bm);
 +      
 +      /*free derived meshes*/
 +      if (em->derivedCage) {
 +              em->derivedCage->needsFree = 1;
 +              em->derivedCage->release(em->derivedCage);
 +      }
 +      if (em->derivedFinal && em->derivedFinal != em->derivedCage) {
 +              em->derivedFinal->needsFree = 1;
 +              em->derivedFinal->release(em->derivedFinal);
 +      }
 +      
 +      em->derivedCage = em->derivedFinal = NULL;
 +      
 +      /*free tesselation data*/
 +      em->tottri = 0;
 +      if (em->looptris) 
 +              MEM_freeN(em->looptris);
 +}
 +
 +void EDBM_stats_update(BMEditMesh *em)
 +{
 +      BMIter iter;
 +      BMHeader *ele;
 +      const char itypes[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
 +      int *tots[3];
 +      int i;
 +
 +      tots[0] = &em->bm->totvertsel;
 +      tots[1] = &em->bm->totedgesel;
 +      tots[2] = &em->bm->totfacesel;
 +      
 +      em->bm->totvertsel = em->bm->totedgesel = em->bm->totfacesel = 0;
 +
 +      for (i=0; i<3; i++) {
 +              ele = BMIter_New(&iter, em->bm, itypes[i], NULL);
 +              for ( ; ele; ele=BMIter_Step(&iter)) {
 +                      if (BM_TestHFlag(ele, BM_SELECT)) {
 +                              (*tots[i])++;
 +                      }
 +              }
 +      }
 +}
 +
 +int EDBM_InitOpf(BMEditMesh *em, BMOperator *bmop, wmOperator *op, const char *fmt, ...)
 +{
 +      BMesh *bm = em->bm;
 +      va_list list;
 +
 +      va_start(list, fmt);
 +
 +      if (!BMO_VInitOpf(bm, bmop, fmt, list)) {
 +              BKE_report(op->reports, RPT_ERROR,
 +                         "Parse error in EDBM_CallOpf");
 +              va_end(list);
 +              return 0;
 +      }
 +      
 +      if (!em->emcopy)
 +              em->emcopy = BMEdit_Copy(em);
 +      em->emcopyusers++;
 +
 +      va_end(list);
 +
 +      return 1;
 +}
 +
 +
 +/*returns 0 on error, 1 on success.  executes and finishes a bmesh operator*/
 +int EDBM_FinishOp(BMEditMesh *em, BMOperator *bmop, wmOperator *op, int report)
 +{
 +      const char *errmsg;
 +      
 +      BMO_Finish_Op(em->bm, bmop);
 +
 +      if (BMO_GetError(em->bm, &errmsg, NULL)) {
 +              BMEditMesh *emcopy = em->emcopy;
 +
 +              if (report) BKE_report(op->reports, RPT_ERROR, errmsg);
 +
 +              BMEdit_Free(em);
 +              *em = *emcopy;
 +              BMEdit_RecalcTesselation(em);
 +
 +              MEM_freeN(emcopy);
 +              em->emcopyusers = 0;
 +              em->emcopy = NULL;
 +              return 0;
 +      } else {
 +              em->emcopyusers--;
 +              if (em->emcopyusers < 0) {
 +                      printf("warning: em->emcopyusers was less then zero.\n");
 +              }
 +
 +              if (em->emcopyusers <= 0) {
 +                      BMEdit_Free(em->emcopy);
 +                      MEM_freeN(em->emcopy);
 +                      em->emcopy = NULL;
 +              }
 +      }
 +
 +      return 1;
 +}
 +
 +int EDBM_CallOpf(BMEditMesh *em, wmOperator *op, const char *fmt, ...)
 +{
 +      BMesh *bm = em->bm;
 +      BMOperator bmop;
 +      va_list list;
 +
 +      va_start(list, fmt);
 +
 +      if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
 +              BKE_report(op->reports, RPT_ERROR,
 +                         "Parse error in EDBM_CallOpf");
 +              va_end(list);
 +              return 0;
 +      }
 +
 +      if (!em->emcopy)
 +              em->emcopy = BMEdit_Copy(em);
 +      em->emcopyusers++;
 +
 +      BMO_Exec_Op(bm, &bmop);
 +
 +      va_end(list);
 +      return EDBM_FinishOp(em, &bmop, op, 1);
 +}
 +
 +int EDBM_CallAndSelectOpf(BMEditMesh *em, wmOperator *op, const char *selectslot, const char *fmt, ...)
 +{
 +      BMesh *bm = em->bm;
 +      BMOperator bmop;
 +      va_list list;
 +
 +      va_start(list, fmt);
 +
 +      if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
 +              BKE_report(op->reports, RPT_ERROR,
 +                         "Parse error in EDBM_CallOpf");
 +              va_end(list);
 +              return 0;
 +      }
 +
 +      if (!em->emcopy)
 +              em->emcopy = BMEdit_Copy(em);
 +      em->emcopyusers++;
 +
 +      BMO_Exec_Op(bm, &bmop);
 +      BMO_HeaderFlag_Buffer(em->bm, &bmop, selectslot, BM_SELECT, BM_ALL);
 +
 +      va_end(list);
 +      return EDBM_FinishOp(em, &bmop, op, 1);
 +}
 +
 +int EDBM_CallOpfSilent(BMEditMesh *em, const char *fmt, ...)
 +{
 +      BMesh *bm = em->bm;
 +      BMOperator bmop;
 +      va_list list;
 +
 +      va_start(list, fmt);
 +
 +      if (!BMO_VInitOpf(bm, &bmop, fmt, list)) {
 +              va_end(list);
 +              return 0;
 +      }
 +
 +      if (!em->emcopy)
 +              em->emcopy = BMEdit_Copy(em);
 +      em->emcopyusers++;
 +
 +      BMO_Exec_Op(bm, &bmop);
 +
 +      va_end(list);
 +      return EDBM_FinishOp(em, &bmop, NULL, 0);
 +}
 +
 +void EDBM_selectmode_to_scene(bContext *C)
 +{
 +      Scene *scene = CTX_data_scene(C);
 +      Object *obedit = CTX_data_edit_object(C);
 +      BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
 +
 +      if (!em)
 +              return;
 +
 +      scene->toolsettings->selectmode = em->selectmode;
 +
 +      /* Request redraw of header buttons (to show new select mode) */
 +      WM_event_add_notifier(C, NC_SCENE|ND_TOOLSETTINGS, scene);
 +}
 +
 +void EDBM_MakeEditBMesh(ToolSettings *ts, Scene *UNUSED(scene), Object *ob)
 +{
 +      Mesh *me = ob->data;
 +      BMesh *bm;
 +
 +      if (!me->mpoly && me->totface) {
 +              fprintf(stderr, "%s: bmesh conversion issue! may lose lots of geometry! (bmesh internal error)\n", __func__);
 +              
 +              /*BMESH_TODO need to write smarter code here*/
 +              bm = BKE_mesh_to_bmesh(me, ob);
 +      } else {
 +              bm = BKE_mesh_to_bmesh(me, ob);
 +      }
 +
 +      if (me->edit_btmesh) {
 +              /* this happens when switching shape keys */
 +              BMEdit_Free(me->edit_btmesh);
 +              MEM_freeN(me->edit_btmesh);
 +      }
 +
 +      me->edit_btmesh = BMEdit_Create(bm);
 +      me->edit_btmesh->selectmode= me->edit_btmesh->bm->selectmode= ts->selectmode;
 +      me->edit_btmesh->me = me;
 +      me->edit_btmesh->ob = ob;
 +}
 +
 +void EDBM_LoadEditBMesh(Scene *scene, Object *ob)
 +{
 +      Mesh *me = ob->data;
 +      BMesh *bm = me->edit_btmesh->bm;
 +
 +      BMO_CallOpf(bm, "object_load_bmesh scene=%p object=%p", scene, ob);
 +}
 +
 +void EDBM_FreeEditBMesh(BMEditMesh *tm)
 +{
 +      BMEdit_Free(tm);
 +}
 +
 +void EDBM_init_index_arrays(BMEditMesh *tm, int forvert, int foredge, int forface)
 +{
 +      EDBM_free_index_arrays(tm);
 +
 +      if (forvert) {
 +              BMIter iter;
 +              BMVert *ele;
 +              int i=0;
 +              
 +              tm->vert_index = MEM_mallocN(sizeof(void**)*tm->bm->totvert, "tm->vert_index");
 +
 +              ele = BMIter_New(&iter, tm->bm, BM_VERTS_OF_MESH, NULL);
 +              for ( ; ele; ele=BMIter_Step(&iter)) {
 +                      tm->vert_index[i++] = ele;
 +              }
 +      }
 +
 +      if (foredge) {
 +              BMIter iter;
 +              BMEdge *ele;
 +              int i=0;
 +              
 +              tm->edge_index = MEM_mallocN(sizeof(void**)*tm->bm->totedge, "tm->edge_index");
 +
 +              ele = BMIter_New(&iter, tm->bm, BM_EDGES_OF_MESH, NULL);
 +              for ( ; ele; ele=BMIter_Step(&iter)) {
 +                      tm->edge_index[i++] = ele;
 +              }
 +      }
 +
 +      if (forface) {
 +              BMIter iter;
 +              BMFace *ele;
 +              int i=0;
 +              
 +              tm->face_index = MEM_mallocN(sizeof(void**)*tm->bm->totface, "tm->face_index");
 +
 +              ele = BMIter_New(&iter, tm->bm, BM_FACES_OF_MESH, NULL);
 +              for ( ; ele; ele=BMIter_Step(&iter)) {
 +                      tm->face_index[i++] = ele;
 +              }
 +      }
 +}
 +
 +void EDBM_free_index_arrays(BMEditMesh *tm)
 +{
 +      if (tm->vert_index) {
 +              MEM_freeN(tm->vert_index);
 +              tm->vert_index = NULL;
 +      }
 +
 +      if (tm->edge_index) {
 +              MEM_freeN(tm->edge_index);
 +              tm->edge_index = NULL;
 +      }
 +
 +      if (tm->face_index) {
 +              MEM_freeN(tm->face_index);
 +              tm->face_index = NULL;
 +      }
 +}
 +
 +BMVert *EDBM_get_vert_for_index(BMEditMesh *tm, int index)
 +{
 +      return tm->vert_index && index < tm->bm->totvert ?tm->vert_index[index]:NULL;
 +}
 +
 +BMEdge *EDBM_get_edge_for_index(BMEditMesh *tm, int index)
 +{
 +      return tm->edge_index && index < tm->bm->totedge ?tm->edge_index[index]:NULL;
 +}
 +
 +BMFace *EDBM_get_face_for_index(BMEditMesh *tm, int index)
 +{
 +      return (tm->face_index && index<tm->bm->totface && index>=0) ? tm->face_index[index] : NULL;
 +}
 +
 +void EDBM_select_flush(BMEditMesh *em, int selectmode)
 +{
 +      em->bm->selectmode = selectmode;
 +      BM_SelectMode_Flush(em->bm);
 +      em->bm->selectmode = em->selectmode;
 +}
 +
 +/*BMESH_TODO*/
 +void EDBM_deselect_flush(BMEditMesh *UNUSED(em))
 +{
 +}
 +
 +
 +void EDBM_selectmode_flush(BMEditMesh *em)
 +{
 +      em->bm->selectmode = em->selectmode;
 +      BM_SelectMode_Flush(em->bm);
 +}
 +
 +/*EDBM_select_[more/less] are api functions, I think the uv editor
 +  uses them? though the select more/less ops themselves do not.*/
 +static void EDBM_select_more(BMEditMesh *em)
 +{
 +      BMOperator bmop;
 +      int usefaces = em->selectmode > SCE_SELECT_EDGE;
 +
 +      BMO_InitOpf(em->bm, &bmop, 
 +                  "regionextend geom=%hvef constrict=%d usefaces=%d",
 +                  BM_SELECT, 0, usefaces);
 +      BMO_Exec_Op(em->bm, &bmop);
 +      BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
 +      BMO_Finish_Op(em->bm, &bmop);
 +
 +      EDBM_selectmode_flush(em);
 +}
 +
 +static void EDBM_select_less(BMEditMesh *em)
 +{
 +      BMOperator bmop;
 +      int usefaces = em->selectmode > SCE_SELECT_EDGE;
 +
 +      BMO_InitOpf(em->bm, &bmop, 
 +                  "regionextend geom=%hvef constrict=%d usefaces=%d",
 +                  BM_SELECT, 0, usefaces);
 +      BMO_Exec_Op(em->bm, &bmop);
 +      BMO_HeaderFlag_Buffer(em->bm, &bmop, "geomout", BM_SELECT, BM_ALL);
 +      BMO_Finish_Op(em->bm, &bmop);
 +
 +      EDBM_selectmode_flush(em);
 +}
 +
 +int EDBM_get_actSelection(BMEditMesh *em, BMEditSelection *ese)
 +{
 +      BMEditSelection *ese_last = em->bm->selected.last;
 +      BMFace *efa = BM_get_actFace(em->bm, 0);
 +
 +      ese->next = ese->prev = NULL;
 +      
 +      if (ese_last) {
 +              if (ese_last->htype == BM_FACE) { /* 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->htype = BM_FACE;
 +              }
 +              else {
 +                      ese->data = ese_last->data;
 +                      ese->htype = ese_last->htype;
 +              }
 +      }
 +      else if (efa) { /* no */
 +              ese->data= (void *)efa;
 +              ese->htype= BM_FACE;
 +      }
 +      else {
 +              ese->data = NULL;
 +              return 0;
 +      }
 +      return 1;
 +}
 +
 +void EDBM_clear_flag_all(BMEditMesh *em, const char hflag)
 +{
 +      int types[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
 +      BMIter iter;
 +      BMHeader *ele;
 +      int i;
 +
 +      if (hflag & BM_SELECT)
 +              BM_clear_selection_history(em->bm);
 +
 +      for (i=0; i<3; i++) {
 +              BM_ITER(ele, &iter, em->bm, types[i], NULL) {
 +                      if (hflag & BM_SELECT) BM_Select(em->bm, ele, FALSE);
 +                      BM_ClearHFlag(ele, hflag);
 +              }
 +      }
 +}
 +
 +void EDBM_set_flag_all(BMEditMesh *em, const char hflag)
 +{
 +      const char itypes[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
 +      BMIter iter;
 +      BMHeader *ele;
 +      int i;
 +
 +      for (i=0; i<3; i++) {
 +              ele= BMIter_New(&iter, em->bm, itypes[i], NULL);
 +              for ( ; ele; ele=BMIter_Step(&iter)) {
 +                      if (hflag & BM_SELECT) {
 +                              BM_Select(em->bm, ele, TRUE);
 +                      }
 +                      else {
 +                              BM_SetHFlag(ele, hflag);
 +                      }
 +              }
 +      }
 +}
 +
 +/**************-------------- Undo ------------*****************/
 +
 +/* for callbacks */
 +
 +static void *getEditMesh(bContext *C)
 +{
 +      Object *obedit= CTX_data_edit_object(C);
 +      if(obedit && obedit->type==OB_MESH) {
 +              Mesh *me= obedit->data;
 +              return me->edit_btmesh;
 +      }
 +      return NULL;
 +}
 +
 +typedef struct undomesh {
 +      Mesh me;
 +      int selectmode;
 +      char obname[64];
 +} undomesh;
 +
 +/*undo simply makes copies of a bmesh*/
 +static void *editbtMesh_to_undoMesh(void *emv, void *obdata)
 +{
 +      BMEditMesh *em = emv;
 +      Mesh *obme = obdata;
 +      
 +      undomesh *me = MEM_callocN(sizeof(undomesh), "undo Mesh");
 +      strcpy(me->obname, em->bm->ob->id.name+2);
 +      
 +      /*make sure shape keys work*/
 +      me->me.key = obme->key ? copy_key_nolib(obme->key) : NULL;
 +
 +#ifdef BMESH_EM_UNDO_RECALC_TESSFACE_WORKAROUND
 +
 +      /*we recalc the tesselation here, to avoid seeding calls to
 +        BMEdit_RecalcTesselation throughout the code.*/
 +      BMEdit_RecalcTesselation(em);
 +
 +#endif
 +
 +      BMO_CallOpf(em->bm, "bmesh_to_mesh mesh=%p notesselation=%i", me, 1);
 +      me->selectmode = em->selectmode;
 +
 +      return me;
 +}
 +
 +static void undoMesh_to_editbtMesh(void *umv, void *emv, void *UNUSED(obdata))
 +{
 +      BMEditMesh *em = emv, *em2;
 +      Object *ob;
 +      undomesh *me = umv;
 +      BMesh *bm;
 +      int allocsize[4] = {512, 512, 2048, 512};
 +      
 +      ob = (Object*)find_id("OB", me->obname);
 +      ob->shapenr = em->bm->shapenr;
 +
 +      BMEdit_Free(em);
 +
 +      bm = BM_Make_Mesh(ob, allocsize);
 +      BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", me, ob, 0);
 +
 +      em2 = BMEdit_Create(bm);
 +      *em = *em2;
 +      
 +      em->selectmode = me->selectmode;
 +
 +      MEM_freeN(em2);
 +}
 +
 +
 +static void free_undo(void *umv)
 +{
 +      if (((Mesh*)umv)->key)
 +      {
 +              free_key(((Mesh*)umv)->key);
 +              MEM_freeN(((Mesh*)umv)->key);
 +      }
 +      
 +      free_mesh(umv, 0);
 +      MEM_freeN(umv);
 +}
 +
 +/* and this is all the undo system needs to know */
 +void undo_push_mesh(bContext *C, const char *name)
 +{
 +      undo_editmode_push(C, name, getEditMesh, free_undo, undoMesh_to_editbtMesh, editbtMesh_to_undoMesh, NULL);
 +}
 +
 +/*write comment here*/
 +UvVertMap *EDBM_make_uv_vert_map(BMEditMesh *em, int selected, int do_face_idx_array, float *limit)
 +{
 +      BMVert *ev;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      /* vars from original func */
 +      UvVertMap *vmap;
 +      UvMapVert *buf;
 +      /* MTexPoly *tf; */ /* UNUSED */
 +      MLoopUV *luv;
 +      unsigned int a;
 +      int totverts, i, totuv;
 +      
 +      if (do_face_idx_array)
 +              EDBM_init_index_arrays(em, 0, 0, 1);
 +
 +      BM_ElemIndex_Ensure(em->bm, BM_VERT);
 +      
 +      totverts= em->bm->totvert;
 +      totuv = 0;
 +
 +      /* generate UvMapVert array */
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +              if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT)))
 +                      totuv += efa->len;
 +      }
 +
 +      if(totuv==0) {
 +              if (do_face_idx_array)
 +                      EDBM_free_index_arrays(em);
 +              return NULL;
 +      }
 +      vmap= (UvVertMap*)MEM_callocN(sizeof(*vmap), "UvVertMap");
 +      if (!vmap) {
 +              if (do_face_idx_array)
 +                      EDBM_free_index_arrays(em);
 +              return NULL;
 +      }
 +
 +      vmap->vert= (UvMapVert**)MEM_callocN(sizeof(*vmap->vert)*totverts, "UvMapVert*");
 +      buf= vmap->buf= (UvMapVert*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvMapVert");
 +
 +      if (!vmap->vert || !vmap->buf) {
 +              free_uv_vert_map(vmap);
 +              if (do_face_idx_array)
 +                      EDBM_free_index_arrays(em);
 +              return NULL;
 +      }
 +      
 +      a = 0;
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +              if(!selected || ((!BM_TestHFlag(efa, BM_HIDDEN)) && BM_TestHFlag(efa, BM_SELECT))) {
 +                      i = 0;
 +                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                              buf->tfindex= i;
 +                              buf->f= a;
 +                              buf->separate = 0;
 +                              
 +                              buf->next= vmap->vert[BM_GetIndex(l->v)];
 +                              vmap->vert[BM_GetIndex(l->v)]= buf;
 +                              
 +                              buf++;
 +                              i++;
 +                      }
 +              }
 +
 +              a++;
 +      }
 +      
 +      /* sort individual uvs for each vert */
 +      a = 0;
 +      BM_ITER(ev, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
 +              UvMapVert *newvlist= NULL, *vlist=vmap->vert[a];
 +              UvMapVert *iterv, *v, *lastv, *next;
 +              float *uv, *uv2, uvdiff[2];
 +
 +              while(vlist) {
 +                      v= vlist;
 +                      vlist= vlist->next;
 +                      v->next= newvlist;
 +                      newvlist= v;
 +
 +                      efa = EDBM_get_face_for_index(em, v->f);
 +                      /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
 +                      
 +                      l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, v->tfindex);
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      uv = luv->uv; 
 +                      
 +                      lastv= NULL;
 +                      iterv= vlist;
 +
 +                      while(iterv) {
 +                              next= iterv->next;
 +                              efa = EDBM_get_face_for_index(em, iterv->f);
 +                              /* tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY); */ /* UNUSED */
 +                              
 +                              l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
 +                              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                              uv2 = luv->uv; 
 +                              
 +                              sub_v2_v2v2(uvdiff, uv2, uv);
 +
 +                              if(fabs(uv[0]-uv2[0]) < limit[0] && fabs(uv[1]-uv2[1]) < limit[1]) {
 +                                      if(lastv) lastv->next= next;
 +                                      else vlist= next;
 +                                      iterv->next= newvlist;
 +                                      newvlist= iterv;
 +                              }
 +                              else
 +                                      lastv=iterv;
 +
 +                              iterv= next;
 +                      }
 +
 +                      newvlist->separate = 1;
 +              }
 +
 +              vmap->vert[a]= newvlist;
 +              a++;
 +      }
 +      
 +      if (do_face_idx_array)
 +              EDBM_free_index_arrays(em);
 +      
 +      return vmap;
 +}
 +
 +
 +UvMapVert *EDBM_get_uv_map_vert(UvVertMap *vmap, unsigned int v)
 +{
 +      return vmap->vert[v];
 +}
 +
++/* from editmesh_lib.c in trunk */
++#if 0 /* BMESH_TODO */
++
++/* A specialized vert map used by stitch operator */
++UvElementMap *EDBM_make_uv_element_map(EditMesh *em, int selected, int do_islands)
++{
++      EditVert *ev;
++      EditFace *efa;
++
++      /* vars from original func */
++      UvElementMap *vmap;
++      UvElement *buf;
++      UvElement *islandbuf;
++      MTFace *tf;
++      unsigned int a;
++      int     i,j, totuv, nverts, nislands = 0, islandbufsize = 0;
++      unsigned int *map;
++      /* for uv island creation */
++      EditFace **stack;
++      int stacksize = 0;
++
++      /* we need the vert */
++      for(ev = em->verts.first, i = 0; ev; ev = ev->next, i++)
++              ev->tmp.l = i;
++
++      totuv = 0;
++
++      for(efa = em->faces.first; efa; efa = efa->next)
++              if(!selected || ((!efa->h) && (efa->f & SELECT)))
++                      totuv += (efa->v4)? 4: 3;
++
++      if(totuv == 0)
++              return NULL;
++
++      vmap = (UvElementMap *)MEM_callocN(sizeof(*vmap), "UvVertElementMap");
++      if(!vmap)
++              return NULL;
++
++      vmap->vert = (UvElement**)MEM_callocN(sizeof(*vmap->vert)*em->totvert, "UvElementVerts");
++      buf = vmap->buf = (UvElement*)MEM_callocN(sizeof(*vmap->buf)*totuv, "UvElement");
++
++      if(!vmap->vert || !vmap->buf) {
++              EDBM_free_uv_element_map(vmap);
++              return NULL;
++      }
++
++      vmap->totalUVs = totuv;
++
++      for(efa = em->faces.first; efa; a++, efa = efa->next) {
++              if(!selected || ((!efa->h) && (efa->f & SELECT))) {
++                      nverts = (efa->v4)? 4: 3;
++
++                      for(i = 0; i<nverts; i++) {
++                              buf->tfindex = i;
++                              buf->face = efa;
++                              buf->separate = 0;
++                              buf->island = INVALID_ISLAND;
++
++                              buf->next = vmap->vert[(*(&efa->v1 + i))->tmp.l];
++                              vmap->vert[(*(&efa->v1 + i))->tmp.l] = buf;
++
++                              buf++;
++                      }
++              }
++
++              efa->tmp.l = INVALID_ISLAND;
++      }
++
++      /* sort individual uvs for each vert */
++      for(a = 0, ev = em->verts.first; ev; a++, ev = ev->next) {
++              UvElement *newvlist = NULL, *vlist = vmap->vert[a];
++              UvElement *iterv, *v, *lastv, *next;
++              float *uv, *uv2;
++
++              while(vlist) {
++                      v= vlist;
++                      vlist= vlist->next;
++                      v->next= newvlist;
++                      newvlist= v;
++
++                      efa = v->face;
++                      tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
++                      uv = tf->uv[v->tfindex];
++
++                      lastv= NULL;
++                      iterv= vlist;
++
++                      while(iterv) {
++                              next= iterv->next;
++                              efa = iterv->face;
++                              tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
++                              uv2 = tf->uv[iterv->tfindex];
++
++                              if(fabsf(uv[0]-uv2[0]) < STD_UV_CONNECT_LIMIT && fabsf(uv[1]-uv2[1]) < STD_UV_CONNECT_LIMIT) {
++                                      if(lastv) lastv->next = next;
++                                      else vlist = next;
++                                      iterv->next = newvlist;
++                                      newvlist = iterv;
++                              }
++                              else
++                                      lastv = iterv;
++
++                              iterv = next;
++                      }
++
++                      newvlist->separate = 1;
++              }
++
++              vmap->vert[a] = newvlist;
++      }
++
++      if(do_islands) {
++              /* at this point, every UvElement in vert points to a UvElement sharing the same vertex. Now we should sort uv's in islands. */
++
++              /* map holds the map from current vmap->buf to the new, sorted map*/
++              map = MEM_mallocN(sizeof(*map)*totuv, "uvelement_remap");
++              stack = MEM_mallocN(sizeof(*stack)*em->totface, "uv_island_face_stack");
++              islandbuf = MEM_callocN(sizeof(*islandbuf)*totuv, "uvelement_island_buffer");
++
++              for(i = 0; i < totuv; i++) {
++                      if(vmap->buf[i].island == INVALID_ISLAND) {
++                              vmap->buf[i].island = nislands;
++                              stack[0] = vmap->buf[i].face;
++                              stack[0]->tmp.l = nislands;
++                              stacksize=1;
++
++                              while(stacksize > 0) {
++                                      efa = stack[--stacksize];
++                                      nverts = efa->v4? 4 : 3;
++
++                                      for(j = 0; j < nverts; j++) {
++                                              UvElement *element, *initelement = vmap->vert[(*(&efa->v1 + j))->tmp.l];
++
++                                              for(element = initelement; element; element = element->next) {
++                                                      if(element->separate)
++                                                              initelement = element;
++
++                                                      if(element->face == efa) {
++                                                              /* found the uv corresponding to our face and vertex. Now fill it to the buffer */
++                                                              element->island = nislands;
++                                                              map[element - vmap->buf] = islandbufsize;
++                                                              islandbuf[islandbufsize].tfindex = element->tfindex;
++                                                              islandbuf[islandbufsize].face = element->face;
++                                                              islandbuf[islandbufsize].separate = element->separate;
++                                                              islandbuf[islandbufsize].island =  nislands;
++                                                              islandbufsize++;
++
++                                                              for(element = initelement; element; element = element->next) {
++                                                                      if(element->separate && element != initelement)
++                                                                              break;
++
++                                                                      if(element->face->tmp.l == INVALID_ISLAND) {
++                                                                              stack[stacksize++] = element->face;
++                                                                              element->face->tmp.l = nislands;
++                                                                      }
++                                                              }
++                                                              break;
++                                                      }
++                                              }
++                                      }
++                              }
++
++                              nislands++;
++                      }
++              }
++
++              /* remap */
++              for(i = 0; i < em->totvert; i++) {
++                      /* important since we may do selection only. Some of these may be NULL */
++                      if(vmap->vert[i])
++                              vmap->vert[i] = &islandbuf[map[vmap->vert[i] - vmap->buf]];
++              }
++
++              vmap->islandIndices = MEM_callocN(sizeof(*vmap->islandIndices)*nislands,"UvVertMap2_island_indices");
++              if(!vmap->islandIndices) {
++                      MEM_freeN(islandbuf);
++                      MEM_freeN(stack);
++                      MEM_freeN(map);
++                      EDBM_free_uv_element_map(vmap);
++              }
++
++              j = 0;
++              for(i = 0; i < totuv; i++) {
++                      UvElement *element = vmap->buf[i].next;
++                      if(element == NULL)
++                              islandbuf[map[i]].next = NULL;
++                      else
++                              islandbuf[map[i]].next = &islandbuf[map[element - vmap->buf]];
++
++                      if(islandbuf[i].island != j) {
++                              j++;
++                              vmap->islandIndices[j] = i;
++                      }
++              }
++
++              MEM_freeN(vmap->buf);
++
++              vmap->buf = islandbuf;
++              vmap->totalIslands = nislands;
++              MEM_freeN(stack);
++              MEM_freeN(map);
++      }
++
++      return vmap;
++}
++
++#else
++
++UvElementMap *EDBM_make_uv_element_map(BMEditMesh *em, int selected, int do_islands)
++{
++      (void)em;
++      (void)selected;
++      (void)do_islands;
++
++      return NULL;
++}
++
++#endif /* BMESH_TODO */
++
++UvMapVert *EM_get_uv_map_vert(UvVertMap *vmap, unsigned int v)
++{
++      return vmap->vert[v];
++}
++
 +void EDBM_free_uv_vert_map(UvVertMap *vmap)
 +{
 +      if (vmap) {
 +              if (vmap->vert) MEM_freeN(vmap->vert);
 +              if (vmap->buf) MEM_freeN(vmap->buf);
 +              MEM_freeN(vmap);
 +      }
 +}
 +
++void EDBM_free_uv_element_map(UvElementMap *vmap)
++{
++      if (vmap) {
++              if (vmap->vert) MEM_freeN(vmap->vert);
++              if (vmap->buf) MEM_freeN(vmap->buf);
++              if (vmap->islandIndices) MEM_freeN(vmap->islandIndices);
++              MEM_freeN(vmap);
++      }
++}
 +
 +/* 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 */
 +MTexPoly *EDBM_get_active_mtexpoly(BMEditMesh *em, BMFace **act_efa, int sloppy)
 +{
 +      BMFace *efa = NULL;
 +      
 +      if(!EDBM_texFaceCheck(em))
 +              return NULL;
 +      
 +      efa = BM_get_actFace(em->bm, sloppy);
 +      
 +      if (efa) {
 +              if (act_efa) *act_efa = efa; 
 +              return CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +      }
 +
 +      if (act_efa) *act_efa= NULL;
 +      return NULL;
 +}
 +
 +/* can we edit UV's for this mesh?*/
 +int EDBM_texFaceCheck(BMEditMesh *em)
 +{
 +      /* some of these checks could be a touch overkill */
 +      return em && em->bm->totface && CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY) &&
 +                 CustomData_has_layer(&em->bm->ldata, CD_MLOOPUV);
 +}
 +
 +int EDBM_vertColorCheck(BMEditMesh *em)
 +{
 +      /* some of these checks could be a touch overkill */
 +      return em && em->bm->totface && CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
 +}
 +
 +static BMVert *cache_mirr_intptr_as_bmvert(intptr_t *index_lookup, int index)
 +{
 +      intptr_t eve_i= index_lookup[index];
 +      return (eve_i == -1) ? NULL : (BMVert *)eve_i;
 +}
 +
 +/* BM_SEARCH_MAXDIST is too big, copied from 2.6x MOC_THRESH, should become a
 + * preference */
 +#define BM_SEARCH_MAXDIST_MIRR 0.00002f
 +#define BM_CD_LAYER_ID "__mirror_index"
 +void EDBM_CacheMirrorVerts(BMEditMesh *em, const short use_select)
 +{
 +      Mesh *me = em->me;
 +      BMesh *bm = em->bm;
 +      BMIter iter;
 +      BMVert *v;
 +      int li, topo = 0;
 +
 +      /* one or the other is used depending if topo is enabled */
 +      BMBVHTree *tree= NULL;
 +      MirrTopoStore_t mesh_topo_store= {NULL, -1, -1, -1};
 +
 +      if (me && (me->editflag & ME_EDIT_MIRROR_TOPO)) {
 +              topo = 1;
 +      }
 +
 +      if (!em->vert_index) {
 +              EDBM_init_index_arrays(em, 1, 0, 0);
 +              em->mirr_free_arrays = 1;
 +      }
 +
 +      if (!CustomData_get_layer_named(&bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID)) {
 +              BM_add_data_layer_named(bm, &bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID);
 +      }
 +
 +      li= CustomData_get_named_layer_index(&bm->vdata, CD_PROP_INT, BM_CD_LAYER_ID);
 +
 +      bm->vdata.layers[li].flag |= CD_FLAG_TEMPORARY;
 +
 +      BM_ElemIndex_Ensure(bm, BM_VERT);
 +
 +      if (topo) {
 +              ED_mesh_mirrtopo_init(me, -1, &mesh_topo_store, TRUE);
 +      }
 +      else {
 +               tree= BMBVH_NewBVH(em, 0, NULL, NULL);
 +      }
 +
 +      BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
 +
 +              /* temporary for testing, check for selection */
 +              if (use_select && !BM_TestHFlag(v, BM_SELECT)) {
 +                      /* do nothing */
 +              }
 +              else {
 +                      BMVert *mirr;
 +                      int *idx = CustomData_bmesh_get_layer_n(&bm->vdata, v->head.data, li);
 +
 +                      if (topo) {
 +                              mirr= cache_mirr_intptr_as_bmvert(mesh_topo_store.index_lookup, BM_GetIndex(v));
 +                      }
 +                      else {
 +                              float co[3] = {-v->co[0], v->co[1], v->co[2]};
 +                              mirr= BMBVH_FindClosestVert(tree, co, BM_SEARCH_MAXDIST_MIRR);
 +                      }
 +
 +                      if (mirr && mirr != v) {
 +                              *idx = BM_GetIndex(mirr);
 +                              idx = CustomData_bmesh_get_layer_n(&bm->vdata, mirr->head.data, li);
 +                              *idx = BM_GetIndex(v);
 +                      }
 +                      else {
 +                              *idx = -1;
 +                      }
 +              }
 +
 +      }
 +
 +
 +      if (topo) {
 +              ED_mesh_mirrtopo_free(&mesh_topo_store);
 +      }
 +      else {
 +              BMBVH_FreeBVH(tree);
 +      }
 +
 +      em->mirror_cdlayer= li;
 +}
 +
 +BMVert *EDBM_GetMirrorVert(BMEditMesh *em, BMVert *v)
 +{
 +      int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
 +
 +      BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
 +
 +      if (mirr && *mirr >=0 && *mirr < em->bm->totvert) {
 +              if (!em->vert_index) {
 +                      printf("err: should only be called between "
 +                              "EDBM_CacheMirrorVerts and EDBM_EndMirrorCache");
 +                      return NULL;
 +              }
 +
 +              return em->vert_index[*mirr];
 +      }
 +
 +      return NULL;
 +}
 +
 +void EDBM_ClearMirrorVert(BMEditMesh *em, BMVert *v)
 +{
 +      int *mirr = CustomData_bmesh_get_layer_n(&em->bm->vdata, v->head.data, em->mirror_cdlayer);
 +
 +      BLI_assert(em->mirror_cdlayer != -1); /* invalid use */
 +
 +      if (mirr) {
 +              *mirr= -1;
 +      }
 +}
 +
 +void EDBM_EndMirrorCache(BMEditMesh *em)
 +{
 +      if (em->mirr_free_arrays) {
 +              MEM_freeN(em->vert_index);
 +              em->vert_index = NULL;
 +      }
 +
 +      em->mirror_cdlayer= -1;
 +}
 +
 +void EDBM_ApplyMirrorCache(BMEditMesh *em, const int sel_from, const int sel_to)
 +{
 +      BMIter iter;
 +      BMVert *v;
 +
 +      BLI_assert(em->vert_index != NULL);
 +
 +      BM_ITER(v, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
 +              if (BM_TestHFlag(v, BM_SELECT) == sel_from) {
 +                      BMVert *mirr= EDBM_GetMirrorVert(em, v);
 +                      if (mirr) {
 +                              if (BM_TestHFlag(mirr, BM_SELECT) == sel_to) {
 +                                      copy_v3_v3(mirr->co, v->co);
 +                                      mirr->co[0] *= -1.0f;
 +                              }
 +                      }
 +              }
 +      }
 +}
@@@ -23,6 -23,6 +23,7 @@@ set(IN
        ../../blenkernel
        ../../blenlib
        ../../blenloader
++      ../../bmesh
        ../../gpu
        ../../imbuf
        ../../makesdna
@@@ -8,7 -8,7 +8,7 @@@ defs = [
  incs = '../include ../../blenlib ../../blenkernel ../../makesdna ../../imbuf'
  incs += ' ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
  incs += ' ../../render/extern/include'
- incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh'
 -incs += ' ../../gpu ../../makesrna ../../blenloader ../uvedit'
++incs += ' ../../gpu ../../makesrna ../../blenloader ../../bmesh ../uvedit'
  
  if env['OURPLATFORM'] == 'linux':
      cflags='-pthread'
  #include "BKE_paint.h"
  #include "BKE_report.h"
  #include "BKE_scene.h"
+ #include "BKE_global.h"
+ #include "BKE_deform.h"
++#include "BKE_tessmesh.h"
 +
  #include "BIF_gl.h"
  #include "BIF_glutil.h"
  
@@@ -4630,6 -4644,31 +4646,30 @@@ static int image_paint_poll(bContext *C
        return 0;
  }
  
 -      EditMesh *em;
+ static int uv_sculpt_brush_poll(bContext *C)
+ {
 -      em = BKE_mesh_get_editmesh(obedit->data);
 -      ret = EM_texFaceCheck(em);
 -      BKE_mesh_end_editmesh(obedit->data, em);
++      BMEditMesh *em;
+       int ret;
+       Object *obedit = CTX_data_edit_object(C);
+       SpaceImage *sima= CTX_wm_space_image(C);
+       Scene *scene = CTX_data_scene(C);
+       ToolSettings *toolsettings = scene->toolsettings;
+       if(!uv_sculpt_brush(C) || !obedit || obedit->type != OB_MESH)
+               return 0;
++      em = ((Mesh *)obedit->data)->edit_btmesh;
++      ret = EDBM_texFaceCheck(em);
+       if(ret && sima) {
+               ARegion *ar= CTX_wm_region(C);
+               if((toolsettings->use_uv_sculpt) && ar->regiontype==RGN_TYPE_WINDOW)
+                       return 1;
+       }
+       return 0;
+ }
  static int image_paint_3d_poll(bContext *C)
  {
        if(CTX_wm_region_view3d(C))
index 0000000,4023797..21bbb01
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,767 +1,787 @@@
 -void HC_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio){
+ /*
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+  *
+  * The Original Code is Copyright (C) Blender Foundation, 2002-2009
+  * All rights reserved.
+  *
+  * Contributor(s): Antony Riakiotakis
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  *
+  * UV Sculpt tools
+  *
+  */
+ /** \file blender/editors/sculpt_paint/sculpt_uv.c
+  *  \ingroup edsculpt
+  */
+ #include "MEM_guardedalloc.h"
+ #include "BLI_utildefines.h"
+ #include "BLI_editVert.h"
+ #include "BLI_math.h"
+ #include "BLI_ghash.h"
+ #include "DNA_object_types.h"
+ #include "DNA_scene_types.h"
+ #include "DNA_brush_types.h"
+ #include "DNA_meshdata_types.h"
+ #include "BKE_brush.h"
+ #include "BKE_paint.h"
+ #include "BKE_context.h"
+ #include "BKE_main.h"
+ #include "BKE_depsgraph.h"
+ #include "BKE_mesh.h"
+ #include "BKE_customdata.h"
++#include "BKE_tessmesh.h"
+ #include "ED_screen.h"
+ #include "ED_image.h"
+ #include "ED_mesh.h"
+ #include "WM_api.h"
+ #include "WM_types.h"
+ #include "RNA_access.h"
+ #include "RNA_define.h"
+ #include "RNA_enum_types.h"
+ #include "paint_intern.h"
+ #include "uvedit_intern.h"
+ #include "UI_view2d.h"
+ #define MARK_BOUNDARY 1
+ typedef struct UvAdjacencyElement {
+       /* pointer to original uvelement */
+       UvElement *element;
+       /* uv pointer for convenience. Caution, this points to the original UVs! */
+       float *uv;
+       /* general use flag (Used to check if Element is boundary here) */
+       char flag;
+ } UvAdjacencyElement;
+ typedef struct UvEdge {
+       unsigned int uv1;
+       unsigned int uv2;
+       /* general use flag (Used to check if edge is boundary here, and propagates to adjacency elements) */
+       char flag;
+ }UvEdge;
+ typedef struct UVInitialStrokeElement{
+       /* index to unique uv */
+       int uv;
+       /* strength of brush on initial position */
+       float strength;
+       /* initial uv position */
+       float initial_uv[2];
+ }UVInitialStrokeElement;
+ typedef struct UVInitialStroke{
+       /* Initial Selection,for grab brushes for instance */
+       UVInitialStrokeElement *initialSelection;
+       /* total initially selected UVs*/
+       int totalInitialSelected;
+       /* initial mouse coordinates */
+       float init_coord[2];
+ }UVInitialStroke;
+ /* custom data for uv smoothing brush */
+ typedef struct UvSculptData{
+       /* Contains the first of each set of coincident uvs.
+        * These will be used to perform smoothing on and propagate the changes
+        * to their coincident uvs */
+       UvAdjacencyElement *uv;
+       /* ...Is what it says */
+       int totalUniqueUvs;
+       /* Edges used for adjacency info, used with laplacian smoothing */
+       UvEdge *uvedges;
+       /* Need I say more? */
+       int totalUvEdges;
+       /* data for initial stroke, used by tools like grab */
+       UVInitialStroke *initial_stroke;
+       /* Timer to be used for airbrush-type brush */
+       wmTimer *timer;
+       /* To determine quickly adjacent uvs */
+       UvElementMap *elementMap;
+       /* uvsmooth Paint for fast reference */
+       Paint *uvsculpt;
+ }UvSculptData;
+ /*********** Improved Laplacian Relaxation Operator ************************/
+ /* Original code by Raul Fernandez Hernandez "farsthary"                   *
+  * adapted to uv smoothing by Antony Riakiatakis                           *
+  ***************************************************************************/
+ typedef struct Temp_UvData{
+       float sum_co[2], p[2], b[2], sum_b[2];
+       int ncounter;
+ }Temp_UVData;
 -static void laplacian_relaxation_iteration_uv(EditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio)
++void HC_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio){
+       Temp_UVData *tmp_uvdata;
+       float diff[2];
+       int i;
+       float radius_root = sqrt(radius);
+       Brush *brush = paint_brush(sculptdata->uvsculpt);
+       tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
+       /* counting neighbors */
+       for (i = 0; i < sculptdata->totalUvEdges; i++){
+               UvEdge *tmpedge = sculptdata->uvedges+i;
+               tmp_uvdata[tmpedge->uv1].ncounter++;
+               tmp_uvdata[tmpedge->uv2].ncounter++;
+               add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
+               add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
+       }
+       for (i = 0; i < sculptdata->totalUniqueUvs; i++){
+               copy_v2_v2(diff,tmp_uvdata[i].sum_co);
+               mul_v2_fl(diff,1.f/tmp_uvdata[i].ncounter);
+               copy_v2_v2(tmp_uvdata[i].p,diff);
+               tmp_uvdata[i].b[0] = diff[0] - sculptdata->uv[i].uv[0];
+               tmp_uvdata[i].b[1] = diff[1] - sculptdata->uv[i].uv[1];
+       }
+       for (i = 0; i < sculptdata->totalUvEdges; i++){
+               UvEdge *tmpedge = sculptdata->uvedges+i;
+               add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_b, tmp_uvdata[tmpedge->uv2].b);
+               add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_b, tmp_uvdata[tmpedge->uv1].b);
+       }
+       for (i = 0; i < sculptdata->totalUniqueUvs; i++){
+               float dist;
+               /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
+                * If ever uv brushes get their own mode we should check for toolsettings option too */
+               if((sculptdata->uv[i].flag & MARK_BOUNDARY)){
+                       continue;
+               }
+               sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
+               diff[1] /= aspectRatio;
+               if((dist = dot_v2v2(diff, diff)) <= radius){
+                       UvElement *element;
+                       float strength;
+                       strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
+                       sculptdata->uv[i].uv[0] = (1.0-strength)*sculptdata->uv[i].uv[0] + strength*(tmp_uvdata[i].p[0] - 0.5f*(tmp_uvdata[i].b[0] + tmp_uvdata[i].sum_b[0]/tmp_uvdata[i].ncounter));
+                       sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*(tmp_uvdata[i].p[1] - 0.5f*(tmp_uvdata[i].b[1] + tmp_uvdata[i].sum_b[1]/tmp_uvdata[i].ncounter));
+                       for(element = sculptdata->uv[i].element; element; element = element->next){
++#if 0 /* BMESH_TODO */
+                               MTFace *mt;
+                               if(element->separate && element != sculptdata->uv[i].element)
+                                       break;
+                               mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
+                               copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
++#else
++                              (void)em;
++#endif /* BMESH_TODO */
+                       }
+               }
+       }
+       MEM_freeN(tmp_uvdata);
+       return;
+ }
 -      EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
++static void laplacian_relaxation_iteration_uv(BMEditMesh *em, UvSculptData *sculptdata, float mouse_coord[2], float alpha, float radius, float aspectRatio)
+ {
+       Temp_UVData *tmp_uvdata;
+       float diff[2];
+       int i;
+       float radius_root = sqrt(radius);
+       Brush *brush = paint_brush(sculptdata->uvsculpt);
+       tmp_uvdata = (Temp_UVData *)MEM_callocN(sculptdata->totalUniqueUvs * sizeof(Temp_UVData), "Temporal data");
+       /* counting neighbors */
+       for (i = 0; i < sculptdata->totalUvEdges; i++){
+               UvEdge *tmpedge = sculptdata->uvedges+i;
+               tmp_uvdata[tmpedge->uv1].ncounter++;
+               tmp_uvdata[tmpedge->uv2].ncounter++;
+               add_v2_v2(tmp_uvdata[tmpedge->uv2].sum_co, sculptdata->uv[tmpedge->uv1].uv);
+               add_v2_v2(tmp_uvdata[tmpedge->uv1].sum_co, sculptdata->uv[tmpedge->uv2].uv);
+       }
+       /* Original Lacplacian algorithm included removal of normal component of translation. here it is not
+        * needed since we translate along the UV plane always.*/
+       for (i = 0; i < sculptdata->totalUniqueUvs; i++){
+               copy_v2_v2(tmp_uvdata[i].p, tmp_uvdata[i].sum_co);
+               mul_v2_fl(tmp_uvdata[i].p, 1.f/tmp_uvdata[i].ncounter);
+       }
+       for (i = 0; i < sculptdata->totalUniqueUvs; i++){
+               float dist;
+               /* This is supposed to happen only if "Pin Edges" is on, since we have initialization on stroke start
+                * If ever uv brushes get their own mode we should check for toolsettings option too */
+               if((sculptdata->uv[i].flag & MARK_BOUNDARY)){
+                       continue;
+               }
+               sub_v2_v2v2(diff, sculptdata->uv[i].uv, mouse_coord);
+               diff[1] /= aspectRatio;
+               if((dist = dot_v2v2(diff, diff)) <= radius){
+                       UvElement *element;
+                       float strength;
+                       strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
+                       sculptdata->uv[i].uv[0] = (1.0-strength)*sculptdata->uv[i].uv[0] + strength*tmp_uvdata[i].p[0];
+                       sculptdata->uv[i].uv[1] = (1.0-strength)*sculptdata->uv[i].uv[1] + strength*tmp_uvdata[i].p[1];
+                       for(element = sculptdata->uv[i].element; element; element = element->next){
++#if 0 /* BMESH_TODO */
+                               MTFace *mt;
+                               if(element->separate && element != sculptdata->uv[i].element)
+                                       break;
+                               mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
+                               copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
++#else
++                              (void)em;
++#endif /* BMESH_TODO */
+                       }
+               }
+       }
+       MEM_freeN(tmp_uvdata);
+       return;
+ }
+ static void uv_sculpt_stroke_apply(bContext *C, wmOperator *op, wmEvent *event, Object *obedit)
+ {
+       float co[2], radius, radius_root;
+       Scene *scene = CTX_data_scene(C);
+       ARegion *ar = CTX_wm_region(C);
 -                                      mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
++      BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
+       unsigned int tool;
+       UvSculptData *sculptdata = (UvSculptData *)op->customdata;
+       SpaceImage *sima;
+       int invert;
+       int width, height;
+       float aspectRatio;
+       float alpha, zoomx, zoomy;
+       Brush *brush = paint_brush(sculptdata->uvsculpt);
+       ToolSettings *toolsettings = CTX_data_tool_settings(C);
+       tool = RNA_boolean_get(op->ptr, "temp_relax")? UV_SCULPT_TOOL_RELAX : toolsettings->uv_sculpt_tool;
+       invert = RNA_boolean_get(op->ptr, "invert")? -1 : 1;
+       alpha = brush_alpha(scene, brush);
+       UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+       sima = CTX_wm_space_image(C);
+       ED_space_image_size(sima, &width, &height);
+       ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
+       radius = brush_size(scene, brush)/(width*zoomx);
+       aspectRatio = width/(float)height;
+       /* We will compare squares to save some computation */
+       radius = radius*radius;
+       radius_root = sqrt(radius);
+       /*
+        * Pinch Tool
+        */
+       if(tool == UV_SCULPT_TOOL_PINCH){
+               int i;
+               alpha *= invert;
+               for (i = 0; i < sculptdata->totalUniqueUvs; i++){
+                       float dist, diff[2];
+                       /* This is supposed to happen only if "Lock Borders" is on, since we have initialization on stroke start
+                        * If ever uv brushes get their own mode we should check for toolsettings option too */
+                       if(sculptdata->uv[i].flag & MARK_BOUNDARY){
+                               continue;
+                       }
+                       sub_v2_v2v2(diff, sculptdata->uv[i].uv, co);
+                       diff[1] /= aspectRatio;
+                       if((dist = dot_v2v2(diff, diff)) <= radius){
+                               UvElement *element;
+                               float strength;
+                               strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
+                               normalize_v2(diff);
+                               sculptdata->uv[i].uv[0] -= strength*diff[0]*0.001;
+                               sculptdata->uv[i].uv[1] -= strength*diff[1]*0.001;
+                               for(element = sculptdata->uv[i].element; element; element = element->next){
++#if 0 /* BMESH_TODO*/
+                                       MTFace *mt;
+                                       if(element->separate && element != sculptdata->uv[i].element)
+                                               break;
 -
 -      BKE_mesh_end_editmesh(obedit->data, em);
++                                      mt = CustomData_em_get(&bm->fdata, element->face->data, CD_MTFACE);
+                                       copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[i].uv);
++#endif
+                               }
+                       }
+               }
+       }
+       /*
+        * Smooth Tool
+        */
+       else if(tool == UV_SCULPT_TOOL_RELAX){
+               unsigned int method = toolsettings->uv_relax_method;
+               if(method == UV_SCULPT_TOOL_RELAX_HC){
+                       HC_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
+               }else{
+                       laplacian_relaxation_iteration_uv(em, sculptdata, co, alpha, radius, aspectRatio);
+               }
+       }
+       /*
+        * Grab Tool
+        */
+       else if(tool == UV_SCULPT_TOOL_GRAB){
+               int i;
+               float diff[2];
+               sub_v2_v2v2(diff, co, sculptdata->initial_stroke->init_coord);
+               for(i = 0; i < sculptdata->initial_stroke->totalInitialSelected; i++ ){
+                       UvElement *element;
+                       int uvindex = sculptdata->initial_stroke->initialSelection[i].uv;
+                       float strength = sculptdata->initial_stroke->initialSelection[i].strength;
+                       sculptdata->uv[uvindex].uv[0] = sculptdata->initial_stroke->initialSelection[i].initial_uv[0] + strength*diff[0];
+                       sculptdata->uv[uvindex].uv[1] = sculptdata->initial_stroke->initialSelection[i].initial_uv[1] + strength*diff[1];
+                       for(element = sculptdata->uv[uvindex].element; element; element = element->next){
++#if 0 /* BMESH_TODO */
+                               MTFace *mt;
+                               if(element->separate && element != sculptdata->uv[uvindex].element)
+                                       break;
+                               mt = CustomData_em_get(&em->fdata, element->face->data, CD_MTFACE);
+                               copy_v2_v2(mt->uv[element->tfindex], sculptdata->uv[uvindex].uv);
++#endif /* BMESH_TODO */
+                       }
+               }
+       }
 -              EM_free_uv_element_map(data->elementMap);
+ }
+ static void uv_sculpt_stroke_exit(bContext *C, wmOperator *op)
+ {
+       UvSculptData *data = op->customdata;
+       if(data->timer){
+               WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), data->timer);
+       }
+       if(data->elementMap)
+       {
 -static int get_uv_element_offset_from_face(UvElementMap *map, EditFace *efa, int index, int island_index, int doIslands){
++              EDBM_free_uv_element_map(data->elementMap);
+       }
+       if(data->uv){
+               MEM_freeN(data->uv);
+       }
+       if(data->uvedges){
+               MEM_freeN(data->uvedges);
+       }
+       if(data->initial_stroke){
+               if(data->initial_stroke->initialSelection){
+                       MEM_freeN(data->initial_stroke->initialSelection);
+               }
+               MEM_freeN(data->initial_stroke);
+       }
+       MEM_freeN(data);
+       op->customdata = NULL;
+ }
 -      EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
++static int get_uv_element_offset_from_face(UvElementMap *map, BMFace *efa, int index, int island_index, int doIslands){
+       UvElement *element = ED_get_uv_element(map, efa, index);
+       if(!element || (doIslands && element->island != island_index)){
+               return -1;
+       }
+       return element - map->buf;
+ }
+ static unsigned int   uv_edge_hash(const void *key){
+       UvEdge *edge = (UvEdge *)key;
+       return 
+               BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) +
+               BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1));
+ }
+ static int uv_edge_compare(const void *a, const void *b){
+       UvEdge *edge1 = (UvEdge *)a;
+       UvEdge *edge2 = (UvEdge *)b;
+       if((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)){
+               return 0;
+       }
+       return 1;
+ }
+ static UvSculptData *uv_sculpt_stroke_init(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       Scene *scene = CTX_data_scene(C);
+       Object *obedit = CTX_data_edit_object(C);
+       ToolSettings *ts = scene->toolsettings;
+       UvSculptData *data = MEM_callocN(sizeof(*data), "UV Smooth Brush Data");
 -                              data->elementMap = EM_make_uv_element_map(em, 0, 1);
++      BMEditMesh *em = ((Mesh *)obedit->data)->edit_btmesh;
++      BMesh *bm = em->bm;
+       op->customdata = data;
+       if(data){
+               int counter = 0, i;
+               ARegion *ar= CTX_wm_region(C);
+               float co[2];
+               EditFace *efa;
+               UvEdge *edges;
+               GHash *edgeHash;
+               GHashIterator* ghi;
+               MTFace *mt;
+               int do_island_optimization = !(ts->uv_sculpt_settings & UV_SCULPT_ALL_ISLANDS);
+               int island_index = 0;
+               /* Holds, for each UvElement in elementMap, a pointer to its unique uv.*/
+               int *uniqueUv;
+               data->uvsculpt = &ts->uvsculpt->paint;
+               if(do_island_optimization){
+                       /* We will need island information */
+                       if(ts->uv_flag & UV_SYNC_SELECTION){
 -                              data->elementMap = EM_make_uv_element_map(em, 1, 1);
++                              data->elementMap = EDBM_make_uv_element_map(em, 0, 1);
+                       }else{
 -                              data->elementMap = EM_make_uv_element_map(em, 0, 0);
++                              data->elementMap = EDBM_make_uv_element_map(em, 1, 1);
+                       }
+               }else {
+                       if(ts->uv_flag & UV_SYNC_SELECTION){
 -                              data->elementMap = EM_make_uv_element_map(em, 1, 0);
++                              data->elementMap = EDBM_make_uv_element_map(em, 0, 0);
+                       }else{
 -                      element = ED_get_uv_element(data->elementMap, hit.efa, hit.uv);
++                              data->elementMap = EDBM_make_uv_element_map(em, 1, 0);
+                       }
+               }
+               if(!data->elementMap){
+                       uv_sculpt_stroke_exit(C, op);
+                       return NULL;
+               }
+               /* Mouse coordinates, useful for some functions like grab and sculpt all islands */
+               UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+               /* we need to find the active island here */
+               if(do_island_optimization){
+                       UvElement *element;
+                       NearestHit hit;
+                       Image *ima= CTX_data_edit_image(C);
+                       uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
 -              for(i = 0; i < em->totvert; i++){
++                      element = ED_get_uv_element(data->elementMap, hit.efa, hit.lindex);
+                       island_index = element->island;
+               }
+               /* Count 'unique' uvs */
+               for(i = 0; i < data->elementMap->totalUVs; i++){
+                       if(data->elementMap->buf[i].separate
+                       && (!do_island_optimization || data->elementMap->buf[i].island == island_index)){
+                               counter++;
+                       }
+               }
+               /* Allocate the unique uv buffers */
+               data->uv = MEM_mallocN(sizeof(*data->uv)*counter, "uv_brush_unique_uvs");
+               uniqueUv = MEM_mallocN(sizeof(*uniqueUv)*data->elementMap->totalUVs, "uv_brush_unique_uv_map");
+               edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "uv_brush_edge_hash");
+               /* we have at most totalUVs edges */
+               edges = MEM_mallocN(sizeof(*edges)*data->elementMap->totalUVs, "uv_brush_all_edges");
+               if(!data->uv || !uniqueUv || !edgeHash || !edges){
+                       if(edges){
+                               MEM_freeN(edges);
+                       }
+                       if(uniqueUv){
+                               MEM_freeN(uniqueUv);
+                       }
+                       if(edgeHash){
+                               MEM_freeN(edgeHash);
+                       }
+                       uv_sculpt_stroke_exit(C, op);
+                       return NULL;
+               }
+               data->totalUniqueUvs = counter;
+               /* So that we can use this as index for the UvElements */
+               counter = -1;
+               /* initialize the unique UVs */
 -                                      mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
++              for(i = 0; i < bm->totvert; i++){
+                       UvElement *element = data->elementMap->vert[i];
+                       for(; element; element = element->next){
+                               if(element->separate){
+                                       if(do_island_optimization && (element->island != island_index)){
+                                               /* skip this uv if not on the active island */
+                                               for(; element->next && !(element->next->separate); element = element->next)
+                                                       ;
+                                               continue;
+                                       }
++#if 0 /* BMESH_TODO */
+                                       efa = element->face;
++                                      mt = CustomData_em_get(&bm->fdata, efa->data, CD_MTFACE);
+                                       counter++;
+                                       data->uv[counter].element = element;
+                                       data->uv[counter].flag = 0;
+                                       data->uv[counter].uv = mt->uv[element->tfindex];
++#else
++                                      (void)efa;
++                                      (void)mt;
++#endif /* BMESH_TODO */
+                               }
+                               /* pointer arithmetic to the rescue, as always :)*/
+                               uniqueUv[element - data->elementMap->buf] = counter;
+                       }
+               }
++#if 0 /* BMESH_TODO */
+               /* Now, on to generate our uv connectivity data */
+               for(efa = em->faces.first, counter = 0; efa; efa = efa->next){
+                       int nverts = efa->v4 ? 4 : 3;
+                       for(i = 0; i < nverts; i++){
+                               int offset1, itmp1 = get_uv_element_offset_from_face(data->elementMap, efa, i, island_index, do_island_optimization);
+                               int offset2, itmp2 = get_uv_element_offset_from_face(data->elementMap, efa, (i+1)%nverts, island_index, do_island_optimization);
+                               /* Skip edge if not found(unlikely) or not on valid island */
+                               if(itmp1 == -1 || itmp2 == -1)
+                                       continue;
+                               offset1 = uniqueUv[itmp1];
+                               offset2 = uniqueUv[itmp2];
+                               edges[counter].flag = 0;
+                               /* using an order policy, sort uvs according to address space. This avoids
+                                * Having two different UvEdges with the same uvs on different positions  */
+                               if(offset1 < offset2){
+                                       edges[counter].uv1 = offset1;
+                                       edges[counter].uv2 = offset2;
+                               }
+                               else{
+                                       edges[counter].uv1 = offset2;
+                                       edges[counter].uv2 = offset1;
+                               }
+                               /* Hack! Set the value of the key to its flag. Now we can set the flag when an edge exists twice :) */
+                               if(BLI_ghash_haskey(edgeHash, &edges[counter])){
+                                       char *flag = BLI_ghash_lookup(edgeHash, &edges[counter]);
+                                       *flag = 1;
+                               }
+                               else{
+                                       /* Hack mentioned */
+                                       BLI_ghash_insert(edgeHash, &edges[counter], &edges[counter].flag);
+                               }
+                               counter++;
+                       }
+               }
++#endif /* BMESH_TODO */
++
+               MEM_freeN(uniqueUv);
+               /* Allocate connectivity data, we allocate edges once */
+               data->uvedges = MEM_mallocN(sizeof(*data->uvedges)*BLI_ghash_size(edgeHash), "uv_brush_edge_connectivity_data");
+               if(!data->uvedges){
+                       BLI_ghash_free(edgeHash, NULL, NULL);
+                       MEM_freeN(edges);
+                       uv_sculpt_stroke_exit(C, op);
+                       return NULL;
+               }
+               ghi = BLI_ghashIterator_new(edgeHash);
+               if(!ghi){
+                       BLI_ghash_free(edgeHash, NULL, NULL);
+                       MEM_freeN(edges);
+                       uv_sculpt_stroke_exit(C, op);
+                       return NULL;
+               }
+               /* fill the edges with data */
+               for(i = 0; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)){
+                       data->uvedges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
+               }
+               data->totalUvEdges = BLI_ghash_size(edgeHash);
+               /* cleanup temporary stuff */
+               BLI_ghashIterator_free(ghi);
+               BLI_ghash_free(edgeHash, NULL, NULL);
+               MEM_freeN(edges);
+               /* transfer boundary edge property to uvs */
+               if(ts->uv_sculpt_settings & UV_SCULPT_LOCK_BORDERS){
+                       for(i = 0; i < data->totalUvEdges; i++){
+                               if(!data->uvedges[i].flag){
+                                       data->uv[data->uvedges[i].uv1].flag |= MARK_BOUNDARY;
+                                       data->uv[data->uvedges[i].uv2].flag |= MARK_BOUNDARY;
+                               }
+                       }
+               }
+               /* Allocate initial selection for grab tool */
+               if(ts->uv_sculpt_tool == UV_SCULPT_TOOL_GRAB){
+                       float radius, radius_root;
+                       UvSculptData *sculptdata = (UvSculptData *)op->customdata;
+                       SpaceImage *sima;
+                       int width, height;
+                       float aspectRatio;
+                       float alpha, zoomx, zoomy;
+                       Brush *brush = paint_brush(sculptdata->uvsculpt);
+                       alpha = brush_alpha(scene, brush);
+                       radius = brush_size(scene, brush);
+                       sima = CTX_wm_space_image(C);
+                       ED_space_image_size(sima, &width, &height);
+                       ED_space_image_zoom(sima, ar, &zoomx, &zoomy);
+                       aspectRatio = width/(float)height;
+                       radius /= (width*zoomx);
+                       radius = radius*radius;
+                       radius_root = sqrt(radius);
+                       /* Allocate selection stack */
+                       data->initial_stroke = MEM_mallocN(sizeof(*data->initial_stroke), "uv_sculpt_initial_stroke");
+                       if(!data->initial_stroke){
+                               uv_sculpt_stroke_exit(C, op);
+                       }
+                       data->initial_stroke->initialSelection = MEM_mallocN(sizeof(*data->initial_stroke->initialSelection)*data->totalUniqueUvs, "uv_sculpt_initial_selection");
+                       if(!data->initial_stroke->initialSelection){
+                               uv_sculpt_stroke_exit(C, op);
+                       }
+                       copy_v2_v2(data->initial_stroke->init_coord, co);
+                       counter = 0;
+                       for(i = 0; i < data->totalUniqueUvs; i++){
+                               float dist, diff[2];
+                               if(data->uv[i].flag & MARK_BOUNDARY){
+                                       continue;
+                               }
+                               sub_v2_v2v2(diff, data->uv[i].uv, co);
+                               diff[1] /= aspectRatio;
+                               if((dist = dot_v2v2(diff, diff)) <= radius){
+                                       float strength;
+                                       strength = alpha*brush_curve_strength(brush, sqrt(dist), radius_root);
+                                       data->initial_stroke->initialSelection[counter].uv = i;
+                                       data->initial_stroke->initialSelection[counter].strength = strength;
+                                       copy_v2_v2(data->initial_stroke->initialSelection[counter].initial_uv, data->uv[i].uv);
+                                       counter++;
+                               }
+                       }
+                       data->initial_stroke->totalInitialSelected = counter;
+               }
+       }
+       return op->customdata;
+ }
+ static int uv_sculpt_stroke_invoke(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       UvSculptData *data;
+       Object *obedit = CTX_data_edit_object(C);
+       if(!(data = uv_sculpt_stroke_init(C, op, event))) {
+               return OPERATOR_CANCELLED;
+       }
+       uv_sculpt_stroke_apply(C, op, event, obedit);
+       data->timer= WM_event_add_timer(CTX_wm_manager(C), CTX_wm_window(C), TIMER, 0.001f);
+       if(!data->timer){
+               uv_sculpt_stroke_exit(C, op);
+               return OPERATOR_CANCELLED;
+       }
+       WM_event_add_modal_handler(C, op);
+       return OPERATOR_RUNNING_MODAL;
+ }
+ static int uv_sculpt_stroke_modal(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       UvSculptData *data = (UvSculptData *)op->customdata;
+       Object *obedit = CTX_data_edit_object(C);
+       switch(event->type) {
+               case LEFTMOUSE:
+               case MIDDLEMOUSE:
+               case RIGHTMOUSE:
+                       uv_sculpt_stroke_exit(C, op);
+                       return OPERATOR_FINISHED;
+               case MOUSEMOVE:
+               case INBETWEEN_MOUSEMOVE:
+                       uv_sculpt_stroke_apply(C, op, event, obedit);
+                       break;
+               case TIMER:
+                       if(event->customdata == data->timer)
+                               uv_sculpt_stroke_apply(C, op, event, obedit);
+                       break;
+               default:
+                       return OPERATOR_RUNNING_MODAL;
+       }
+       ED_region_tag_redraw(CTX_wm_region(C));
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+       DAG_id_tag_update(obedit->data, 0);
+       return OPERATOR_RUNNING_MODAL;
+ }
+ void SCULPT_OT_uv_sculpt_stroke(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name = "Sculpt UVs";
+       ot->description = "Sculpt UVs using a brush";
+       ot->idname = "SCULPT_OT_uv_sculpt_stroke";
+       /* api callbacks */
+       ot->invoke = uv_sculpt_stroke_invoke;
+       ot->modal = uv_sculpt_stroke_modal;
+       ot->poll = uv_sculpt_poll;
+       /* flags */
+       ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+       /* props */
+       RNA_def_boolean(ot->srna, "invert", 0, "Invert", "Inverts the operator");
+       RNA_def_boolean(ot->srna, "temp_relax", 0, "Relax", "Relax Tool");
+ }
@@@ -468,6 -416,34 +465,36 @@@ static void draw_uvs_other(Scene *scene
        }
  }
  
 -              MFace *mface= me->mface;
 -              MTFace *tface= me->mtface;
 -              int a;
+ static void draw_uvs_texpaint(SpaceImage *sima, Scene *scene, Object *ob)
+ {
+       Mesh *me= ob->data;
+       Image *curimage = ED_space_image(sima);
+       if(sima->flag & SI_DRAW_OTHER)
+               draw_uvs_other(scene, ob, curimage);
+       glColor3ub(112, 112, 112);
+       if(me->mtface) {
 -              for(a=me->totface; a>0; a--, tface++, mface++) {
++              MPoly *mface= me->mpoly;
++              MTexPoly *tface= me->mtpoly;
++              MLoopUV *mloopuv;
++              int a, b;
 -                              glVertex2fv(tface->uv[0]);
 -                              glVertex2fv(tface->uv[1]);
 -                              glVertex2fv(tface->uv[2]);
 -                              if(mface->v4) glVertex2fv(tface->uv[3]);
++              for(a=me->totpoly; a>0; a--, tface++, mface++) {
+                       if(tface->tpage == curimage) {
+                               glBegin(GL_LINE_LOOP);
++
++                              mloopuv = me->mloopuv + mface->loopstart;
++                              for (b=0; b<mface->totloop; b++, mloopuv++) {
++                                      glVertex2fv(mloopuv->uv);
++                              }
+                               glEnd();
+                       }
+               }
+       }
+ }
  /* draws uv's in the image space */
  static void draw_uvs(SpaceImage *sima, Scene *scene, Object *obedit)
  {
        float pointsize;
        int drawfaces, interpedges;
        Image *ima= sima->image;
 -      StitchPreviewer *stitch_preview = uv_get_stitch_previewer();
  
 -      em= BKE_mesh_get_editmesh(me);
 -      activetf= EM_get_active_mtface(em, &efa_act, NULL, 0); /* will be set to NULL if hidden */
++#if 0 /* BMESH_TODO */
++      StitchPreviewer *stitch_preview = uv_get_stitch_previewer();
++#else
++      StitchPreviewer *stitch_preview = NULL;
++#endif
 +      em= me->edit_btmesh;
 +      activetf= EDBM_get_active_mtexpoly(em, &efa_act, 0); /* will be set to NULL if hidden */
 +      activef = BM_get_actFace(em->bm, 0);
        ts= scene->toolsettings;
  
        drawfaces= draw_uvs_face_check(scene);
                }
                
        }
-       
        /* 3. draw active face stippled */
  
 -      if(activetf) {
 +      if(activef) {
                glEnable(GL_BLEND);
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                UI_ThemeColor4(TH_EDITMESH_ACTIVE);
                bglEnd();       
        }
  
+       /* finally draw stitch preview */
+       if(stitch_preview) {
+               glPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
+               glEnableClientState(GL_VERTEX_ARRAY);
+               glEnable(GL_BLEND);
+               UI_ThemeColor4(TH_STITCH_PREVIEW_ACTIVE);
+               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_tris);
+               glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_static_tris*3);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->static_quads);
+               glDrawArrays(GL_QUADS, 0, stitch_preview->num_static_quads*4);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_tris);
+               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+               UI_ThemeColor4(TH_STITCH_PREVIEW_FACE);
+               glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris*3);
+               glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+               UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE);
+               glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris*3);
+               glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
+               /*UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
+               glDrawArrays(GL_TRIANGLES, 0, stitch_preview->num_tris*3);*/
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_quads);
+               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+               UI_ThemeColor4(TH_STITCH_PREVIEW_FACE);
+               glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);
+               glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+               UI_ThemeColor4(TH_STITCH_PREVIEW_EDGE);
+               glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);
+               glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);
+               /*UI_ThemeColor4(TH_STITCH_PREVIEW_VERT);
+               glDrawArrays(GL_QUADS, 0, stitch_preview->num_quads*4);*/
+               glDisable(GL_BLEND);
+               /* draw vert preview */
+               glPointSize(pointsize*2.0);
+               UI_ThemeColor4(TH_STITCH_PREVIEW_STITCHABLE);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_stitchable);
+               glDrawArrays(GL_POINTS, 0, stitch_preview->num_stitchable);
+               UI_ThemeColor4(TH_STITCH_PREVIEW_UNSTITCHABLE);
+               glVertexPointer(2, GL_FLOAT, 0, stitch_preview->preview_unstitchable);
+               glDrawArrays(GL_POINTS, 0, stitch_preview->num_unstitchable);
+               glPopClientAttrib();
+               glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+       }
        glPointSize(1.0);
 -      BKE_mesh_end_editmesh(obedit->data, em);
  }
  
- void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit)
+ void draw_uvedit_main(SpaceImage *sima, ARegion *ar, Scene *scene, Object *obedit, Object *obact)
  {
-       int show_uvedit, show_uvshadow;
+       ToolSettings *toolsettings = scene->toolsettings;
+       int show_uvedit, show_uvshadow, show_texpaint_uvshadow;
  
+       show_texpaint_uvshadow = (obact && obact->type == OB_MESH && obact->mode == OB_MODE_TEXTURE_PAINT);
        show_uvedit= ED_space_image_show_uvedit(sima, obedit);
        show_uvshadow= ED_space_image_show_uvshadow(sima, obedit);
  
  #ifndef ED_UVEDIT_INTERN_H
  #define ED_UVEDIT_INTERN_H
  
- struct SpaceImage;
+ struct EditFace;
+ struct EditMesh;
 +struct MTexPoly;
- struct Scene;
  struct Image;
+ struct MTFace;
  struct Object;
+ struct Scene;
+ struct SpaceImage;
+ struct UvElementMap;
  struct wmOperatorType;
 +struct BMEditMesh;
 +struct BMFace;
 +struct BMLoop;
 +struct BMEdge;
 +struct BMVert;
  
  /* id can be from 0 to 3 */
  #define TF_PIN_MASK(id) (TF_PIN1 << id)
  #define TF_SEL_MASK(id) (TF_SEL1 << id)
  
 +/* visibility and selection */
 +int uvedit_face_visible_nolocal(struct Scene *scene, struct BMFace *efa);
 +
  /* geometric utilities */
  void uv_center(float uv[][2], float cent[2], int quad);
  float uv_area(float uv[][2], int quad);
  void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy);
  
 -      struct EditFace *efa;
 -      struct MTFace *tf;
 -
 -      int vert, uv;
 -      int edge, vert2;
 +float poly_uv_area(float uv[][2], int len);
 +void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len);
 +void poly_uv_center(struct BMEditMesh *em, struct BMFace *f, float cent[2]);
 +
+ /* find nearest */
+ typedef struct NearestHit {
 -void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct EditMesh *em, float co[2], float penalty[2], struct NearestHit *hit);
 -void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct EditMesh *em, float co[2], struct NearestHit *hit);
++      struct BMFace *efa;
++      struct MTexPoly *tf;
++      struct BMLoop *l, *nextl;
++      struct MLoopUV *luv, *nextluv;
++      int lindex; //index of loop within face
++      int vert1, vert2; //index in mesh of edge vertices
+ } NearestHit;
 -struct UvElement *ED_get_uv_element(struct UvElementMap *map, struct EditFace *efa, int index);
++void uv_find_nearest_vert(struct Scene *scene, struct Image *ima, struct BMEditMesh *em, float co[2], float penalty[2], struct NearestHit *hit);
++void uv_find_nearest_edge(struct Scene *scene, struct Image *ima, struct BMEditMesh *em, float co[2], struct NearestHit *hit);
+ /* utility tool functions */
++struct UvElement *ED_get_uv_element(struct UvElementMap *map, struct BMFace *efa, int index);
+ void uvedit_live_unwrap_update(struct SpaceImage *sima, struct Scene *scene, struct Object *obedit);
+ /* smart stitch */
+ /* object that stores display data for previewing before accepting stitching */
+ typedef struct StitchPreviewer {
+       /* OpenGL requires different calls for Triangles and Quads.
+        * here we'll store the quads of the mesh */
+       float *preview_quads;
+       /* ...and here we'll store the triangles*/
+       float *preview_tris;
+       /* preview data. These will be either the previewed vertices or edges depending on stitch mode settings */
+       float *preview_stitchable;
+       float *preview_unstitchable;
+       /* here we'll store the number of triangles and quads to be drawn */
+       unsigned int num_tris;
+       unsigned int num_quads;
+       unsigned int num_stitchable;
+       unsigned int num_unstitchable;
+       /* store static island Quads */
+       float *static_quads;
+       /* ...and here we'll store the triangles*/
+       float *static_tris;
+       unsigned int num_static_tris;
+       unsigned int num_static_quads;
+ } StitchPreviewer;
+ StitchPreviewer *uv_get_stitch_previewer(void);
  /* operators */
  void UV_OT_average_islands_scale(struct wmOperatorType *ot);
  void UV_OT_cube_project(struct wmOperatorType *ot);
  void UV_OT_cylinder_project(struct wmOperatorType *ot);
@@@ -643,24 -549,13 +671,15 @@@ static int uvedit_center(Scene *scene, 
  
  /************************** find nearest ****************************/
  
- typedef struct NearestHit {
-       BMFace *efa;
-       MTexPoly *tf;
-       BMLoop *l, *nextl;
-       MLoopUV *luv, *nextluv;
-       int lindex; //index of loop within face
-       int vert1, vert2; //index in mesh of edge vertices
- } NearestHit;
- static void find_nearest_uv_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
 -void uv_find_nearest_edge(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
++void uv_find_nearest_edge(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
  {
 -      MTFace *tf;
 -      EditFace *efa;
 -      EditVert *eve;
 +      MTexPoly *tf;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MLoopUV *luv, *nextluv;
        float mindist, dist;
 -      int i, nverts;
 +      int i;
  
        mindist= 1e10f;
        memset(hit, 0, sizeof(*hit));
@@@ -710,32 -594,28 +729,32 @@@ static void find_nearest_uv_face(Scene 
  
        mindist= 1e10f;
        memset(hit, 0, sizeof(*hit));
 -      
 -      for(efa= em->faces.first; efa; efa= efa->next) {
 -              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
  
 -              if(uvedit_face_visible(scene, ima, efa, tf)) {
 -                      nverts= efa->v4? 4: 3;
 -                      cent[0]= cent[1]= 0.0f;
 +      /*this will fill in hit.vert1 and hit.vert2*/
-       find_nearest_uv_edge(scene, ima, em, co, hit);
++      uv_find_nearest_edge(scene, ima, em, co, hit);
 +      hit->l = hit->nextl = NULL;
 +      hit->luv = hit->nextluv = NULL;
  
 -                      for(i=0; i<nverts; i++) {
 -                              add_v2_v2(cent, tf->uv[i]);
 -                      }
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +              tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +              if(!uvedit_face_visible(scene, ima, efa, tf))
 +                      continue;
 +              
 +              cent[0]= cent[1]= 0.0f;
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  
 -                      cent[0] /= nverts;
 -                      cent[1] /= nverts;
 -                      dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
 +                      add_v2_v2(cent, luv->uv);
 +              }
  
 -                      if(dist < mindist) {
 -                              hit->tf= tf;
 -                              hit->efa= efa;
 -                              mindist= dist;
 -                      }
 +              cent[0] /= efa->len;
 +              cent[1] /= efa->len;
 +              dist= fabs(co[0]- cent[0]) + fabs(co[1]- cent[1]);
 +
 +              if(dist < mindist) {
 +                      hit->tf= tf;
 +                      hit->efa= efa;
 +                      mindist= dist;
                }
        }
  }
@@@ -786,21 -647,13 +805,21 @@@ static int nearest_uv_between(BMEditMes
        return (c1*c2 >= 0.0f);
  }
  
- static void find_nearest_uv_vert(Scene *scene, Image *ima, BMEditMesh *em,
-                                float co[2], float penalty[2], NearestHit *hit)
 -void uv_find_nearest_vert(Scene *scene, Image *ima, EditMesh *em, float co[2], float penalty[2], NearestHit *hit)
++void uv_find_nearest_vert(Scene *scene, Image *ima, BMEditMesh *em,
++                          float co[2], float penalty[2], NearestHit *hit)
  {
 -      EditFace *efa;
 -      EditVert *eve;
 -      MTFace *tf;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        float mindist, dist;
 -      int i, nverts;
 +      int i;
 +
 +      /*this will fill in hit.vert1 and hit.vert2*/
-       find_nearest_uv_edge(scene, ima, em, co, hit);
++      uv_find_nearest_edge(scene, ima, em, co, hit);
 +      hit->l = hit->nextl = NULL;
 +      hit->luv = hit->nextluv = NULL;
  
        mindist= 1e10f;
        memset(hit, 0, sizeof(*hit));
@@@ -918,10 -764,21 +937,31 @@@ static UvMapVert *uv_vertex_map_get(UvV
        return NULL;
  }
  
 -UvElement *ED_get_uv_element(UvElementMap *map, EditFace *efa, int index)
++/* BMESH_TODO - in some cases we already know the loop so looking up the index isnt needed */
++
++UvElement *ED_get_uv_element(UvElementMap *map, BMFace *efa, int index)
+ {
 -      UvElement *element = map->vert[(*(&efa->v1 + index))->tmp.l];
++      BMLoop *loop = efa->loops.first;
++      UvElement *element;
++
++      while (index >= 0) {
++              loop = loop->next;
++              index--;
++      }
++
++      element = map->vert[BM_GetIndex(loop->v)];
+       for(; element; element = element->next)
+               if(element->face == efa)
+                       return element;
+       return NULL;
+ }
 -static int uv_edge_tag_faces(UvMapVert *first1, UvMapVert *first2, int *totface)
 +static int uv_edge_tag_faces(BMEditMesh *em, UvMapVert *first1, UvMapVert *first2, int *totface)
  {
        UvMapVert *iterv1, *iterv2;
 -      EditFace *efa;
 +      BMFace *efa;
        int tot = 0;
  
        /* count number of faces this edge has */
@@@ -1536,173 -1321,6 +1576,176 @@@ static void UV_OT_weld(wmOperatorType *
        ot->poll= ED_operator_uvedit;
  }
  
++#if 0 // BMESH_TODO --- this function has been moved elsewhere
 +/* ******************** stitch operator **************** */
 +
 +/* just for averaging UVs */
 +typedef struct UVVertAverage {
 +      float uv[2];
 +      int count;
 +} UVVertAverage;
 +
 +static int stitch_exec(bContext *C, wmOperator *op)
 +{
 +      Scene *scene;
 +      Object *obedit;
 +      BMEditMesh *em;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      BMVert *eve;
 +      Image *ima;
 +      SpaceImage *sima= CTX_wm_space_image(C);
 +      MTexPoly *tf;
 +      MLoopUV *luv;
 +
 +      scene= CTX_data_scene(C);
 +      obedit= CTX_data_edit_object(C);
 +      em= ((Mesh*)obedit->data)->edit_btmesh;
 +      ima= CTX_data_edit_image(C);
 +      sima= CTX_wm_space_image(C);
 +      
 +      if(RNA_boolean_get(op->ptr, "use_limit")) {
 +              UvVertMap *vmap;
 +              UvMapVert *vlist, *iterv;
 +              float newuv[2], limit[2], pixels;
 +              int a, vtot;
 +
 +              pixels= RNA_float_get(op->ptr, "limit");
 +              uvedit_pixel_to_float(sima, limit, pixels);
 +
 +              EDBM_init_index_arrays(em, 0, 0, 1);
 +              vmap= EDBM_make_uv_vert_map(em, 1, 0, limit);
 +
 +              if(vmap == NULL) {
 +                      return OPERATOR_CANCELLED;
 +              }
 +              
 +              a = 0;
 +              BM_ITER(eve, &iter, em->bm, BM_VERTS_OF_MESH, NULL) {
 +                      vlist= EDBM_get_uv_map_vert(vmap, a);
 +
 +                      while(vlist) {
 +                              newuv[0]= 0; newuv[1]= 0;
 +                              vtot= 0;
 +
 +                              for(iterv=vlist; iterv; iterv=iterv->next) {
 +                                      if((iterv != vlist) && iterv->separate)
 +                                              break;
 +
 +                                      efa = EDBM_get_face_for_index(em, iterv->f);
 +                                      tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +                                      
 +                                      l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
 +                                      if (uvedit_uv_selected(em, scene, l)) {
 +                                              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +
 +                                              newuv[0] += luv->uv[0];
 +                                              newuv[1] += luv->uv[1];
 +                                              vtot++;
 +                                      }
 +                              }
 +
 +                              if(vtot > 1) {
 +                                      newuv[0] /= vtot; newuv[1] /= vtot;
 +
 +                                      for(iterv=vlist; iterv; iterv=iterv->next) {
 +                                              if((iterv != vlist) && iterv->separate)
 +                                                      break;
 +
 +                                              efa = EDBM_get_face_for_index(em, iterv->f);
 +                                              tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +                                              
 +                                              l = BMIter_AtIndex(em->bm, BM_LOOPS_OF_FACE, efa, iterv->tfindex);
 +                                              if (uvedit_uv_selected(em, scene, l)) {
 +                                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +
 +                                                      luv->uv[0] = newuv[0];
 +                                                      luv->uv[1] = newuv[1];
 +                                                      vtot++;
 +                                              }
 +                                      }
 +                              }
 +
 +                              vlist= iterv;
 +                      }
 +
 +                      a++;
 +              }
 +
 +              EDBM_free_uv_vert_map(vmap);
 +              EDBM_free_index_arrays(em);
 +      }
 +      else {
 +              UVVertAverage *uv_average, *uvav;
 +
 +              BM_ElemIndex_Ensure(em->bm, BM_VERT);
 +
 +              uv_average= MEM_callocN(sizeof(UVVertAverage)*em->bm->totvert, "Stitch");
 +              
 +              // gather uv averages per vert
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +                      if(!uvedit_face_visible(scene, ima, efa, tf))
 +                              continue;
 +                      
 +                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                              if(uvedit_uv_selected(em, scene, l)) {
 +                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                      uvav = uv_average + BM_GetIndex(l->v);
 +
 +                                      uvav->count++;
 +                                      uvav->uv[0] += luv->uv[0];
 +                                      uvav->uv[1] += luv->uv[1];
 +                              }
 +                      }
 +              }
 +              
 +              // apply uv welding
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +                      if(!uvedit_face_visible(scene, ima, efa, tf))
 +                              continue;
 +                      
 +                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                              if(uvedit_uv_selected(em, scene, l)) {
 +                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                      uvav = uv_average + BM_GetIndex(l->v);
 +                                      luv->uv[0] = uvav->uv[0]/uvav->count;
 +                                      luv->uv[1] = uvav->uv[1]/uvav->count;
 +                              }
 +                      }
 +              }
 +
 +              MEM_freeN(uv_average);
 +      }
 +
 +      uvedit_live_unwrap_update(sima, scene, obedit);
 +      DAG_id_tag_update(obedit->data, 0);
 +      WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
 +
 +      return OPERATOR_FINISHED;
 +}
 +
 +static void UV_OT_stitch(wmOperatorType *ot)
 +{
 +      /* identifiers */
 +      ot->name= "Stitch";
 +      ot->description= "Stitch selected UV vertices by proximity";
 +      ot->idname= "UV_OT_stitch";
 +      ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
 +      
 +      /* api callbacks */
 +      ot->exec= stitch_exec;
 +      ot->poll= ED_operator_uvedit;
 +
 +      /* properties */
 +      RNA_def_boolean(ot->srna, "use_limit", 1, "Use Limit", "Stitch UVs within a specified limit distance");
 +      RNA_def_float(ot->srna, "limit", 20.0, 0.0f, FLT_MAX, "Limit", "Limit distance in image pixels", -FLT_MAX, FLT_MAX);
 +}
 +
++#endif
++
  /* ******************** (de)select all operator **************** */
  
  static void select_all_perform(bContext *C, int action)
@@@ -1891,21 -1494,17 +1934,21 @@@ static int mouse_select(bContext *C, fl
        /* find nearest element */
        if(loop) {
                /* find edge */
-               find_nearest_uv_edge(scene, ima, em, co, &hit);
+               uv_find_nearest_edge(scene, ima, em, co, &hit);
                if(hit.efa == NULL) {
 -                      BKE_mesh_end_editmesh(obedit->data, em);
 +                      BLI_array_free(hitv);
 +                      BLI_array_free(hituv);
                        return OPERATOR_CANCELLED;
                }
 +
 +              hitlen = 0;
        }
        else if(selectmode == UV_SELECT_VERTEX) {
                /* find vertex */
-               find_nearest_uv_vert(scene, ima, em, co, penalty, &hit);
+               uv_find_nearest_vert(scene, ima, em, co, penalty, &hit);
                if(hit.efa == NULL) {
 -                      BKE_mesh_end_editmesh(obedit->data, em);
 +                      BLI_array_free(hitv);
 +                      BLI_array_free(hituv);
                        return OPERATOR_CANCELLED;
                }
  
        }
        else if(selectmode == UV_SELECT_EDGE) {
                /* find edge */
-               find_nearest_uv_edge(scene, ima, em, co, &hit);
+               uv_find_nearest_edge(scene, ima, em, co, &hit);
                if(hit.efa == NULL) {
 -                      BKE_mesh_end_editmesh(obedit->data, em);
 +                      BLI_array_free(hitv);
 +                      BLI_array_free(hituv);
                        return OPERATOR_CANCELLED;
                }
  
                }
                
                /* make active */
 -              EM_set_actFace(em, hit.efa);
 +              BM_set_actFace(em->bm, hit.efa);
  
                /* mark all face vertices as being hit */
 -              for(i=0; i<4; i++)
 -                      hituv[i]= hit.tf->uv[i];
 +              i = 0;
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, hit.efa) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  
 -              hitv[0]= hit.efa->v1->tmp.l;
 -              hitv[1]= hit.efa->v2->tmp.l;
 -              hitv[2]= hit.efa->v3->tmp.l;
 +                      BLI_array_growone(hitv);
 +                      BLI_array_growone(hituv);
 +                      hituv[i]= luv->uv;
 +                      hitv[i] = BM_GetIndex(l->v);
 +                      i++;
 +              }
                
 -              if(hit.efa->v4) hitv[3]= hit.efa->v4->tmp.l;
 -              else hitv[3]= 0xFFFFFFFF;
 +              hitlen = hit.efa->len;
        }
        else if(selectmode == UV_SELECT_ISLAND) {
-               find_nearest_uv_vert(scene, ima, em, co, NULL, &hit);
+               uv_find_nearest_vert(scene, ima, em, co, NULL, &hit);
  
                if(hit.efa==NULL) {
 -                      BKE_mesh_end_editmesh(obedit->data, em);
 +                      BLI_array_free(hitv);
 +                      BLI_array_free(hituv);
                        return OPERATOR_CANCELLED;
                }
 +
 +              hitlen = 0;
        }
        else {
 -              BKE_mesh_end_editmesh(obedit->data, em);
 +              hitlen = 0;
 +              BLI_array_free(hitv);
 +              BLI_array_free(hituv);
                return OPERATOR_CANCELLED;
        }
  
@@@ -3457,6 -3146,180 +3500,183 @@@ static void UV_OT_tile_set(wmOperatorTy
        RNA_def_int_vector(ot->srna, "tile", 2, NULL, 0, INT_MAX, "Tile", "Tile coordinate", 0, 10);
  }
  
 -      EditMesh *em;
 -      EditEdge *editedge;
+ static int seams_from_islands_exec(bContext *C, wmOperator *op)
+ {
+       UvVertMap *vmap;
+       Object *ob = CTX_data_edit_object(C);
+       Mesh *me= (Mesh*)ob->data;
 -      em = BKE_mesh_get_editmesh(me);
++      BMEditMesh *em;
++      BMEdge *editedge;
+       float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT};
+       char mark_seams = RNA_boolean_get(op->ptr, "mark_seams");
+       char mark_sharp = RNA_boolean_get(op->ptr, "mark_sharp");
 -      if(!EM_texFaceCheck(em)) {
 -              BKE_mesh_end_editmesh(ob->data, em);
++      BMesh *bm;
++      BMIter iter;
++
++      em = me->edit_btmesh;
++      bm = em->bm;
 -      EM_init_index_arrays(em, 0, 0, 1);
 -      vmap = EM_make_uv_vert_map(em, 0, 0, limit);
++      if(!EDBM_texFaceCheck(em)) {
+               return OPERATOR_CANCELLED;
+       }
+       /* This code sets editvert->tmp.l to the index. This will be useful later on. */
 -      for(editedge = em->edges.first; editedge; editedge = editedge->next) {
++      EDBM_init_index_arrays(em, 0, 0, 1);
++      vmap = EDBM_make_uv_vert_map(em, 0, 0, limit);
 -              EditFace *efa1, *efa2;
++      BM_ITER(editedge, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+               /* flags to determine if we uv is separated from first editface match */
+               char separated1 = 0, separated2;
+               /* set to denote edge must be flagged as seam */
+               char faces_separated = 0;
+               /* flag to keep track if uv1 is disconnected from first editface match */
+               char v1coincident = 1;
+               /* For use with v1coincident. v1coincident will change only if we've had commonFaces */
+               int commonFaces = 0;
 -              mvinit1 = vmap->vert[editedge->v1->tmp.l];
++              BMFace *efa1, *efa2;
+               UvMapVert *mv1, *mvinit1, *mv2, *mvinit2, *mviter;
+               /* mv2cache stores the first of the list of coincident uv's for later comparison
+                * mv2sep holds the last separator and is copied to mv2cache when a hit is first found */
+               UvMapVert *mv2cache = NULL, *mv2sep = NULL;
 -                      editedge->seam = 0;
++              mvinit1 = vmap->vert[BM_GetIndex(editedge->v1)];
+               if(mark_seams)
 -                      efa1 = EM_get_face_for_index(mv1->f);
 -                      mvinit2 = vmap->vert[editedge->v2->tmp.l];
++                      BM_ClearHFlag(editedge, BM_SEAM);
+               for(mv1 = mvinit1; mv1 && !faces_separated; mv1 = mv1->next) {
+                       if(mv1->separate && commonFaces)
+                               v1coincident = 0;
+                       separated2 = 0;
 -                              efa2 = EM_get_face_for_index(mv2->f);
++                      efa1 = EDBM_get_face_for_index(em, mv1->f);
++                      mvinit2 = vmap->vert[BM_GetIndex(editedge->v2)];
+                       for(mv2 = mvinit2; mv2; mv2 = mv2->next) {
+                               if(mv2->separate)
+                                       mv2sep = mv2;
 -                              editedge->seam = 1;
++                              efa2 = EDBM_get_face_for_index(em, mv2->f);
+                               if(efa1 == efa2) {
+                                       /* if v1 is not coincident no point in comparing */
+                                       if(v1coincident) {
+                                               /* have we found previously anything? */
+                                               if(mv2cache) {
+                                                       /* flag seam unless proved to be coincident with previous hit */
+                                                       separated2 = 1;
+                                                       for(mviter = mv2cache; mviter; mviter = mviter->next) {
+                                                               if(mviter->separate && mviter != mv2cache)
+                                                                       break;
+                                                               /* coincident with previous hit, do not flag seam */
+                                                               if(mviter == mv2)
+                                                                       separated2 = 0;
+                                                       }
+                                               }
+                                               /* First hit case, store the hit in the cache */
+                                               else {
+                                                       mv2cache = mv2sep;
+                                                       commonFaces = 1;
+                                               }
+                                       }
+                                       else
+                                               separated1 = 1;
+                                       if(separated1 || separated2) {
+                                               faces_separated = 1;
+                                               break;
+                                       }
+                               }
+                       }
+               }
+               if(faces_separated) {
+                       if(mark_seams)
 -                              editedge->sharp = 1;
++                              BM_SetHFlag(editedge, BM_SEAM);
+                       if(mark_sharp)
 -      EM_free_uv_vert_map(vmap);
 -      EM_free_index_arrays();
 -      BKE_mesh_end_editmesh(me, em);
++                              BM_SetHFlag(editedge, BM_SHARP);
+               }
+       }
+       me->drawflag |= ME_DRAWSEAMS;
 -      EditMesh *em= BKE_mesh_get_editmesh(me);
 -      EditFace *efa;
++      EDBM_free_uv_vert_map(vmap);
++      EDBM_free_index_arrays(em);
+       DAG_id_tag_update(&me->id, 0);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
+       return OPERATOR_FINISHED;
+ }
+ static void UV_OT_seams_from_islands(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Seams From Islands";
+       ot->description= "Set mesh seams according to island setup in the UV editor";
+       ot->idname= "UV_OT_seams_from_islands";
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       /* api callbacks */
+       ot->exec= seams_from_islands_exec;
+       ot->poll= ED_operator_uvedit;
+       RNA_def_boolean(ot->srna, "mark_seams", 1, "Mark Seams", "Mark boundary edges as seams");
+       RNA_def_boolean(ot->srna, "mark_sharp", 0, "Mark Sharp", "Mark boundary edges as sharp");
+ }
+ static int mark_seam_exec(bContext *C, wmOperator *UNUSED(op))
+ {
+       Object *ob = CTX_data_edit_object(C);
+       Scene *scene = CTX_data_scene(C);
+       Mesh *me= (Mesh*)ob->data;
 -      for(efa = em->faces.first; efa; efa = efa->next) {
 -              MTFace *mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -              int i, nverts = efa->v4? 4 : 3;
++      BMEditMesh *em= me->edit_btmesh;
++      BMesh *bm = em->bm;
++      BMFace *efa;
++      BMLoop *loop;
 -              for(i = 0; i < nverts; i++)
 -                      if(uvedit_edge_selected(scene, efa, mt, i))
 -                              (*(&efa->e1 + i))->seam = 1;
++      BMIter iter, liter;
 -      BKE_mesh_end_editmesh(me, em);
 -
++      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
++              BM_ITER(loop, &liter, bm, BM_LOOPS_OF_FACE, efa) {
++                      if(uvedit_edge_selected(em, scene, loop)) {
++                              BM_SetHFlag(loop, BM_SEAM);
++                      }
++              }
+       }
+       me->drawflag |= ME_DRAWSEAMS;
+       if(scene->toolsettings->edge_mode_live_unwrap)
+               ED_unwrap_lscm(scene, ob, FALSE);
+       DAG_id_tag_update(&me->id, 0);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, me);
+       return OPERATOR_FINISHED;
+ }
+ static void UV_OT_mark_seam(wmOperatorType *ot)
+ {
+       /* identifiers */
+       ot->name= "Mark Seams";
+       ot->description= "Mark selected UV edges as seams";
+       ot->idname= "UV_OT_mark_seam";
+       /* flags */
+       ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
+       /* api callbacks */
+       ot->exec= mark_seam_exec;
+       ot->poll= ED_operator_uvedit;
+ }
  /* ************************** registration **********************************/
  
  void ED_operatortypes_uvedit(void)
        WM_operatortype_append(UV_OT_snap_selected);
  
        WM_operatortype_append(UV_OT_align);
++#if 0 /* BMESH_TODO */
        WM_operatortype_append(UV_OT_stitch);
++#endif
+       WM_operatortype_append(UV_OT_seams_from_islands);
+       WM_operatortype_append(UV_OT_mark_seam);
        WM_operatortype_append(UV_OT_weld);
        WM_operatortype_append(UV_OT_pin);
  
index 0000000,38c8f5b..cc13954
mode 000000,100644..100644
--- /dev/null
@@@ -1,0 -1,1442 +1,1446 @@@
 -                      EM_free_uv_element_map(stitch_state->element_map);
++
++#if 0 /* BMESH TODO */
++
+ /*
+  * ***** 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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): Antony Riakiotakis.
+  *
+  * ***** END GPL LICENSE BLOCK *****
+  */
+ /** \file blender/editors/uvedit/uvedit_stitch.c
+  *  \ingroup eduv
+  */
+ #include <stdlib.h>
+ #include <string.h>
+ #include <math.h>
+ #include "MEM_guardedalloc.h"
+ #include "DNA_object_types.h"
+ #include "DNA_meshdata_types.h"
+ #include "DNA_scene_types.h"
+ #include "BLI_editVert.h"
+ #include "BLI_ghash.h"
+ #include "BLI_math.h"
+ #include "BLI_math_vector.h"
+ #include "BLI_string.h"
+ #include "BKE_context.h"
+ #include "BKE_customdata.h"
+ #include "BKE_depsgraph.h"
+ #include "BKE_mesh.h"
++#include "BKE_tessmesh.h"
+ #include "ED_mesh.h"
+ #include "ED_uvedit.h"
+ #include "ED_screen.h"
+ #include "RNA_access.h"
+ #include "RNA_define.h"
+ #include "WM_api.h"
+ #include "WM_types.h"
+ #include "UI_view2d.h"
+ #include "uvedit_intern.h"
+ /* ********************** smart stitch operator *********************** */
+ struct IslandStitchData;
+ /* This is a straightforward implementation, count the uv's in the island that will move and take the mean displacement/rotation and apply it to all
+  * elements of the island except from the stitchable */
+ typedef struct IslandStitchData{
+       /* rotation can be used only for edges, for vertices there is no such notion */
+       float rotation;
+       float translation[2];
+       /* Used for rotation, the island will rotate around this point */
+       float medianPoint[2];
+       int numOfElements;
+       int num_rot_elements;
+       /* Flag to remember if island has been added for preview */
+       char addedForPreview;
+       /* Flag an island to be considered for determining static island */
+       char stitchableCandidate;
+ }IslandStitchData;
+ /* just for averaging UVs */
+ typedef struct UVVertAverage {
+       float uv[2];
+       unsigned short count;
+ } UVVertAverage;
+ typedef struct UvEdge {
+       /* index to uv buffer */
+       unsigned int uv1;
+       unsigned int uv2;
+       /* general use flag (Used to check if edge is boundary here, and propagates to adjacency elements) */
+       char flag;
+       /* element that guarantees element->face has the face on element->tfindex and element->tfindex+1 is the second uv */
+       UvElement *element;
+ }UvEdge;
+ /* stitch state object */
+ typedef struct StitchState {
+       /* use limit flag */
+       char use_limit;
+       /* limit to operator, same as original operator */
+       float limit_dist;
+       /* snap uv islands together during stitching */
+       char snap_islands;
+       /* stich at midpoints or at islands */
+       char midpoints;
+       /* editmesh, cached for use in modal handler */
+       EditMesh *em;
+       /* element map for getting info about uv connectivity */
+       UvElementMap *element_map;
+       /* edge container */
+       UvEdge *uvedges;
+       /* container of first of a group of coincident uvs, these will be operated upon */
+       UvElement **uvs;
+       /* maps uvelements to their first coincident uv */
+       int *map;
+       /* 2D normals per uv to calculate rotation for snapping */
+       float *normals;
+       /* edge storage */
+       UvEdge *edges;
+       /* count of separate uvs and edges */
+       int total_boundary_edges;
+       int total_separate_uvs;
+       /* hold selection related information */
+       UvElement **selection_stack;
+       int selection_size;
+       /* island that stays in place */
+       int static_island;
+       /* store number of primitives per face so that we can allocate the active island buffer later */
+       unsigned int *quads_per_island;
+       unsigned int *tris_per_island;
+ } StitchState;
+ /*
+  * defines for UvElement flags
+  */
+ #define STITCH_SELECTED 1
+ #define STITCH_STITCHABLE 2
+ #define STITCH_PROCESSED 4
+ #define STITCH_BOUNDARY 8
+ #define STITCH_STITCHABLE_CANDIDATE 16
+ #define STITCH_NO_PREVIEW -1
+ /* previewer stuff (see uvedit_intern.h for more info) */
+ static StitchPreviewer *_stitch_preview;
+ /* constructor */
+ static StitchPreviewer * stitch_preview_init(void)
+ {
+       _stitch_preview = MEM_mallocN(sizeof(StitchPreviewer), "stitch_previewer");
+       _stitch_preview->preview_quads = NULL;
+       _stitch_preview->preview_tris = NULL;
+       _stitch_preview->preview_stitchable = NULL;
+       _stitch_preview->preview_unstitchable = NULL;
+       _stitch_preview->num_quads = 0;
+       _stitch_preview->num_tris = 0;
+       _stitch_preview->num_stitchable = 0;
+       _stitch_preview->num_unstitchable = 0;
+       _stitch_preview->static_quads = NULL;
+       _stitch_preview->static_tris = NULL;
+       _stitch_preview->num_static_tris = 0;
+       _stitch_preview->num_static_quads = 0;
+       return _stitch_preview;
+ }
+ /* destructor...yeah this should be C++ :) */
+ static void stitch_preview_delete(void)
+ {
+       if(_stitch_preview)
+       {
+               if(_stitch_preview->preview_quads){
+                       MEM_freeN(_stitch_preview->preview_quads);
+                       _stitch_preview->preview_quads = NULL;
+               }
+               if(_stitch_preview->preview_tris){
+                       MEM_freeN(_stitch_preview->preview_tris);
+                       _stitch_preview->preview_tris = NULL;
+               }
+               if(_stitch_preview->preview_stitchable){
+                       MEM_freeN(_stitch_preview->preview_stitchable);
+                       _stitch_preview->preview_stitchable = NULL;
+               }
+               if(_stitch_preview->preview_unstitchable){
+                       MEM_freeN(_stitch_preview->preview_unstitchable);
+                       _stitch_preview->preview_unstitchable = NULL;
+               }
+               if(_stitch_preview->static_quads){
+                       MEM_freeN(_stitch_preview->static_quads);
+                       _stitch_preview->static_quads = NULL;
+               }
+               if(_stitch_preview->static_tris){
+                       MEM_freeN(_stitch_preview->static_tris);
+                       _stitch_preview->static_tris = NULL;
+               }
+               MEM_freeN(_stitch_preview);
+               _stitch_preview = NULL;
+       }
+ }
+ /* "getter method" */
+ StitchPreviewer *uv_get_stitch_previewer(void)
+ {
+       return _stitch_preview;
+ }
+ #define HEADER_LENGTH 256
+ /* This function updates the header of the UV editor when the stitch tool updates its settings */
+ static void stitch_update_header(StitchState *stitch_state, bContext *C)
+ {
+       static char str[] = "(S)nap %s, (M)idpoints %s, (L)imit %.2f (Alt Wheel adjust) %s, Switch (I)sland, shift select vertices";
+       char msg[HEADER_LENGTH];
+       ScrArea *sa= CTX_wm_area(C);
+       if(sa) {
+               BLI_snprintf(msg, HEADER_LENGTH, str,
+                               stitch_state->snap_islands? "On" : "Off",
+                               stitch_state->midpoints? "On": "Off",
+                               stitch_state->limit_dist,
+                               stitch_state->use_limit? "On" : "Off");
+               ED_area_headerprint(sa, msg);
+       }
+ }
+ static int getNumOfIslandUvs(UvElementMap *elementMap, int island){
+       if(island == elementMap->totalIslands-1){
+               return elementMap->totalUVs - elementMap->islandIndices[island];
+       }else{
+               return elementMap->islandIndices[island+1] - elementMap->islandIndices[island];
+       }
+ }
+ static void stitch_uv_rotate(float rotation, float medianPoint[2], float uv[2]){
+       float uv_rotation_result[2];
+       uv[0] -= medianPoint[0];
+       uv[1] -= medianPoint[1];
+       uv_rotation_result[0] = cos(rotation)*uv[0] - sin(rotation)*uv[1];
+       uv_rotation_result[1] = sin(rotation)*uv[0] + cos(rotation)*uv[1];
+       uv[0] = uv_rotation_result[0] + medianPoint[0];
+       uv[1] = uv_rotation_result[1] + medianPoint[1];
+ }
+ /* calculate snapping for islands */
+ static void stitch_calculate_island_snapping(StitchState *state, StitchPreviewer *preview, IslandStitchData *island_stitch_data, int final){
+       int i;
+       EditFace *efa;
+       MTFace *mt;
+       UvElement *element;
+       for(i = 0; i <  state->element_map->totalIslands; i++){
+               if(island_stitch_data[i].addedForPreview){
+                       int numOfIslandUVs = 0, j;
+                       /* check to avoid divide by 0 */
+                       if(island_stitch_data[i].num_rot_elements>0){
+                               island_stitch_data[i].rotation /= island_stitch_data[i].num_rot_elements;
+                               island_stitch_data[i].medianPoint[0] /= island_stitch_data[i].numOfElements;
+                               island_stitch_data[i].medianPoint[1] /= island_stitch_data[i].numOfElements;
+                       }
+                       island_stitch_data[i].translation[0] /= island_stitch_data[i].numOfElements;
+                       island_stitch_data[i].translation[1] /= island_stitch_data[i].numOfElements;
+                       numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
+                       element = &state->element_map->buf[state->element_map->islandIndices[i]];
+                       for(j = 0; j < numOfIslandUVs; j++, element++){
+                               /* stitchable uvs have already been processed, don't process */
+                               if(!(element->flag & STITCH_PROCESSED)){
+                                       efa = element->face;
+                                       mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                                       if(final){
+                                               stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, mt->uv[element->tfindex]);
+                                               mt->uv[element->tfindex][0] += island_stitch_data[i].translation[0];
+                                               mt->uv[element->tfindex][1] += island_stitch_data[i].translation[1];
+                                       }
+                                       else if(efa->tmp.l != STITCH_NO_PREVIEW){
+                                               if(efa->v4){
+                                                       stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, &preview->preview_quads[efa->tmp.l + 2*element->tfindex]);
+                                                       preview->preview_quads[efa->tmp.l + 2*element->tfindex] += island_stitch_data[i].translation[0];
+                                                       preview->preview_quads[efa->tmp.l + 2*element->tfindex + 1] += island_stitch_data[i].translation[1];
+                                               }
+                                               else {
+                                                       stitch_uv_rotate(island_stitch_data[i].rotation, island_stitch_data[i].medianPoint, &preview->preview_tris[efa->tmp.l + 2*element->tfindex]);
+                                                       preview->preview_tris[efa->tmp.l + 2*element->tfindex]  += island_stitch_data[i].translation[0];
+                                                       preview->preview_tris[efa->tmp.l + 2*element->tfindex + 1] += island_stitch_data[i].translation[1];
+                                               }
+                                       }
+                               }
+                               /* cleanup */
+                               element->flag &= STITCH_SELECTED;
+                       }
+               }
+       }
+ }
+ static void stitch_island_calculate_edge_rotation(UvEdge *edge, StitchState *state, UVVertAverage *uv_average, unsigned int *uvfinal_map, IslandStitchData *island_stitch_data)
+ {
+       UvElement *element;
+       EditFace *efa;
+       MTFace *mt;
+       int nverts;
+       float uv1[2], uv2[2];
+       float edgecos, edgesin;
+       int index1, index2;
+       element = edge->element;
+       efa = element->face;
+       nverts = (efa->v4)? 4 : 3;
+       mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+       index1 = uvfinal_map[(*(&element->face->v1 + element->tfindex))->tmp.l];
+       index2 = uvfinal_map[(*(&element->face->v1 + (element->tfindex + 1)%nverts))->tmp.l];
+       /* the idea here is to take the directions of the edges and find the rotation between final and initial
+       * direction. This, using inner and outer vector products, gives the angle. Directions are differences so... */
+       uv1[0] = mt->uv[(element->tfindex + 1)%nverts][0] - mt->uv[element->tfindex][0];
+       uv1[1] = mt->uv[(element->tfindex + 1)%nverts][1] - mt->uv[element->tfindex][1];
+       uv2[0] = uv_average[index2].uv[0] - uv_average[index1].uv[0];
+       uv2[1] = uv_average[index2].uv[1] - uv_average[index1].uv[1];
+       normalize_v2(uv1);
+       normalize_v2(uv2);
+       edgecos = uv1[0]*uv2[0] + uv1[1]*uv2[1];
+       edgesin = uv1[0]*uv2[1] - uv2[0]*uv1[1];
+       island_stitch_data[element->island].num_rot_elements++;
+       island_stitch_data[element->island].rotation += (edgesin > 0)? acos(MAX2(-1.0, MIN2(1.0, edgecos))): -acos(MAX2(-1.0, MIN2(1.0, edgecos)));
+ }
+ static void stitch_island_calculate_vert_rotation(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data, char do_static)
+ {
+       float edgecos = 1, edgesin = 0;
+       int index;
+       UvElement *element_iter;
+       if((element->island == state->static_island) && !do_static)
+               return;
+       index = (*(&element->face->v1 + element->tfindex))->tmp.l;
+       element_iter = state->element_map->vert[index];
+       if(!do_static){
+               for(; element_iter; element_iter = element_iter->next){
+                       if((element_iter->separate) && (element_iter->flag & STITCH_STITCHABLE) &&
+                                       (element_iter != element) && (element_iter->island == state->static_island)
+                       ){
+                               int index_tmp1, index_tmp2;
+                               float normal[2];
+                               /* easily possible*/
+                               index_tmp1 = element_iter - state->element_map->buf;
+                               index_tmp1 = state->map[index_tmp1];
+                               index_tmp2 = element - state->element_map->buf;
+                               index_tmp2 = state->map[index_tmp2];
+                               negate_v2_v2(normal, state->normals + index_tmp2*2);
+                               edgecos = dot_v2v2(normal, state->normals + index_tmp1*2);
+                               edgesin = cross_v2v2(normal, state->normals + index_tmp1*2);
+                               break;
+                       }
+               }
+       }
+       island_stitch_data[element->island].num_rot_elements++;
+       island_stitch_data[element->island].rotation += (edgesin > 0)? acos(edgecos): -acos(edgecos);
+ }
+ static void stitch_state_delete(StitchState *stitch_state)
+ {
+       if(stitch_state){
+               if(stitch_state->element_map){
 -              state->element_map = EM_make_uv_element_map(state->em, 0, 1);
++                      EDBM_free_uv_element_map(stitch_state->element_map);
+               }
+               if(stitch_state->uvs){
+                       MEM_freeN(stitch_state->uvs);
+               }
+               if(stitch_state->selection_stack){
+                       MEM_freeN(stitch_state->selection_stack);
+               }
+               if(stitch_state->quads_per_island){
+                       MEM_freeN(stitch_state->quads_per_island);
+               }
+               if(stitch_state->tris_per_island){
+                       MEM_freeN(stitch_state->tris_per_island);
+               }
+               if(stitch_state->map){
+                       MEM_freeN(stitch_state->map);
+               }
+               if(stitch_state->normals){
+                       MEM_freeN(stitch_state->normals);
+               }
+               if(stitch_state->edges){
+                       MEM_freeN(stitch_state->edges);
+               }
+               MEM_freeN(stitch_state);
+       }
+ }
+ /* checks for remote uvs that may be stitched with a certain uv, flags them if stitchable. */
+ static void determine_uv_stitchability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){
+       int vert_index;
+       UvElement *element_iter;
+       float limit= state->limit_dist;
+       int do_limit = state->use_limit;
+       vert_index = (*(&element->face->v1 + element->tfindex))->tmp.l;
+       element_iter = state->element_map->vert[vert_index];
+       for(; element_iter; element_iter = element_iter->next){
+               if(element_iter->separate){
+                       if(element_iter == element){
+                               continue;
+                       }
+                       if(do_limit){
+                               MTFace *mtface_orig = CustomData_em_get(&state->em->fdata, element->face->data, CD_MTFACE);
+                               MTFace *mtface_iter = CustomData_em_get(&state->em->fdata, element_iter->face->data, CD_MTFACE);
+                               if(fabs(mtface_orig->uv[element->tfindex][0] - mtface_iter->uv[element_iter->tfindex][0]) < limit
+                                               && fabs(mtface_orig->uv[element->tfindex][1] - mtface_iter->uv[element_iter->tfindex][1]) < limit){
+                                       island_stitch_data[element_iter->island].stitchableCandidate = 1;
+                                       island_stitch_data[element->island].stitchableCandidate = 1;
+                                       element->flag |= STITCH_STITCHABLE_CANDIDATE;
+                               }
+                       }else{
+                               /* if no limit exists, then the mere existence of a separate uv means that the uv is stitchable */
+                               island_stitch_data[element_iter->island].stitchableCandidate = 1;
+                               island_stitch_data[element->island].stitchableCandidate = 1;
+                               element->flag |= STITCH_STITCHABLE_CANDIDATE;
+                       }
+               }
+       }
+ }
+ /* set preview buffer position of UV face in editface->tmp.l */
+ static void stitch_set_face_preview_buffer_position(EditFace *efa, StitchPreviewer *preview)
+ {
+       if(efa->tmp.l == STITCH_NO_PREVIEW)
+       {
+               if(efa->v4)
+               {
+                       efa->tmp.l = preview->num_quads*8;
+                       preview->num_quads++;
+               } else {
+                       efa->tmp.l = preview->num_tris*6;
+                       preview->num_tris++;
+               }
+       }
+ }
+ /* setup face preview for all coincident uvs and their faces */
+ static void stitch_setup_face_preview_for_uv_group(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){
+       StitchPreviewer *preview = uv_get_stitch_previewer();
+       /* static island does not change so returning immediately */
+       //if(state->snap_islands && !state->midpoints && state->static_island == element->island)
+       //      return;
+       if(state->snap_islands){
+               island_stitch_data[element->island].addedForPreview = 1;
+       }
+       do{
+               stitch_set_face_preview_buffer_position(element->face, preview);
+               element = element->next;
+       }while(element && !element->separate);
+ }
+ /* checks if uvs are indeed stitchable and registers so that they can be shown in preview */
+ static void stitch_validate_stichability(UvElement *element, StitchState *state, IslandStitchData *island_stitch_data){
+       UvElement *element_iter;
+       StitchPreviewer *preview;
+       preview = uv_get_stitch_previewer();
+       element_iter = state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l];
+       for(; element_iter; element_iter = element_iter->next){
+               if(element_iter->separate){
+                       if(element_iter == element)
+                               continue;
+                       if(state->use_limit){
+                               MTFace *mtface_orig = CustomData_em_get(&state->em->fdata, element->face->data, CD_MTFACE);
+                               MTFace *mtface_iter = CustomData_em_get(&state->em->fdata, element_iter->face->data, CD_MTFACE);
+                               if(fabs(mtface_orig->uv[element->tfindex][0] - mtface_iter->uv[element_iter->tfindex][0]) < state->limit_dist
+                                               && fabs(mtface_orig->uv[element->tfindex][1] - mtface_iter->uv[element_iter->tfindex][1]) < state->limit_dist){
+                                       if(((element_iter->island == state->static_island) || (element->island == state->static_island)) &&
+                                                       !((element_iter->island == element->island) && state->snap_islands)){
+                                               element->flag |= STITCH_STITCHABLE;
+                                               preview->num_stitchable++;
+                                               stitch_setup_face_preview_for_uv_group(element, state, island_stitch_data);
+                                               return;
+                                       }
+                               }
+                       }else{
+                               if(((element_iter->island == state->static_island) || (element->island == state->static_island)) &&
+                                               !((element_iter->island == element->island) && state->snap_islands)){
+                                       element->flag |= STITCH_STITCHABLE;
+                                       preview->num_stitchable++;
+                                       stitch_setup_face_preview_for_uv_group(element, state, island_stitch_data);
+                                       return;
+                               }
+                       }
+               }
+       }
+       /* this can happen if the uvs to be stitched are not on a stitchable island */
+       if(!(element->flag & STITCH_STITCHABLE)){
+               preview->num_unstitchable++;
+       }
+ }
+ /* main processing function. It calculates preview and final positions. */
+ static int stitch_process_data(StitchState *state, Scene *scene, int final)
+ {
+       int i;
+       StitchPreviewer *preview = uv_get_stitch_previewer();
+       IslandStitchData *island_stitch_data = NULL;
+       int previous_island = state->static_island;
+       EditFace *efa;
+       EditVert *ev;
+       UVVertAverage *final_position;
+       char stitch_midpoints = state->midpoints;
+       /* use vertex normals for snapping rotation */
+       char use_vert_normals = 1;
+       /* used to map uv indices to uvaverage indices for selection */
+       unsigned int *uvfinal_map;
+       /* cleanup previous preview */
+       stitch_preview_delete();
+       preview = stitch_preview_init();
+       if(preview == NULL)
+               return 0;
+       /* each face holds its position in the preview buffer in tmp. -1 is uninitialized */
+       for(efa = state->em->faces.first; efa; efa = efa->next){
+               efa->tmp.l = STITCH_NO_PREVIEW;
+       }
+       island_stitch_data = MEM_callocN(sizeof(*island_stitch_data)*state->element_map->totalIslands, "stitch_island_data");
+       if(!island_stitch_data){
+               return 0;
+       }
+       /* store Indices to editVerts. */
+       for(ev = state->em->verts.first, i = 0; ev; ev = ev->next, i++){
+               ev->tmp.l = i;
+       }
+       /*****************************************
+        *  First determine stitchability of uvs *
+        *****************************************/
+       for(i = 0; i < state->selection_size; i++){
+               UvElement *element = state->selection_stack[i];
+               determine_uv_stitchability(element, state, island_stitch_data);
+       }
+       /* set static island to one that is added for preview */
+       state->static_island %= state->element_map->totalIslands;
+       while(!(island_stitch_data[state->static_island].stitchableCandidate)){
+               state->static_island++;
+               state->static_island %= state->element_map->totalIslands;
+               /* this is entirely possible if for example limit stitching with no stitchable verts or no selection */
+               if(state->static_island == previous_island)
+                       break;
+       }
+       for(i = 0; i < state->selection_size; i++){
+               UvElement *element = state->selection_stack[i];
+               if(element->flag & STITCH_STITCHABLE_CANDIDATE){
+                       element->flag &= ~STITCH_STITCHABLE_CANDIDATE;
+                       stitch_validate_stichability(element, state, island_stitch_data);
+               }else{
+                       /* add to preview for unstitchable */
+                       preview->num_unstitchable++;
+               }
+       }
+       /*****************************************
+        *  Setup preview for stitchable islands *
+        *****************************************/
+       if(state->snap_islands){
+               for(i = 0; i <  state->element_map->totalIslands; i++){
+                       if(island_stitch_data[i].addedForPreview){
+                               int numOfIslandUVs = 0, j;
+                               UvElement *element;
+                               numOfIslandUVs = getNumOfIslandUvs(state->element_map, i);
+                               element = &state->element_map->buf[state->element_map->islandIndices[i]];
+                               for(j = 0; j < numOfIslandUVs; j++, element++){
+                                       stitch_set_face_preview_buffer_position(element->face, preview);
+                               }
+                       }
+               }
+       }
+       /*********************************************************************
+        * Setup the preview buffers and fill them with the appropriate data *
+        *********************************************************************/
+       if(!final){
+               unsigned int tricount = 0, quadcount = 0;
+               int stitchBufferIndex = 0, unstitchBufferIndex = 0;
+               /* initialize the preview buffers */
+               preview->preview_quads = (float *)MEM_mallocN(preview->num_quads*sizeof(float)*8, "quad_uv_stitch_prev");
+               preview->preview_tris = (float *)MEM_mallocN(preview->num_tris*sizeof(float)*6, "tri_uv_stitch_prev");
+               preview->preview_stitchable = (float *)MEM_mallocN(preview->num_stitchable*sizeof(float)*2, "stitch_preview_stichable_data");
+               preview->preview_unstitchable = (float *)MEM_mallocN(preview->num_unstitchable*sizeof(float)*2, "stitch_preview_unstichable_data");
+               preview->static_quads = (float *)MEM_mallocN(state->quads_per_island[state->static_island]*sizeof(float)*8, "static_island_preview_quads");
+               preview->static_tris = (float *)MEM_mallocN(state->tris_per_island[state->static_island]*sizeof(float)*6, "static_island_preview_tris");
+               preview->num_static_quads = state->quads_per_island[state->static_island];
+               preview->num_static_tris = state->tris_per_island[state->static_island];
+               /* will cause cancel and freeing of all data structures so OK */
+               if(!preview->preview_quads || !preview->preview_tris || !preview->preview_stitchable || !preview->preview_unstitchable){
+                       return 0;
+               }
+               /* copy data from MTFaces to the preview display buffers */
+               for(efa = state->em->faces.first; efa; efa = efa->next){
+                       MTFace *mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                       UvElement *element = ED_get_uv_element(state->element_map, efa, 0);
+                       if(element){
+                               if(efa->tmp.l != STITCH_NO_PREVIEW){
+                                       if(efa->v4) {
+                                               memcpy(preview->preview_quads+efa->tmp.l, &mt->uv[0][0], 8*sizeof(float));
+                                       } else {
+                                               memcpy(preview->preview_tris+efa->tmp.l, &mt->uv[0][0], 6*sizeof(float));
+                                       }
+                               }
+                               if(element->island == state->static_island){
+                                       if(efa->v4) {
+                                               memcpy(preview->static_quads + quadcount*8, &mt->uv[0][0], 8*sizeof(float));
+                                               quadcount++;
+                                       } else {
+                                               memcpy(preview->static_tris + tricount*6, &mt->uv[0][0], 6*sizeof(float));
+                                               tricount++;
+                                       }
+                               }
+                       }
+               }
+               /* fill the appropriate preview buffers */
+               for(i = 0; i < state->total_separate_uvs; i++){
+                       UvElement *element = (UvElement *)state->uvs[i];
+                       if(element->flag & STITCH_STITCHABLE){
+                               MTFace *mt;
+                               efa = element->face;
+                               mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                               preview->preview_stitchable[stitchBufferIndex*2] = mt->uv[element->tfindex][0];
+                               preview->preview_stitchable[stitchBufferIndex*2 + 1] = mt->uv[element->tfindex][1];
+                               stitchBufferIndex++;
+                       }
+                       else if(element->flag & STITCH_SELECTED){
+                               MTFace *mt;
+                               efa = element->face;
+                               mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                               preview->preview_unstitchable[unstitchBufferIndex*2] = mt->uv[element->tfindex][0];
+                               preview->preview_unstitchable[unstitchBufferIndex*2 + 1] = mt->uv[element->tfindex][1];
+                               unstitchBufferIndex++;
+                       }
+               }
+       }
+       /******************************************************
+        * Here we calculate the final coordinates of the uvs *
+        ******************************************************/
+       final_position = MEM_callocN(state->selection_size*sizeof(*final_position), "stitch_uv_average");
+       uvfinal_map = MEM_mallocN(state->em->totvert*sizeof(*uvfinal_map), "stitch_uv_final_map");
+       /* first pass, calculate final position for stitchable uvs of the static island */
+       for(i = 0; i < state->selection_size; i++){
+               UvElement *element = state->selection_stack[i];
+               if(element->flag & STITCH_STITCHABLE){
+                       UvElement *element_iter = state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l];
+                       uvfinal_map[(*(&element->face->v1 + element->tfindex))->tmp.l] = i;
+                       for(;element_iter; element_iter = element_iter->next){
+                               if(element_iter->flag & STITCH_STITCHABLE){
+                                       MTFace *mt;
+                                       efa = element_iter->face;
+                                       mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                                       if(stitch_midpoints){
+                                               final_position[i].uv[0] += mt->uv[element_iter->tfindex][0];
+                                               final_position[i].uv[1] += mt->uv[element_iter->tfindex][1];
+                                               final_position[i].count++;
+                                       }else if(element_iter->island == state->static_island){
+                                               final_position[i].uv[0] = mt->uv[element_iter->tfindex][0];
+                                               final_position[i].uv[1] = mt->uv[element_iter->tfindex][1];
+                                       }
+                               }
+                       }
+               }
+               if(stitch_midpoints){
+                       final_position[i].uv[0] /= final_position[i].count;
+                       final_position[i].uv[1] /= final_position[i].count;
+               }
+       }
+       /* second pass, calculate island rotation and translation before modifying any uvs */
+       if(state->snap_islands){
+               for(i = 0; i < state->selection_size; i++){
+                       UvElement *element = state->selection_stack[i];
+                       if(element->flag & STITCH_STITCHABLE){
+                               MTFace *mt;
+                               efa = element->face;
+                               mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                               /* accumulate each islands' translation from stitchable elements. it is important to do here
+                                * because in final pass MTFaces get modified and result is zero. */
+                               island_stitch_data[element->island].translation[0] += final_position[i].uv[0] - mt->uv[element->tfindex][0];
+                               island_stitch_data[element->island].translation[1] += final_position[i].uv[1] - mt->uv[element->tfindex][1];
+                               island_stitch_data[element->island].medianPoint[0] += mt->uv[element->tfindex][0];
+                               island_stitch_data[element->island].medianPoint[1] += mt->uv[element->tfindex][1];
+                               island_stitch_data[element->island].numOfElements++;
+                       }
+               }
+               /* only calculate rotation when an edge has been fully selected */
+               for(i = 0; i < state->total_boundary_edges; i++){
+                       UvEdge *edge = state->edges+i;
+                       if((state->uvs[edge->uv1]->flag & STITCH_STITCHABLE) && (state->uvs[edge->uv2]->flag & STITCH_STITCHABLE)){
+                               stitch_island_calculate_edge_rotation(edge, state, final_position, uvfinal_map, island_stitch_data);
+                               use_vert_normals = 0;
+                       }
+               }
+               if(use_vert_normals){
+                       for(i = 0; i < state->selection_size; i++){
+                               UvElement *element = state->selection_stack[i];
+                               if(element->flag & STITCH_STITCHABLE){
+                                       stitch_island_calculate_vert_rotation(element, state, island_stitch_data, 0);
+                               }
+                       }
+               }
+       }
+       /* third pass, propagate changes to stitchable uvs */
+       for(i = 0; i < state->selection_size; i++){
+               UvElement *element = state->selection_stack[i];
+               if(element->flag & STITCH_STITCHABLE){
+                       UvElement *element_iter = state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l];
+                       for(;element_iter;){
+                               /* determine if uv stitchable */
+                               if(element_iter->separate && element_iter->flag & STITCH_STITCHABLE){
+                                       MTFace *mt;
+                                       efa = element_iter->face;
+                                       mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                                       /* propagate to coincident uvs */
+                                       do{
+                                               efa = element_iter->face;
+                                               mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                                               element_iter->flag |= STITCH_PROCESSED;
+                                               /* either flush to preview or to the MTFace, if final */
+                                               if(final){
+                                                       mt->uv[element_iter->tfindex][0] = final_position[i].uv[0];
+                                                       mt->uv[element_iter->tfindex][1] = final_position[i].uv[1];
+                                                       uvedit_uv_select(scene, efa, mt, element_iter->tfindex);
+                                               }else if(efa->tmp.l != STITCH_NO_PREVIEW){
+                                                       if(efa->v4){
+                                                               *(preview->preview_quads+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0];
+                                                               *(preview->preview_quads+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1];
+                                                       }else{
+                                                               *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2) = final_position[i].uv[0];
+                                                               *(preview->preview_tris+efa->tmp.l + element_iter->tfindex*2 + 1) = final_position[i].uv[1];
+                                                       }
+                                               }
+                                               /* end of calculations, keep only the selection flag */
+                                               if( (!state->snap_islands) || ((!stitch_midpoints) && (element_iter->island == state->static_island))) {
+                                                       element_iter->flag &= STITCH_SELECTED;
+                                               }
+                                               element_iter = element_iter->next;
+                                       }while(element_iter && !element_iter->separate);
+                                       continue;
+                               }
+                               element_iter = element_iter->next;
+                       }
+               }
+       }
+       /* final pass, calculate Island translation/rotation if needed */
+       if(state->snap_islands){
+               stitch_calculate_island_snapping(state, preview, island_stitch_data, final);
+       }
+       MEM_freeN(final_position);
+       MEM_freeN(uvfinal_map);
+       MEM_freeN(island_stitch_data);
+       return 1;
+ }
+ /* Stitch hash initialisation functions */
+ static unsigned int   uv_edge_hash(const void *key){
+       UvEdge *edge = (UvEdge *)key;
+       return
+               BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv2)) +
+               BLI_ghashutil_inthash(SET_INT_IN_POINTER(edge->uv1));
+ }
+ static int uv_edge_compare(const void *a, const void *b){
+       UvEdge *edge1 = (UvEdge *)a;
+       UvEdge *edge2 = (UvEdge *)b;
+       if((edge1->uv1 == edge2->uv1) && (edge1->uv2 == edge2->uv2)){
+               return 0;
+       }
+       return 1;
+ }
+ /* Select all common uvs */
+ static void stitch_select_uv(UvElement *element, StitchState *stitch_state, int always_select)
+ {
+       /* This works due to setting of tmp in find nearest uv vert */
+       UvElement *element_iter;
+       UvElement **selection_stack = stitch_state->selection_stack;
+       element_iter = stitch_state->element_map->vert[(*(&element->face->v1 + element->tfindex))->tmp.l];
+       /* first deselect all common uvs */
+       for(; element_iter; element_iter = element_iter->next){
+               if(element_iter->separate){
+                       /* only separators go to selection */
+                       if(element_iter->flag & STITCH_SELECTED){
+                               int i;
+                               if(always_select)
+                                       continue;
+                               element_iter->flag &= ~STITCH_SELECTED;
+                               for(i = 0; i < stitch_state->selection_size; i++){
+                                       if(selection_stack[i] == element_iter){
+                                               (stitch_state->selection_size)--;
+                                               selection_stack[i] = selection_stack[stitch_state->selection_size];
+                                               break;
+                                       }
+                               }
+                       }else{
+                               element_iter->flag |= STITCH_SELECTED;
+                               selection_stack[(stitch_state->selection_size)++] = element_iter;
+                       }
+               }
+       }
+ }
+ static void stitch_calculate_edge_normal(EditMesh *em, UvEdge *edge, float *normal){
+       UvElement *element = edge->element;
+       EditFace *efa = element->face;
+       MTFace *mt = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
+       int nverts = efa->v4?4 : 3;
+       int index = index = (element->tfindex + 2)%nverts;
+       float tangent[2], internal[2];
+       sub_v2_v2v2(tangent, mt->uv[(element->tfindex + 1)%nverts],  mt->uv[element->tfindex]);
+       sub_v2_v2v2(internal, mt->uv[index],  mt->uv[element->tfindex]);
+       /* choose one of the normals */
+       normal[0] = tangent[1];
+       normal[1] = -tangent[0];
+       /* if normal points inside the face, invert */
+       if(dot_v2v2(normal, internal) > 0){
+               normal[0] = -tangent[1];
+               normal[1] = tangent[0];
+       }
+       normalize_v2(normal);
+ }
+ static int stitch_init(bContext *C, wmOperator *op)
+ {
+       /* for fast edge lookup... */
+       GHash *edgeHash;
+       /* ...and actual edge storage */
+       UvEdge *edges;
+       int total_edges;
+       /* maps uvelements to their first coincident uv */
+       int *map;
+       int counter = 0, i;
+       EditFace *efa;
+       EditMesh *em;
+       GHashIterator* ghi;
+       UvEdge *all_edges;
+       StitchState *state = MEM_mallocN(sizeof(StitchState), "stitch state");
+       Scene *scene = CTX_data_scene(C);
+       ToolSettings *ts = scene->toolsettings;
+       Object *obedit = CTX_data_edit_object(C);
+       op->customdata = state;
+       if(!state)
+               return 0;
+       /* initialize state */
+       state->use_limit = RNA_boolean_get(op->ptr, "use_limit");
+       state->limit_dist = RNA_float_get(op->ptr, "limit");
+       state->em = em = BKE_mesh_get_editmesh((Mesh*)obedit->data);
+       state->snap_islands = RNA_boolean_get(op->ptr, "snap_islands");
+       state->static_island = RNA_int_get(op->ptr, "static_island");
+       state->midpoints = RNA_boolean_get(op->ptr, "midpoint_snap");
+       /* in uv synch selection, all uv's are visible */
+       if(ts->uv_flag & UV_SYNC_SELECTION){
 -              state->element_map = EM_make_uv_element_map(state->em, 1, 1);
++              state->element_map = EDBM_make_uv_element_map(state->em, 0, 1);
+       }else{
 -
++              state->element_map = EDBM_make_uv_element_map(state->em, 1, 1);
+       }
+       if(!state->element_map){
+               stitch_state_delete(state);
+               return 0;
+       }
+       /* Entirely possible if redoing last operator that static island is bigger than total number of islands.
+        * This ensures we get no hang in the island checking code in stitch_process_data. */
+       state->static_island %= state->element_map->totalIslands;
+       /* Count 'unique' uvs */
+       for(i = 0; i < state->element_map->totalUVs; i++){
+               if(state->element_map->buf[i].separate){
+                       counter++;
+               }
+       }
+       /* Allocate the unique uv buffers */
+       state->uvs = MEM_mallocN(sizeof(*state->uvs)*counter, "uv_stitch_unique_uvs");
+       /* internal uvs need no normals but it is hard and slow to keep a map of
+        * normals only for boundary uvs, so allocating for all uvs */
+       state->normals = MEM_callocN(sizeof(*state->normals)*counter*2, "uv_stitch_normals");
+       state->total_separate_uvs = counter;
+       /* we can at most have totalUVs edges or uvs selected. Actually they are less, considering we store only
+        * unique uvs for processing but I am accounting for all bizarre cases, especially for edges, this way */
+       state->selection_stack = MEM_mallocN(sizeof(*state->selection_stack)*counter, "uv_stitch_selection_stack");
+       state->map = map = MEM_mallocN(sizeof(*map)*state->element_map->totalUVs, "uv_stitch_unique_map");
+       /* Allocate the edge stack */
+       edgeHash = BLI_ghash_new(uv_edge_hash, uv_edge_compare, "stitch_edge_hash");
+       all_edges = MEM_mallocN(sizeof(*all_edges)*state->element_map->totalUVs, "stitch_all_edges");
+       if(!state->selection_stack || !state->uvs || !map || !edgeHash || !all_edges){
+               stitch_state_delete(state);
+               return 0;
+       }
+       /* So that we can use this as index for the UvElements */
+       counter = -1;
+       /* initialize the unique UVs and map */
+       for(i = 0; i < state->em->totvert; i++){
+               UvElement *element = state->element_map->vert[i];
+               for(; element; element = element->next){
+                       if(element->separate){
+                               counter++;
+                               state->uvs[counter] = element;
+                       }
+                       /* pointer arithmetic to the rescue, as always :)*/
+                       map[element - state->element_map->buf] = counter;
+               }
+       }
+       /* Now, on to generate our uv connectivity data */
+       for(efa = state->em->faces.first, counter = 0; efa; efa = efa->next){
+               if((ts->uv_flag & UV_SYNC_SELECTION) || (!efa->h && efa->f & SELECT)){
+                       int nverts = efa->v4 ? 4 : 3;
+                       for(i = 0; i < nverts; i++){
+                               UvElement *element = ED_get_uv_element(state->element_map, efa, i);
+                               int offset1, itmp1 = element - state->element_map->buf;
+                               int offset2, itmp2 = ED_get_uv_element(state->element_map, efa, (i+1)%nverts) - state->element_map->buf;
+                               offset1 = map[itmp1];
+                               offset2 = map[itmp2];
+                               all_edges[counter].flag = 0;
+                               all_edges[counter].element = element;
+                               /* using an order policy, sort uvs according to address space. This avoids
+                                * Having two different UvEdges with the same uvs on different positions  */
+                               if(offset1 < offset2){
+                                       all_edges[counter].uv1 = offset1;
+                                       all_edges[counter].uv2 = offset2;
+                               }
+                               else{
+                                       all_edges[counter].uv1 = offset2;
+                                       all_edges[counter].uv2 = offset1;
+                               }
+                               if(BLI_ghash_haskey(edgeHash, &all_edges[counter])){
+                                       char *flag = BLI_ghash_lookup(edgeHash, &all_edges[counter]);
+                                       *flag = 0;
+                               }
+                               else{
+                                       BLI_ghash_insert(edgeHash, &all_edges[counter], &(all_edges[counter].flag));
+                                       all_edges[counter].flag = STITCH_BOUNDARY;
+                               }
+                               counter++;
+                       }
+               }
+       }
+       ghi = BLI_ghashIterator_new(edgeHash);
+       total_edges = 0;
+       /* fill the edges with data */
+       for(i = 0; !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)){
+               UvEdge *edge = ((UvEdge *)BLI_ghashIterator_getKey(ghi));
+               if(edge->flag & STITCH_BOUNDARY){
+                       total_edges++;
+               }
+       }
+       state->edges = edges = MEM_mallocN(sizeof(*edges)*total_edges, "stitch_edges");
+       if(!ghi || !edges){
+               MEM_freeN(all_edges);
+               stitch_state_delete(state);
+               return 0;
+       }
+       state->total_boundary_edges = total_edges;
+       /* fill the edges with data */
+       for(i = 0, BLI_ghashIterator_init(ghi, edgeHash); !BLI_ghashIterator_isDone(ghi); BLI_ghashIterator_step(ghi)){
+               UvEdge *edge = ((UvEdge *)BLI_ghashIterator_getKey(ghi));
+               if(edge->flag & STITCH_BOUNDARY){
+                       edges[i++] = *((UvEdge *)BLI_ghashIterator_getKey(ghi));
+               }
+       }
+       /* cleanup temporary stuff */
+       BLI_ghashIterator_free(ghi);
+       MEM_freeN(all_edges);
+       /* refill hash with new pointers to cleanup duplicates */
+       BLI_ghash_free(edgeHash, NULL, NULL);
+       /***** calculate 2D normals for boundary uvs *****/
+       /* we use boundary edges to calculate 2D normals.
+        * to disambiguate the direction of the normal, we also need
+        * a point "inside" the island, that can be provided by
+        * the opposite uv for a quad, or the next uv for a triangle. */
+       for(i = 0; i < total_edges; i++){
+               float normal[2];
+               stitch_calculate_edge_normal(em, edges + i, normal);
+               add_v2_v2(state->normals + edges[i].uv1*2, normal);
+               add_v2_v2(state->normals + edges[i].uv2*2, normal);
+               normalize_v2(state->normals + edges[i].uv1*2);
+               normalize_v2(state->normals + edges[i].uv2*2);
+       }
+       /***** fill selection stack *******/
+       state->selection_size = 0;
+       /* Load old selection if redoing operator with different settings */
+       if(RNA_struct_property_is_set(op->ptr, "selection")){
+               int faceIndex, elementIndex;
+               UvElement *element;
+               EM_init_index_arrays(em, 0, 0, 1);
+                       RNA_BEGIN(op->ptr, itemptr, "selection") {
+                               faceIndex = RNA_int_get(&itemptr, "face_index");
+                               elementIndex = RNA_int_get(&itemptr, "element_index");
+                               efa = EM_get_face_for_index(faceIndex);
+                               element = ED_get_uv_element(state->element_map, efa, elementIndex);
+                               stitch_select_uv(element, state, 1);
+                       }
+                       RNA_END;
+               EM_free_index_arrays();
+               /* Clear the selection */
+               RNA_collection_clear(op->ptr, "selection");
+       } else {
+               for(efa = state->em->faces.first ; efa; efa = efa->next){
+                       int numOfVerts;
+                       MTFace *mt;
+                       mt = CustomData_em_get(&state->em->fdata, efa->data, CD_MTFACE);
+                       numOfVerts = efa->v4 ? 4 : 3;
+                       for(i = 0; i < numOfVerts; i++){
+                               if(uvedit_uv_selected(scene, efa, mt, i)){
+                                       UvElement *element = ED_get_uv_element(state->element_map, efa, i);
+                                       stitch_select_uv(element, state, 1);
+                               }
+                       }
+               }
+       }
+       /***** initialise static island preview data *****/
+       state->quads_per_island = MEM_mallocN(sizeof(*state->quads_per_island)*state->element_map->totalIslands,
+                       "stitch island quads");
+       state->tris_per_island = MEM_mallocN(sizeof(*state->tris_per_island)*state->element_map->totalIslands,
+                       "stitch island tris");
+       for(i = 0; i < state->element_map->totalIslands; i++){
+               state->quads_per_island[i] = 0;
+               state->tris_per_island[i] = 0;
+       }
+       for(efa = state->em->faces.first; efa; efa = efa->next){
+               UvElement *element = ED_get_uv_element(state->element_map, efa, 0);
+               if(element){
+                       if(efa->v4){
+                               state->quads_per_island[element->island]++;
+                       }
+                       else {
+                               state->tris_per_island[element->island]++;
+                       }
+               }
+       }
+       if(!stitch_process_data(state, scene, 0)){
+               stitch_state_delete(state);
+               return 0;
+       }
+       stitch_update_header(state, C);
+       return 1;
+ }
+ static int stitch_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
+ {
+       Object *obedit = CTX_data_edit_object(C);
+       if(!stitch_init(C, op))
+               return OPERATOR_CANCELLED;
+       WM_event_add_modal_handler(C, op);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+       return OPERATOR_RUNNING_MODAL;
+ }
+ static void stitch_exit(bContext *C, wmOperator *op, int finished)
+ {
+       StitchState *stitch_state;
+       Scene *scene;
+       SpaceImage *sima;
+       ScrArea *sa= CTX_wm_area(C);
+       Object *obedit;
+       scene= CTX_data_scene(C);
+       obedit= CTX_data_edit_object(C);
+       sima= CTX_wm_space_image(C);
+       stitch_state = (StitchState *)op->customdata;
+       if(finished){
+               EditFace *efa;
+               int i;
+               RNA_float_set(op->ptr, "limit", stitch_state->limit_dist);
+               RNA_boolean_set(op->ptr, "use_limit", stitch_state->use_limit);
+               RNA_boolean_set(op->ptr, "snap_islands", stitch_state->snap_islands);
+               RNA_int_set(op->ptr, "static_island", stitch_state->static_island);
+               RNA_boolean_set(op->ptr, "midpoint_snap", stitch_state->midpoints);
+               for(i = 0, efa = stitch_state->em->faces.first; efa; efa = efa->next, i++){
+                       efa->tmp.l = i;
+               }
+               /* Store selection for re-execution of stitch */
+               for(i = 0; i < stitch_state->selection_size; i++){
+                       PointerRNA itemptr;
+                       UvElement *element = stitch_state->selection_stack[i];
+                       RNA_collection_add(op->ptr, "selection", &itemptr);
+                       RNA_int_set(&itemptr, "face_index", element->face->tmp.l);
+                       RNA_int_set(&itemptr, "element_index", element->tfindex);
+               }
+               uvedit_live_unwrap_update(sima, scene, obedit);
+       }
+       if(sa)
+               ED_area_headerprint(sa, NULL);
+       DAG_id_tag_update(obedit->data, 0);
+       WM_event_add_notifier(C, NC_GEOM|ND_DATA, obedit->data);
+       BKE_mesh_end_editmesh(obedit->data, stitch_state->em);
+       stitch_state_delete(stitch_state);
+       op->customdata = NULL;
+       stitch_preview_delete();
+ }
+ static int stitch_cancel(bContext *C, wmOperator *op)
+ {
+       stitch_exit(C, op, 0);
+       return OPERATOR_CANCELLED;
+ }
+ static int stitch_exec(bContext *C, wmOperator *op)
+ {
+       Scene *scene = CTX_data_scene(C);
+       if(!stitch_init(C, op))
+               return OPERATOR_CANCELLED;
+       if(stitch_process_data((StitchState *)op->customdata, scene, 1)){
+               stitch_exit(C, op, 1);
+               return OPERATOR_FINISHED;
+       }else {
+               return stitch_cancel(C, op);
+       }
+ }
+ static void stitch_select(bContext *C, Scene *scene, wmEvent *event, StitchState *stitch_state){
+       /* add uv under mouse to processed uv's */
+       float co[2];
+       NearestHit hit;
+       ARegion *ar= CTX_wm_region(C);
+       Image *ima= CTX_data_edit_image(C);
+       UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &co[0], &co[1]);
+       uv_find_nearest_vert(scene, ima, stitch_state->em, co, NULL, &hit);
+       if(hit.efa)
+       {
+               /* Add vertex to selection, deselect all common uv's of vert other
+                * than selected and update the preview. This behavior was decided so that
+                * you can do stuff like deselect the opposite stitchable vertex and the initial still gets deselected */
+               /* This works due to setting of tmp in find nearest uv vert */
+               UvElement *element = ED_get_uv_element(stitch_state->element_map, hit.efa, hit.uv);
+               stitch_select_uv(element, stitch_state, 0);
+       }
+ }
+ static int stitch_modal(bContext *C, wmOperator *op, wmEvent *event)
+ {
+       StitchState *stitch_state;
+       Scene *scene = CTX_data_scene(C);
+       stitch_state = (StitchState *)op->customdata;
+       switch(event->type){
+               case MIDDLEMOUSE:
+                       return OPERATOR_PASS_THROUGH;
+               /* Cancel */
+               case ESCKEY:
+                       return stitch_cancel(C, op);
+               case LEFTMOUSE:
+                       if(event->shift && (U.flag & USER_LMOUSESELECT)){
+                               if(event->val == KM_RELEASE){
+                                       stitch_select(C, scene, event, stitch_state);
+                                       if(!stitch_process_data(stitch_state, scene, 0)){
+                                               return stitch_cancel(C, op);
+                                       }
+                               }
+                               break;
+                       }
+               case PADENTER:
+               case RETKEY:
+                       if(stitch_process_data(stitch_state, scene, 1)){
+                               stitch_exit(C, op, 1);
+                               return OPERATOR_FINISHED;
+                       }
+                       else {
+                               return stitch_cancel(C, op);
+                       }
+               /* Increase limit */
+               case PADPLUSKEY:
+               case WHEELUPMOUSE:
+                       if(event->alt){
+                               stitch_state->limit_dist += 0.01;
+                               if(!stitch_process_data(stitch_state, scene, 0)){
+                                       return stitch_cancel(C, op);
+                               }
+                               break;
+                       }
+                       else{
+                               return OPERATOR_PASS_THROUGH;
+                       }
+               /* Decrease limit */
+               case PADMINUS:
+               case WHEELDOWNMOUSE:
+                       if(event->alt){
+                               stitch_state->limit_dist -= 0.01;
+                               stitch_state->limit_dist = MAX2(0.01, stitch_state->limit_dist);
+                               if(!stitch_process_data(stitch_state, scene, 0)){
+                                       return stitch_cancel(C, op);
+                               }
+                               break;
+                       }else{
+                               return OPERATOR_PASS_THROUGH;
+                       }
+               /* Use Limit (Default off)*/
+               case LKEY:
+                       if(event->val == KM_PRESS){
+                               stitch_state->use_limit = !stitch_state->use_limit;
+                               if(!stitch_process_data(stitch_state, scene, 0)){
+                                       return stitch_cancel(C, op);
+                               }
+                               break;
+                       }
+                       return OPERATOR_RUNNING_MODAL;
+               case IKEY:
+                       if(event->val == KM_PRESS){
+                               stitch_state->static_island++;
+                               stitch_state->static_island %= stitch_state->element_map->totalIslands;
+                               if(!stitch_process_data(stitch_state, scene, 0)){
+                                       return stitch_cancel(C, op);
+                               }
+                               break;
+                       }
+                       return OPERATOR_RUNNING_MODAL;
+               case MKEY:
+                       if(event->val == KM_PRESS){
+                               stitch_state->midpoints = !stitch_state->midpoints;
+                               if(!stitch_process_data(stitch_state, scene, 0)){
+                                       return stitch_cancel(C, op);
+                               }
+                       }
+                       break;
+               /* Select geometry*/
+               case RIGHTMOUSE:
+                       if(!event->shift){
+                                       return stitch_cancel(C, op);
+                       }
+                       if(event->val == KM_RELEASE && !(U.flag & USER_LMOUSESELECT)){
+                               stitch_select(C, scene, event, stitch_state);
+                               if(!stitch_process_data(stitch_state, scene, 0)){
+                                       return stitch_cancel(C, op);
+                               }
+                               break;
+                       }
+                       return OPERATOR_RUNNING_MODAL;
+               /* snap islands on/off */
+               case SKEY:
+                       if(event->val == KM_PRESS){
+                               stitch_state->snap_islands = !stitch_state->snap_islands;
+                               if(!stitch_process_data(stitch_state, scene, 0)){
+                                       return stitch_cancel(C, op);
+                               }
+                               break;
+                       } else
+                       return OPERATOR_RUNNING_MODAL;
+               default:
+                       return OPERATOR_RUNNING_MODAL;
+       }
+       /* if updated settings, renew feedback message */
+       stitch_update_header(stitch_state, C);
+       ED_region_tag_redraw(CTX_wm_region(C));
+       return OPERATOR_RUNNING_MODAL;
+ }
+ void UV_OT_stitch(wmOperatorType *ot)
+ {
+       PropertyRNA *prop;
+       /* identifiers */
+       ot->name = "Stitch";
+       ot->description = "Stitch selected UV vertices by proximity";
+       ot->idname = "UV_OT_stitch";
+       ot->flag = OPTYPE_REGISTER|OPTYPE_UNDO;
+       
+       /* api callbacks */
+       ot->invoke = stitch_invoke;
+       ot->modal = stitch_modal;
+       ot->exec = stitch_exec;
+       ot->cancel = stitch_cancel;
+       ot->poll= ED_operator_uvedit;
+       /* properties */
+       RNA_def_boolean(ot->srna, "use_limit", 0, "Use Limit", "Stitch UVs within a specified limit distance");
+       RNA_def_boolean(ot->srna, "snap_islands", 1, "Snap Islands", "Snap islands together. On edge stitch mode, rotates the islands too");
+       RNA_def_float(ot->srna, "limit", 0.01f, 0.0f, FLT_MAX, "Limit", "Limit distance in normalized coordinates", 0.0, FLT_MAX);
+       RNA_def_int(ot->srna, "static_island", 0, 0, INT_MAX, "Static Island",  "Island that stays in place when stitching islands", 0, INT_MAX);
+       RNA_def_boolean(ot->srna, "midpoint_snap", 0, "Snap At Midpoint", "Uv's are stitched at midpoint instead of at static island");
+       prop = RNA_def_collection_runtime(ot->srna, "selection", &RNA_SelectedUvElement, "Selection", "");
+       /* Selection should not be editable or viewed in toolbar */
+       RNA_def_property_flag(prop, PROP_HIDDEN);
+ }
++#endif /* BMESH TODO */
  #include "DNA_meshdata_types.h"
  #include "DNA_object_types.h"
  #include "DNA_scene_types.h"
+ #include "DNA_modifier_types.h"
  
 +#include "BLI_utildefines.h"
  #include "BLI_math.h"
  #include "BLI_edgehash.h"
  #include "BLI_editVert.h"
  #include "BLI_uvproject.h"
  #include "BLI_utildefines.h"
 +#include "BLI_rand.h"
  #include "BLI_string.h"
  
+ #include "BKE_cdderivedmesh.h"
+ #include "BKE_subsurf.h"
  #include "BKE_context.h"
  #include "BKE_customdata.h"
  #include "BKE_depsgraph.h"
  #include "BKE_image.h"
  #include "BKE_main.h"
  #include "BKE_mesh.h"
+ #include "BKE_report.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "BLI_math.h"
 +#include "BLI_edgehash.h"
 +#include "BLI_editVert.h"
 +#include "BLI_scanfill.h"
 +#include "BLI_array.h"
 +#include "BLI_uvproject.h"
  
  #include "PIL_time.h"
  
@@@ -318,6 -276,201 +322,215 @@@ static ParamHandle *construct_param_han
        return handle;
  }
  
 -
++#if 0 /* BMESH_TODO */
+ static void texface_from_original_index(EditFace *editFace, MTFace *texFace, int index, float **uv, ParamBool *pin, ParamBool *select, Scene *scene)
+ {
+       int i, nverts = (editFace->v4)? 4: 3;
+       *uv = NULL;
+       *pin = 0;
+       *select = 1;
+       if(index == ORIGINDEX_NONE)
+               return;
+       for(i = 0; i < nverts; i++) {
+               if((*(&editFace->v1 + i))->tmp.t == index) {
+                       *uv = texFace->uv[i];
+                       *pin = ((texFace->unwrap & TF_PIN_MASK(i)) != 0);
+                       *select = (uvedit_uv_selected(scene, editFace, texFace, i) != 0);
+               }
+       }
+ }
+ /* unwrap handle initialization for subsurf aware-unwrapper. The many modifications required to make the original function(see above)
+  * work justified the existence of a new function. */
+ static ParamHandle *construct_param_handle_subsurfed(Scene *scene, EditMesh *editMesh, short fill, short sel, short correct_aspect)
+ {
+       ParamHandle *handle;
+       /* index pointers */
+       MFace *face;
+       MEdge *edge;
+       EditVert *editVert;
+       MTFace *texface;
+       EditFace *editFace, **editFaceTmp;
+       EditEdge *editEdge, **editEdgeTmp;
+       int i;
+       /* modifier initialization data, will  control what type of subdivision will happen*/
+       SubsurfModifierData smd = {{0}};
+       /* Used to hold subsurfed Mesh */
+       DerivedMesh *derivedMesh, *initialDerived;
+       /* holds original indices for subsurfed mesh */
+       int *origVertIndices, *origFaceIndices, *origEdgeIndices;
+       /* Holds vertices of subsurfed mesh */
+       MVert *subsurfedVerts;
+       MEdge *subsurfedEdges;
+       MFace *subsurfedFaces;
+       MTFace *subsurfedTexfaces;
+       /* number of vertices and faces for subsurfed mesh*/
+       int numOfEdges, numOfFaces;
+       /* holds a map to editfaces for every subsurfed MFace. These will be used to get hidden/ selected flags etc. */
+       EditFace **faceMap;
+       /* Mini container to hold all EditFaces so that they may be indexed easily and fast. */
+       EditFace **editFaceArray;
+       /* similar to the above, we need a way to map edges to their original ones */
+       EditEdge **edgeMap;
+       EditEdge **editEdgeArray;
+       handle = param_construct_begin();
+       if(correct_aspect) {
+               EditFace *eface = EM_get_actFace(editMesh, 1);
+               if(eface) {
+                       float aspx, aspy;
+                       texface= CustomData_em_get(&editMesh->fdata, eface->data, CD_MTFACE);
+                       ED_image_uv_aspect(texface->tpage, &aspx, &aspy);
+               
+                       if(aspx!=aspy)
+                               param_aspect_ratio(handle, aspx, aspy);
+               }
+       }
+       /* number of subdivisions to perform */
+       smd.levels = scene->toolsettings->uv_subsurf_level;
+       smd.subdivType = ME_CC_SUBSURF;
+               
+       initialDerived = CDDM_from_editmesh(editMesh, NULL);
+       derivedMesh = subsurf_make_derived_from_derived(initialDerived, &smd,
+               0, NULL, 0, 0, 1);
+       initialDerived->release(initialDerived);
+       /* get the derived data */
+       subsurfedVerts = derivedMesh->getVertArray(derivedMesh);
+       subsurfedEdges = derivedMesh->getEdgeArray(derivedMesh);
+       subsurfedFaces = derivedMesh->getFaceArray(derivedMesh);
+       origVertIndices = derivedMesh->getVertDataArray(derivedMesh, CD_ORIGINDEX);
+       origEdgeIndices = derivedMesh->getEdgeDataArray(derivedMesh, CD_ORIGINDEX);
+       origFaceIndices = derivedMesh->getFaceDataArray(derivedMesh, CD_ORIGINDEX);
+       subsurfedTexfaces = derivedMesh->getFaceDataArray(derivedMesh, CD_MTFACE);
+       numOfEdges = derivedMesh->getNumEdges(derivedMesh);
+       numOfFaces = derivedMesh->getNumFaces(derivedMesh);
+       faceMap = MEM_mallocN(numOfFaces*sizeof(EditFace *), "unwrap_edit_face_map");
+       editFaceArray = MEM_mallocN(editMesh->totface*sizeof(EditFace *), "unwrap_editFaceArray");
+       /* fill edit face array with edit faces */
+       for(editFace = editMesh->faces.first, editFaceTmp = editFaceArray; editFace; editFace= editFace->next, editFaceTmp++)
+               *editFaceTmp = editFace;
+       /* map subsurfed faces to original editFaces */
+       for(i = 0; i < numOfFaces; i++)
+               faceMap[i] = editFaceArray[origFaceIndices[i]];
+       MEM_freeN(editFaceArray);
+       edgeMap = MEM_mallocN(numOfEdges*sizeof(EditEdge *), "unwrap_edit_edge_map");
+       editEdgeArray = MEM_mallocN(editMesh->totedge*sizeof(EditEdge *), "unwrap_editEdgeArray");
+       /* fill edit edge array with edit edges */
+       for(editEdge = editMesh->edges.first, editEdgeTmp = editEdgeArray; editEdge; editEdge= editEdge->next, editEdgeTmp++)
+               *editEdgeTmp = editEdge;
+       /* map subsurfed edges to original editEdges */
+       for(i = 0; i < numOfEdges; i++) {
+               /* not all edges correspond to an old edge */
+               edgeMap[i] = (origEdgeIndices[i] != -1)?
+                       editEdgeArray[origEdgeIndices[i]] : NULL;
+       }
+       MEM_freeN(editEdgeArray);
+       /* we need the editvert indices too */
+       for(editVert = editMesh->verts.first, i=0; editVert; editVert = editVert->next, i++)
+               editVert->tmp.t = i;
+       /* Prepare and feed faces to the solver */
+       for(i = 0; i < numOfFaces; i++) {
+               ParamKey key, vkeys[4];
+               ParamBool pin[4], select[4];
+               float *co[4];
+               float *uv[4];
+               EditFace *origFace = faceMap[i];
+               MTFace *origtexface = (MTFace *)CustomData_em_get(&editMesh->fdata, origFace->data, CD_MTFACE);
+               
+               face = subsurfedFaces+i;
+               if(scene->toolsettings->uv_flag & UV_SYNC_SELECTION) {
+                       if(origFace->h)
+                               continue;
+               }
+               else {
+                       if((origFace->h) || (sel && (origFace->f & SELECT)==0))
+                               continue;
+               }
+               /* Now we feed the rest of the data from the subsurfed faces */
+               texface= subsurfedTexfaces+i;
+               /* We will not check for v4 here. Subsurfed mfaces always have 4 vertices. */
+               key = (ParamKey)face;
+               vkeys[0] = (ParamKey)face->v1;
+               vkeys[1] = (ParamKey)face->v2;
+               vkeys[2] = (ParamKey)face->v3;
+               vkeys[3] = (ParamKey)face->v4;
+               co[0] = subsurfedVerts[face->v1].co;
+               co[1] = subsurfedVerts[face->v2].co;
+               co[2] = subsurfedVerts[face->v3].co;
+               co[3] = subsurfedVerts[face->v4].co;
+               
+               /* This is where all the magic is done. If the vertex exists in the, we pass the original uv pointer to the solver, thus
+                * flushing the solution to the edit mesh. */
+               texface_from_original_index(origFace, origtexface, origVertIndices[face->v1], &uv[0], &pin[0], &select[0], scene);
+               texface_from_original_index(origFace, origtexface, origVertIndices[face->v2], &uv[1], &pin[1], &select[1], scene);
+               texface_from_original_index(origFace, origtexface, origVertIndices[face->v3], &uv[2], &pin[2], &select[2], scene);
+               texface_from_original_index(origFace, origtexface, origVertIndices[face->v4], &uv[3], &pin[3], &select[3], scene);
+               param_face_add(handle, key, 4, vkeys, co, uv, pin, select);
+       }
+       /* these are calculated from original mesh too */
+       for(edge = subsurfedEdges, i = 0; i < numOfEdges; i++, edge++) {
+               if((edgeMap[i] != NULL) && edgeMap[i]->seam) {
+                       ParamKey vkeys[2];
+                       vkeys[0] = (ParamKey)edge->v1;
+                       vkeys[1] = (ParamKey)edge->v2;
+                       param_edge_set_seam(handle, vkeys);
+               }
+       }
+       param_construct_end(handle, fill, 0);
+       /* cleanup */
+       MEM_freeN(faceMap);
+       MEM_freeN(edgeMap);
+       derivedMesh->release(derivedMesh);
+       return handle;
+ }
++#else
++
++static ParamHandle *construct_param_handle_subsurfed(Scene *scene, BMEditMesh *editMesh, short fill, short sel, short correct_aspect)
++{
++      (void)scene;
++      (void)editMesh;
++      (void)fill;
++      (void)sel;
++      (void)correct_aspect;
++      return NULL;
++}
++
++#endif /* BMESH_TODO */
++
  /* ******************** Minimize Stretch operator **************** */
  
  typedef struct MinStretch {
@@@ -616,17 -778,23 +829,21 @@@ static ParamHandle *liveHandle = NULL
  
  void ED_uvedit_live_unwrap_begin(Scene *scene, Object *obedit)
  {
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
        short abf = scene->toolsettings->unwrapper == 0;
        short fillholes = scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
+       short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF;
  
        if(!ED_uvedit_test(obedit)) {
 -              BKE_mesh_end_editmesh(obedit->data, em);
                return;
        }
  
-       liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1);
+       if(use_subsurf)
+               liveHandle = construct_param_handle_subsurfed(scene, em, fillholes, 0, 1);
+       else
+               liveHandle = construct_param_handle(scene, em, 0, fillholes, 0, 1);
  
        param_lscm_begin(liveHandle, PARAM_TRUE, abf);
 -      BKE_mesh_end_editmesh(obedit->data, em);
  }
  
  void ED_uvedit_live_unwrap_re_solve(void)
@@@ -932,14 -1103,17 +1149,17 @@@ static void uv_map_clip_correct(BMEditM
  /* assumes UV Map is checked, doesn't run update funcs */
  void ED_unwrap_lscm(Scene *scene, Object *obedit, const short sel)
  {
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
        ParamHandle *handle;
  
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        const short fill_holes= scene->toolsettings->uvcalc_flag & UVCALC_FILLHOLES;
        const short correct_aspect= !(scene->toolsettings->uvcalc_flag & UVCALC_NO_ASPECT_CORRECT);
-       short implicit= 0;
+       const short use_subsurf = scene->toolsettings->uvcalc_flag & UVCALC_USESUBSURF;
  
-       handle= construct_param_handle(scene, em, implicit, fill_holes, sel, correct_aspect);
+       if(use_subsurf)
+               handle = construct_param_handle_subsurfed(scene, em, fill_holes, sel, correct_aspect);
+       else
+               handle= construct_param_handle(scene, em, 0, fill_holes, sel, correct_aspect);
  
        param_lscm_begin(handle, PARAM_FALSE, scene->toolsettings->unwrapper == 0);
        param_lscm_solve(handle);
Simple merge