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

index 8fd54c9d49ac70d0f57a1730b48661cd4596a83b,1dba79b34d71330e0add69f3ff129cab9cb3770d..3aa9434073d29e3838d1470c40e8535ae9669cf2
@@@ -523,10 -523,11 +523,10 @@@ class VIEW3D_MT_select_edit_mesh(Menu)
  
          layout.separator()
  
 -        layout.operator("mesh.select_by_number_vertices", text="Triangles").type = 'TRIANGLES'
 -        layout.operator("mesh.select_by_number_vertices", text="Quads").type = 'QUADS'
 +        layout.operator("mesh.select_by_number_vertices", text = "By Number of Verts")
          if context.scene.tool_settings.mesh_select_mode[2] == False:
              layout.operator("mesh.select_non_manifold", text="Non Manifold")
 -        layout.operator("mesh.select_by_number_vertices", text="Loose Verts/Edges").type = 'OTHER'
 +        layout.operator("mesh.select_loose_verts", text = "Loose Verts/Edges")
          layout.operator("mesh.select_similar", text="Similar")
  
          layout.separator()
@@@ -760,7 -761,7 +760,7 @@@ class VIEW3D_MT_object_clear(Menu)
          layout.operator("object.location_clear", text="Location")
          layout.operator("object.rotation_clear", text="Rotation")
          layout.operator("object.scale_clear", text="Scale")
-         layout ("object.origin_clear", text="Origin")
+         layout.operator("object.origin_clear", text="Origin")
  
  
  class VIEW3D_MT_object_specials(Menu):
@@@ -1109,9 -1110,9 +1109,9 @@@ class VIEW3D_MT_sculpt(Menu)
      def draw(self, context):
          layout = self.layout
  
-         tool_settings = context.tool_settings
-         sculpt = tool_settings.sculpt
-         brush = tool_settings.sculpt.brush
+         toolsettings = context.tool_settings
+         sculpt = toolsettings.sculpt
+         brush = toolsettings.sculpt.brush
  
          layout.operator("ed.undo")
          layout.operator("ed.redo")
          layout.prop(sculpt, "show_brush")
  
          # TODO, make available from paint menu!
-         layout.prop(tool_settings, "sculpt_paint_use_unified_size", text="Unify Size")
-         layout.prop(tool_settings, "sculpt_paint_use_unified_strength", text="Unify Strength")
+         layout.prop(toolsettings, "sculpt_paint_use_unified_size", text="Unify Size")
+         layout.prop(toolsettings, "sculpt_paint_use_unified_strength", text="Unify Strength")
  
  # ********** Particle menu **********
  
@@@ -1452,7 -1453,7 +1452,7 @@@ class VIEW3D_MT_edit_mesh(Menu)
      def draw(self, context):
          layout = self.layout
  
-         settings = context.tool_settings
+         toolsettings = context.tool_settings
  
          layout.operator("ed.undo")
          layout.operator("ed.redo")
  
          layout.separator()
  
-         layout.prop(settings, "use_mesh_automerge")
-         layout.prop_menu_enum(settings, "proportional_edit")
-         layout.prop_menu_enum(settings, "proportional_edit_falloff")
+         layout.prop(toolsettings, "use_mesh_automerge")
+         layout.prop_menu_enum(toolsettings, "proportional_edit")
+         layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
  
          layout.separator()
  
@@@ -1502,9 -1503,7 +1502,9 @@@ class VIEW3D_MT_edit_mesh_specials(Menu
          layout.operator_context = 'INVOKE_REGION_WIN'
  
          layout.operator("mesh.subdivide", text="Subdivide").smoothness = 0.0
 +        """
          layout.operator("mesh.subdivide", text="Subdivide Smooth").smoothness = 1.0
 +        """
          layout.operator("mesh.merge", text="Merge...")
          layout.operator("mesh.remove_doubles")
          layout.operator("mesh.hide", text="Hide")
          layout.operator("mesh.select_all").action = 'INVERT'
          layout.operator("mesh.flip_normals")
          layout.operator("mesh.vertices_smooth", text="Smooth")
 -        layout.operator("mesh.bevel", text="Bevel")
 +        layout.operator("mesh.bevel", text="Bevel")
          layout.operator("mesh.faces_shade_smooth")
          layout.operator("mesh.faces_shade_flat")
          layout.operator("mesh.blend_from_shape")
@@@ -1586,7 -1585,6 +1586,7 @@@ class VIEW3D_MT_edit_mesh_vertices(Menu
          layout.operator("mesh.rip_move")
          layout.operator("mesh.split")
          layout.operator("mesh.separate")
 +        layout.operator("mesh.vert_connect")
  
          layout.separator()
  
@@@ -1635,10 -1633,6 +1635,10 @@@ class VIEW3D_MT_edit_mesh_edges(Menu)
  
          layout.separator()
  
 +        layout.operator("mesh.bridge_edge_loops", text="Bridge Two Edge Loops")
 +
 +        layout.separator()
 +
          layout.operator("TRANSFORM_OT_edge_slide")
          layout.operator("TRANSFORM_OT_edge_crease")
          layout.operator("mesh.loop_multi_select", text="Edge Loop").ring = False
@@@ -1671,6 -1665,11 +1671,6 @@@ class VIEW3D_MT_edit_mesh_faces(Menu)
  
          layout.separator()
  
 -        layout.operator("mesh.fgon_make")
 -        layout.operator("mesh.fgon_clear")
 -
 -        layout.separator()
 -
          layout.operator("mesh.quads_convert_to_tris")
          layout.operator("mesh.tris_convert_to_quads")
          layout.operator("mesh.edge_flip")
          layout.separator()
  
          layout.operator_menu_enum("mesh.uvs_rotate", "direction")
 -        layout.operator_menu_enum("mesh.uvs_mirror", "axis")
 +        layout.operator("mesh.uvs_reverse")
          layout.operator_menu_enum("mesh.colors_rotate", "direction")
 -        layout.operator_menu_enum("mesh.colors_mirror", "axis")
 +        layout.operator("mesh.colors_reverse")
  
  
  class VIEW3D_MT_edit_mesh_normals(Menu):
@@@ -1719,7 -1718,7 +1719,7 @@@ class VIEW3D_MT_edit_mesh_showhide(Show
  def draw_curve(self, context):
      layout = self.layout
  
-     settings = context.tool_settings
+     toolsettings = context.tool_settings
  
      layout.menu("VIEW3D_MT_transform")
      layout.menu("VIEW3D_MT_mirror")
  
      layout.separator()
  
-     layout.prop_menu_enum(settings, "proportional_edit")
-     layout.prop_menu_enum(settings, "proportional_edit_falloff")
+     layout.prop_menu_enum(toolsettings, "proportional_edit")
+     layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
  
      layout.separator()
  
@@@ -1871,7 -1870,7 +1871,7 @@@ class VIEW3D_MT_edit_meta(Menu)
      def draw(self, context):
          layout = self.layout
  
-         settings = context.tool_settings
+         toolsettings = context.tool_settings
  
          layout.operator("ed.undo")
          layout.operator("ed.redo")
  
          layout.separator()
  
-         layout.prop_menu_enum(settings, "proportional_edit")
-         layout.prop_menu_enum(settings, "proportional_edit_falloff")
+         layout.prop_menu_enum(toolsettings, "proportional_edit")
+         layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
  
          layout.separator()
  
@@@ -1915,7 -1914,7 +1915,7 @@@ class VIEW3D_MT_edit_lattice(Menu)
      def draw(self, context):
          layout = self.layout
  
-         settings = context.tool_settings
+         toolsettings = context.tool_settings
  
          layout.menu("VIEW3D_MT_transform")
          layout.menu("VIEW3D_MT_mirror")
  
          layout.separator()
  
-         layout.prop_menu_enum(settings, "proportional_edit")
-         layout.prop_menu_enum(settings, "proportional_edit_falloff")
+         layout.prop_menu_enum(toolsettings, "proportional_edit")
+         layout.prop_menu_enum(toolsettings, "proportional_edit_falloff")
  
  
  class VIEW3D_MT_edit_armature(Menu):
index 22cd822bf9369155a52c6980fb011a690f7d71f6,30a4b154e31a8148dea63f0fb3ae594499a66932..06e4787c741115a5d250837fb274e8ed6b03de55
@@@ -36,8 -36,7 +36,8 @@@
  struct BoundBox;
  struct DispList;
  struct ListBase;
 -struct EditMesh;
 +struct BMEditMesh;
 +struct BMesh;
  struct Mesh;
  struct MPoly;
  struct MLoop;
@@@ -53,54 -52,27 +53,57 @@@ struct CustomData
  struct DerivedMesh;
  struct Scene;
  struct MLoopUV;
+ struct UvVertMap;
+ struct UvMapVert;
+ struct UvElementMap;
+ struct UvElement;
  #ifdef __cplusplus
  extern "C" {
  #endif
  
 -struct EditMesh *BKE_mesh_get_editmesh(struct Mesh *me);
 -void BKE_mesh_end_editmesh(struct Mesh *me, struct EditMesh *em);
 +struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
 +
 +/*
 + * this function recreates a tesselation.
 + * returns number of tesselation faces.
 + *
 + * use_poly_origindex sets whether or not the tesselation faces' origindex
 + * layer should point to original poly indices or real poly indices.
 + *
 + * use_face_origindex sets the tesselation faces' origindex layer
 + * to point to the tesselation faces themselves, not the polys.
 + *
 + * if both of the above are 0, it'll use the indices of the mpolys of the MPoly
 + * data in pdata, and ignore the origindex layer altogether.
 + */
 +int mesh_recalcTesselation(struct CustomData *fdata, struct CustomData *ldata, 
 +      struct CustomData *pdata, struct MVert *mvert, int totface, 
 +      int totloop, int totpoly);
  
  /* for forwards compat only quad->tri polys to mface, skip ngons.
   */
  int mesh_mpoly_to_mface(struct CustomData *fdata, struct CustomData *ldata,
        struct CustomData *pdata, int totface, int totloop, int totpoly);
  
 +/*calculates a face normal.*/
 +void mesh_calc_poly_normal(struct MPoly *mpoly, struct MLoop *loopstart, 
 +                           struct MVert *mvarray, float no[3]);
 +
 +void mesh_calc_poly_normal_coords(struct MPoly *mpoly, struct MLoop *loopstart,
 +                                  const float (*vertex_coords)[3], float no[3]);
 +
 +void mesh_calc_poly_center(struct MPoly *mpoly, struct MLoop *loopstart,
 +                           struct MVert *mvarray, float cent[3]);
 +
 +float mesh_calc_poly_area(struct MPoly *mpoly, struct MLoop *loopstart,
 +                          struct MVert *mvarray, float polynormal[3]);
 +
  void unlink_mesh(struct Mesh *me);
 -void free_mesh(struct Mesh *me);
 +void free_mesh(struct Mesh *me, int unlink);
  struct Mesh *add_mesh(const char *name);
  struct Mesh *copy_mesh(struct Mesh *me);
 -void mesh_update_customdata_pointers(struct Mesh *me);
 +void mesh_update_customdata_pointers(struct Mesh *me, const short do_ensure_tess_cd);
 +
  void make_local_mesh(struct Mesh *me);
  void boundbox_mesh(struct Mesh *me, float *loc, float *size);
  void tex_space_mesh(struct Mesh *me);
@@@ -110,26 -82,17 +113,26 @@@ int test_index_face(struct MFace *mface
  struct Mesh *get_mesh(struct Object *ob);
  void set_mesh(struct Object *ob, struct Mesh *me);
  void mball_to_mesh(struct ListBase *lb, struct Mesh *me);
 -int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *_totvert,
 -      struct MEdge **alledge, int *_totedge, struct MFace **allface, int *_totface);
 -int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase,
 -      struct MVert **allvert, int *_totvert, struct MEdge **alledge, int *_totedge,
 -      struct MFace **allface, int *_totface);
 +int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *totvert,
 +      struct MEdge **alledge, int *totedge, struct MFace **allface, struct MLoop **allloop, struct MPoly **allpoly, 
 +      int *totface, int *totloop, int *totpoly);
 +int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase, struct MVert **allvert, int *_totvert,
 +      struct MEdge **alledge, int *_totedge, struct MFace **allface, struct MLoop **allloop, struct MPoly **allpoly, 
 +      int *_totface, int *_totloop, int *_totpoly);
  void nurbs_to_mesh(struct Object *ob);
  void mesh_to_curve(struct Scene *scene, struct Object *ob);
  void free_dverts(struct MDeformVert *dvert, int totvert);
  void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); /* __NLA */
  void mesh_delete_material_index(struct Mesh *me, short index);
  void mesh_set_smooth_flag(struct Object *meshOb, int enableSmooth);
 +void convert_mfaces_to_mpolys(struct Mesh *mesh);
 +void mesh_calc_normals_tessface(struct MVert *mverts, int numVerts,struct  MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
 +
 +/*used for unit testing; compares two meshes, checking only
 +  differences we care about.  should be usable with leaf's
 +  testing framework I get RNA work done, will use hackish
 +  testing code for now.*/
 +const char *mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
  
  struct BoundBox *mesh_get_bb(struct Object *ob);
  void mesh_get_texspace(struct Mesh *me, float *loc_r, float *rot_r, float *size_r);
@@@ -143,21 -106,7 +146,21 @@@ void mesh_strip_loose_edges(struct Mes
        /* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL
         * and vertex normals are stored in actual mverts.
         */
 -void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
 +void mesh_calc_normals_mapping(
 +        struct MVert *mverts, int numVerts,
 +        struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3],
 +        struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3]);
 +      /* extended version of 'mesh_calc_normals' with option not to calc vertex normals */
 +void mesh_calc_normals_mapping_ex(
 +        struct MVert *mverts, int numVerts,
 +        struct MLoop *mloop, struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3],
 +        struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3],
 +        const short only_face_normals);
 +
 +void mesh_calc_normals(
 +        struct MVert *mverts, int numVerts,
 +        struct MLoop *mloop, struct MPoly *mpolys,
 +        int numLoops, int numPolys, float (*polyNors_r)[3]);
  
        /* Return a newly MEM_malloc'd array of all the mesh vertex locations
         * (_numVerts_r_ may be NULL) */
@@@ -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);
  
index c2cb45822807b3a212e45a24600bbbfcacb13c54,b75d8e0daa6ecec3adf9467966f9f4841294533b..12a0b1892a1638fbd5f727b85562e4f96e838621
@@@ -116,9 -116,10 +116,10 @@@ MINLINE void star_m3_v3(float rmat[3][3
  
  /*********************************** Length **********************************/
  
+ MINLINE float len_squared_v2(const float v[2]);
  MINLINE float len_v2(const float a[2]);
  MINLINE float len_v2v2(const float a[2], const float b[2]);
- MINLINE float len_squared_v2v2(const float a[3], const float b[3]);
+ MINLINE float len_squared_v2v2(const float a[2], const float b[2]);
  MINLINE float len_v3(const float a[3]);
  MINLINE float len_v3v3(const float a[3], const float b[3]);
  MINLINE float len_squared_v3v3(const float a[3], const float b[3]);
@@@ -170,7 -171,6 +171,7 @@@ float angle_v3v3v3(const float a[3], co
  float angle_normalized_v3v3(const float v1[3], const float v2[3]);
  void angle_tri_v3(float angles[3], const float v1[3], const float v2[3], const float v3[3]);
  void angle_quad_v3(float angles[4], const float v1[3], const float v2[3], const float v3[3], const float v4[3]);
 +void angle_poly_v3(float* angles, const float* verts[3], int len);
  
  /********************************* Geometry **********************************/
  
index 6f014a859dbd5a5d2e390e1f761378db86e5439e,dc9a32222f7705572e4a535d3fd62e235407c6fd..9c5d8f3261f6e80809b449660be46173dd2db41d
@@@ -429,6 -429,11 +429,11 @@@ MINLINE void star_m3_v3(float rmat[][3]
  
  /*********************************** Length **********************************/
  
+ MINLINE float len_squared_v2(const float v[2])
+ {
+       return v[0]*v[0] + v[1]*v[1];
+ }
  MINLINE float len_v2(const float v[2])
  {
        return (float)sqrtf(v[0]*v[0] + v[1]*v[1]);
@@@ -448,7 -453,7 +453,7 @@@ MINLINE float len_v3(const float a[3]
        return sqrtf(dot_v3v3(a, a));
  }
  
- MINLINE float len_squared_v2v2(const float a[3], const float b[3])
+ MINLINE float len_squared_v2v2(const float a[2], const float b[2])
  {
        float d[2];
  
@@@ -510,29 -515,6 +515,29 @@@ MINLINE float normalize_v3_v3(float r[3
        return d;
  }
  
 +MINLINE double normalize_v3_d(double n[3])
 +{
 +      double d= n[0]*n[0] + n[1]*n[1] + n[2]*n[2];
 +
 +      /* a larger value causes normalize errors in a
 +         scaled down models with camera xtreme close */
 +      if(d > 1.0e-35) {
 +              double mul;
 +
 +              d= sqrt(d);
 +              mul = 1.0 / d;
 +
 +              n[0] *= mul;
 +              n[1] *= mul;
 +              n[2] *= mul;
 +      } else {
 +              n[0] = n[1] = n[2] = 0;
 +              d= 0.0;
 +      }
 +
 +      return d;
 +}
 +
  MINLINE float normalize_v3(float n[3])
  {
        return normalize_v3_v3(n, n);
index 978cb4d00e332299333898313c68c3a0a029d403,fa15590e4e3a4d2c1e83a294e75785a28c094bf2..b51133d284b2b40ad4090b0e3bba92a4c0de4e9d
  
  #include "MEM_guardedalloc.h"
  
 +#include "BLI_utildefines.h"
  #include "BLI_blenlib.h"
  #include "BLI_math.h"
 -#include "BLI_utildefines.h"
 +#include "BLI_cellalloc.h"
 +#include "BLI_edgehash.h"
  
  #include "BKE_anim.h"
  #include "BKE_action.h"
@@@ -2705,16 -2703,6 +2705,16 @@@ static void lib_link_key(FileData *fd, 
  
        key= main->key.first;
        while(key) {
 +              /*check if we need to generate unique ids for the shapekeys*/
 +              if (!key->uidgen) {
 +                      KeyBlock *block;
 +
 +                      key->uidgen = 1;
 +                      for (block=key->block.first; block; block=block->next) {
 +                              block->uid = key->uidgen++;
 +                      }
 +              }
 +
                if(key->id.flag & LIB_NEEDLINK) {
                        if(key->adt) lib_link_animdata(fd, &key->id, key->adt);
                        
@@@ -3637,26 -3625,6 +3637,26 @@@ static void lib_link_customdata_mtface(
  
  }
  
 +static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata, int totface)
 +{
 +      int i;
 +
 +      for(i=0; i<pdata->totlayer; i++) {
 +              CustomDataLayer *layer = &pdata->layers[i];
 +              
 +              if(layer->type == CD_MTEXPOLY) {
 +                      MTexPoly *tf= layer->data;
 +                      int i;
 +
 +                      for (i=0; i<totface; i++, tf++) {
 +                              tf->tpage= newlibadr(fd, me->id.lib, tf->tpage);
 +                              if(tf->tpage && tf->tpage->id.us==0)
 +                                      tf->tpage->id.us= 1;
 +                      }
 +              }
 +      }
 +}
 +
  static void lib_link_mesh(FileData *fd, Main *main)
  {
        Mesh *me;
                        me->texcomesh= newlibadr_us(fd, me->id.lib, me->texcomesh);
  
                        lib_link_customdata_mtface(fd, me, &me->fdata, me->totface);
 +                      lib_link_customdata_mtpoly(fd, me, &me->pdata, me->totpoly);
                        if(me->mr && me->mr->levels.first)
                                lib_link_customdata_mtface(fd, me, &me->mr->fdata,
                                                           ((MultiresLevel*)me->mr->levels.first)->totface);
  
 +                      /*check if we need to convert mfaces to mpolys*/
 +                      if (me->totface && !me->totpoly) {
 +                              convert_mfaces_to_mpolys(me);
 +                      }
 +                      
 +                      /*
 +                       * Re-tesselate, even if the polys were just created from tessfaces, this
 +                       * is important because it:
 +                       *  - fill the CD_POLYINDEX layer
 +                       *  - gives consistency of tessface between loading from a file and
 +                       *    converting an edited BMesh back into a mesh (i.e. it replaces
 +                       *    quad tessfaces in a loaded mesh immediately, instead of lazily
 +                       *    waiting until edit mode has been entered/exited, making it easier
 +                       *    to recognize problems that would otherwise only show up after edits).
 +                       */
 +                      me->totface = mesh_recalcTesselation(
 +                              &me->fdata, &me->ldata, &me->pdata,
 +                              me->mvert, me->totface, me->totloop, me->totpoly);
 +
 +                      mesh_update_customdata_pointers(me, TRUE);
 +
                        me->id.flag -= LIB_NEEDLINK;
                }
                me= me->id.next;
@@@ -3728,17 -3674,10 +3728,17 @@@ static void direct_link_dverts(FileDat
        }
  
        for (i= count; i > 0; i--, mdverts++) {
 -              if(mdverts->dw) {
 -                      mdverts->dw= newdataadr(fd, mdverts->dw);
 +              /*convert to vgroup allocation system*/
 +              MDeformWeight *dw;
 +              if(mdverts->dw && (dw= newdataadr(fd, mdverts->dw))) {
 +                      const ssize_t dw_len= mdverts->totweight * sizeof(MDeformWeight);
 +                      void *dw_tmp= BLI_cellalloc_malloc(dw_len, "direct_link_dverts");
 +                      memcpy(dw_tmp, dw, dw_len);
 +                      mdverts->dw= dw_tmp;
 +                      MEM_freeN(dw);
                }
 -              if (mdverts->dw == NULL) {
 +              else {
 +                      mdverts->dw= NULL;
                        mdverts->totweight= 0;
                }
        }
@@@ -3751,18 -3690,7 +3751,18 @@@ static void direct_link_mdisps(FileDat
  
                for(i = 0; i < count; ++i) {
                        mdisps[i].disps = newdataadr(fd, mdisps[i].disps);
 -
 +                      
 +                      /*put .disps into cellalloc system*/
 +                      if (mdisps[i].disps) {
 +                              float *disp2;
 +                              
 +                              disp2 = BLI_cellalloc_malloc(MEM_allocN_len(mdisps[i].disps), "cellalloc .disps copy");
 +                              memcpy(disp2, mdisps[i].disps, MEM_allocN_len(mdisps[i].disps));
 +                              
 +                              MEM_freeN(mdisps[i].disps);
 +                              mdisps[i].disps = (float (*)[3])disp2;
 +                      }
 +                      
                        if( (fd->flags & FD_FLAGS_SWITCH_ENDIAN) && (mdisps[i].disps) ) {
                                /* DNA_struct_switch_endian doesn't do endian swap for (*disps)[] */
                                /* this does swap for data written at write_mdisps() - readfile.c */
@@@ -3812,17 -3740,12 +3812,17 @@@ static void direct_link_mesh(FileData *
        mesh->mvert= newdataadr(fd, mesh->mvert);
        mesh->medge= newdataadr(fd, mesh->medge);
        mesh->mface= newdataadr(fd, mesh->mface);
 +      mesh->mloop= newdataadr(fd, mesh->mloop);
 +      mesh->mpoly= newdataadr(fd, mesh->mpoly);
        mesh->tface= newdataadr(fd, mesh->tface);
        mesh->mtface= newdataadr(fd, mesh->mtface);
        mesh->mcol= newdataadr(fd, mesh->mcol);
        mesh->msticky= newdataadr(fd, mesh->msticky);
        mesh->dvert= newdataadr(fd, mesh->dvert);
 -      
 +      mesh->mloopcol= newdataadr(fd, mesh->mloopcol);
 +      mesh->mloopuv= newdataadr(fd, mesh->mloopuv);
 +      mesh->mtpoly= newdataadr(fd, mesh->mtpoly);
 +
        /* animdata */
        mesh->adt= newdataadr(fd, mesh->adt);
        direct_link_animdata(fd, mesh->adt);
        direct_link_customdata(fd, &mesh->vdata, mesh->totvert);
        direct_link_customdata(fd, &mesh->edata, mesh->totedge);
        direct_link_customdata(fd, &mesh->fdata, mesh->totface);
 -
 +      direct_link_customdata(fd, &mesh->ldata, mesh->totloop);
 +      direct_link_customdata(fd, &mesh->pdata, mesh->totpoly);
 +      
  
  #ifdef USE_BMESH_FORWARD_COMPAT
        /* NEVER ENABLE THIS CODE INTO BMESH!
  
        mesh->bb= NULL;
        mesh->mselect = NULL;
 -      mesh->edit_mesh= NULL;
 +      mesh->edit_btmesh= NULL;
        
        /* Multires data */
        mesh->mr= newdataadr(fd, mesh->mr);
@@@ -4794,7 -4715,7 +4794,7 @@@ static void lib_link_scene(FileData *fd
                        link_paint(fd, sce, &sce->toolsettings->vpaint->paint);
                        link_paint(fd, sce, &sce->toolsettings->wpaint->paint);
                        link_paint(fd, sce, &sce->toolsettings->imapaint.paint);
+                       link_paint(fd, sce, &sce->toolsettings->uvsculpt->paint);
                        sce->toolsettings->skgen_template = newlibadr(fd, sce->id.lib, sce->toolsettings->skgen_template);
  
                        for(base= sce->base.first; base; base= next) {
@@@ -4924,6 -4845,7 +4924,7 @@@ static void direct_link_scene(FileData 
                direct_link_paint(fd, (Paint**)&sce->toolsettings->sculpt);
                direct_link_paint(fd, (Paint**)&sce->toolsettings->vpaint);
                direct_link_paint(fd, (Paint**)&sce->toolsettings->wpaint);
+               direct_link_paint(fd, (Paint**)&sce->toolsettings->uvsculpt);
  
                sce->toolsettings->imapaint.paintcursor= NULL;
                sce->toolsettings->particle.paintcursor= NULL;
@@@ -6652,7 -6574,7 +6653,7 @@@ static void customdata_version_242(Mes
                }
        }
  
 -      mesh_update_customdata_pointers(me);
 +      mesh_update_customdata_pointers(me, TRUE);
  }
  
  /*only copy render texface layer from active*/
@@@ -12354,7 -12276,7 +12355,7 @@@ static void do_versions(FileData *fd, L
                Mesh *me;
  
                for(me= main->mesh.first; me; me= me->id.next)
 -                      mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
 +                      mesh_calc_normals_tessface(me->mvert, me->totvert, me->mface, me->totface, NULL);
        }
  
        if (main->versionfile < 256 || (main->versionfile == 256 && main->subversionfile < 2)){
index f41e9c91c8f3149e18aca626d71228a0b0798a2f,1231a076502b3752d55f189cfe4b0908f81d93b1..fb484cc680674183f344acb6b77a44918c0d597b
@@@ -152,7 -152,6 +152,7 @@@ Any case: direct data is ALWAYS after t
  #include "BKE_modifier.h"
  #include "BKE_fcurve.h"
  #include "BKE_pointcache.h"
 +#include "BKE_mesh.h"
  
  #include "BLO_writefile.h"
  #include "BLO_readfile.h"
@@@ -1683,135 -1682,22 +1683,135 @@@ static void write_customdata(WriteData 
  static void write_meshs(WriteData *wd, ListBase *idbase)
  {
        Mesh *mesh;
 +      int save_for_old_blender= 0;
 +
 +#ifdef USE_BMESH_SAVE_AS_COMPAT
 +      save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */
 +#endif
  
        mesh= idbase->first;
        while(mesh) {
                if(mesh->id.us>0 || wd->current) {
                        /* write LibData */
 -                      writestruct(wd, ID_ME, "Mesh", 1, mesh);
 +                      if (!save_for_old_blender) {
 +
 +#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
 +                              Mesh backup_mesh = {{0}};
 +                              /* cache only - dont write */
 +                              backup_mesh.mface = mesh->mface;
 +                              mesh->mface = NULL;
 +                              /* -- */
 +                              backup_mesh.totface = mesh->totface;
 +                              mesh->totface = 0;
 +                              /* -- */
 +#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
 +
 +                              writestruct(wd, ID_ME, "Mesh", 1, mesh);
 +
 +                              /* direct data */
 +                              if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
 +                              if (mesh->adt) write_animdata(wd, mesh->adt);
 +
 +                              writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
 +
 +                              write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
 +                              write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
 +                              /* fdata is really a dummy - written so slots align */
 +                              write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, -1, 0);
 +                              write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, -1, 0);
 +                              write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
 +
 +#ifdef USE_BMESH_SAVE_WITHOUT_MFACE
 +                              /* cache only - dont write */
 +                              mesh->mface = backup_mesh.mface;
 +                              /* -- */
 +                              mesh->totface = backup_mesh.totface;
 +#endif /* USE_BMESH_SAVE_WITHOUT_MFACE */
  
 -                      /* direct data */
 -                      if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
 -                      if (mesh->adt) write_animdata(wd, mesh->adt);
 +                      }
 +                      else {
  
 -                      writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
 +#ifdef USE_BMESH_SAVE_AS_COMPAT
  
 -                      write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
 -                      write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
 -                      write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, -1, 0);
 +                              Mesh backup_mesh = {{0}};
 +
 +                              /* backup */
 +                              backup_mesh.mpoly = mesh->mpoly;
 +                              mesh->mpoly = NULL;
 +                              /* -- */
 +                              backup_mesh.mface = mesh->mface;
 +                              mesh->mface = NULL;
 +                              /* -- */
 +                              backup_mesh.totface = mesh->totface;
 +                              mesh->totface = 0;
 +                              /* -- */
 +                              backup_mesh.totpoly = mesh->totpoly;
 +                              mesh->totpoly = 0;
 +                              /* -- */
 +                              backup_mesh.totloop = mesh->totloop;
 +                              mesh->totloop = 0;
 +                              /* -- */
 +                              backup_mesh.fdata = mesh->fdata;
 +                              memset(&mesh->fdata, 0, sizeof(CustomData));
 +                              /* -- */
 +                              backup_mesh.pdata = mesh->pdata;
 +                              memset(&mesh->pdata, 0, sizeof(CustomData));
 +                              /* -- */
 +                              backup_mesh.ldata = mesh->ldata;
 +                              memset(&mesh->ldata, 0, sizeof(CustomData));
 +                              /* -- */
 +                              backup_mesh.edit_btmesh = mesh->edit_btmesh;
 +                              mesh->edit_btmesh = NULL;
 +                              /* backup */
 +
 +
 +                              /* now fill in polys to mfaces*/
 +                              mesh->totface= mesh_mpoly_to_mface(&mesh->fdata, &backup_mesh.ldata, &backup_mesh.pdata,
 +                                                                 mesh->totface, backup_mesh.totloop, backup_mesh.totpoly);
 +
 +                              mesh_update_customdata_pointers(mesh, FALSE);
 +
 +                              writestruct(wd, ID_ME, "Mesh", 1, mesh);
 +
 +                              /* direct data */
 +                              if (mesh->id.properties) IDP_WriteProperty(mesh->id.properties, wd);
 +                              if (mesh->adt) write_animdata(wd, mesh->adt);
 +
 +                              writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat);
 +
 +                              write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, -1, 0);
 +                              write_customdata(wd, &mesh->id, mesh->totedge, &mesh->edata, -1, 0);
 +                              write_customdata(wd, &mesh->id, mesh->totface, &mesh->fdata, -1, 0);
 +                              /* harmless for older blender versioins but _not_ writing these keeps file size down */
 +                              /*
 +                              write_customdata(wd, &mesh->id, mesh->totloop, &mesh->ldata, -1, 0);
 +                              write_customdata(wd, &mesh->id, mesh->totpoly, &mesh->pdata, -1, 0);
 +                              */
 +
 +                              /* restore */
 +                              mesh->mpoly = backup_mesh.mpoly;
 +                              /* -- */
 +                              mesh->mface = backup_mesh.mface;
 +                              /* -- */
 +                              CustomData_free(&mesh->fdata, mesh->totface);
 +                              /* -- */
 +                              mesh->fdata= backup_mesh.fdata;
 +                              /* -- */
 +                              mesh->pdata= backup_mesh.pdata;
 +                              /* -- */
 +                              mesh->ldata= backup_mesh.ldata;
 +                              /* -- */
 +                              mesh->totface = backup_mesh.totface;
 +                              mesh->totpoly = backup_mesh.totpoly;
 +                              mesh->totloop = backup_mesh.totloop;
 +                              /* -- */
 +                              mesh_update_customdata_pointers(mesh, FALSE);
 +                              /* --*/
 +                              mesh->edit_btmesh = backup_mesh.edit_btmesh; /* keep this after updating custom pointers */
 +                              /* restore */
 +
 +#endif /* USE_BMESH_SAVE_AS_COMPAT */
 +                      }
                }
                mesh= mesh->id.next;
        }
@@@ -2077,6 -1963,9 +2077,9 @@@ static void write_scenes(WriteData *wd
                if(tos->sculpt) {
                        writestruct(wd, DATA, "Sculpt", 1, tos->sculpt);
                }
+               if(tos->uvsculpt) {
+                       writestruct(wd, DATA, "UvSculpt", 1, tos->uvsculpt);
+               }
  
                // write_paint(wd, &tos->imapaint.paint);
  
index e9884c5d8ce012647f11e304f315e55f0dc7e39d,790fb88300d1f4fb2fe86e19e1f045950e92760c..4abba91b7160a34aa196b6e991aa45be4788f249
@@@ -43,6 -43,7 +43,6 @@@ struct EditVert
  struct EditEdge;
  struct EditFace;
  struct bContext;
 -struct wmOperator;
  struct wmWindowManager;
  struct wmKeyConfig;
  struct ReportList;
@@@ -60,176 -61,135 +60,182 @@@ struct MCol
  struct UvVertMap;
  struct UvMapVert;
  struct CustomData;
 +struct BMEditMesh;
 +struct BMEditSelection;
 +struct BMesh;
 +struct BMVert;
 +struct MLoopCol;
 +struct BMEdge;
 +struct BMFace;
 +struct UvVertMap;
 +struct UvMapVert;
  struct Material;
  struct Object;
  struct rcti;
 +struct wmOperator;
 +struct ToolSettings;
  
 -#define EM_FGON_DRAW  1 // face flag
 -#define EM_FGON                       2 // edge and face flag both
 +// edge and face flag both
 +#define EM_FGON               2
 +// face flag
 +#define EM_FGON_DRAW  1
  
  /* editbutflag */
 -#define B_CLOCKWISE                   1
 -#define B_KEEPORIG                    2
 -#define B_BEAUTY                      4
 -#define B_SMOOTH                      8
 -#define B_BEAUTY_SHORT        0x10
 -#define B_AUTOFGON                    0x20
 -#define B_KNIFE                               0x80
 +#define B_CLOCKWISE           1
 +#define B_KEEPORIG            2
 +#define B_BEAUTY              4
 +#define B_SMOOTH              8
 +#define B_BEAUTY_SHORT        16
 +#define B_AUTOFGON            32
 +#define B_KNIFE                       0x80
  #define B_PERCENTSUBD         0x40
  //#define B_MESH_X_MIRROR             0x100 // deprecated, use mesh
  #define B_JOINTRIA_UV         0x200
  #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);
 -struct MTFace *EM_get_active_mtface(struct EditMesh *em, struct EditFace **act_efa, struct MCol **mcol, int sloppy);
 +struct MTexPoly       *EM_get_active_mtexpoly(struct BMEditMesh *em, struct BMFace **act_efa, struct MLoopCol **col, int sloppy);
  int paintface_mouse_select(struct bContext *C, struct Object *ob, const int mval[2], int extend);
  int do_paintface_box_select(struct ViewContext *vc, struct rcti *rect, int select, int extend);
  void paintface_deselect_all_visible(struct Object *ob, int action, short flush_flags);
@@@ -239,9 -199,6 +245,9 @@@ int paintface_minmax(struct Object *ob
  void paintface_hide(struct Object *ob, const int unselected);
  void paintface_reveal(struct Object *ob);
  
 +void paintvert_deselect_all_visible(struct Object *ob, int action, short flush_flags);
 +void          paintvert_flush_flags(struct Object *ob);
 +
  /* object_vgroup.c */
  
  #define WEIGHT_REPLACE 1
@@@ -264,26 -221,18 +270,26 @@@ void            ED_vgroup_vert_add(struct Object 
  void          ED_vgroup_vert_remove(struct Object *ob, struct bDeformGroup *dg, int vertnum);
  float         ED_vgroup_vert_weight(struct Object *ob, struct bDeformGroup *dg, int vertnum);
  
 -/*needed by edge slide*/
 -struct EditVert *editedge_getOtherVert(struct EditEdge *eed, struct EditVert *eve);
 -struct EditVert *editedge_getSharedVert(struct EditEdge *eed, struct EditEdge *eed2);
 -int editedge_containsVert(struct EditEdge *eed, struct EditVert *eve);
 -int editface_containsVert(struct EditFace *efa, struct EditVert *eve);
 -int editface_containsEdge(struct EditFace *efa, struct EditEdge *eed);
 -short sharesFace(struct EditMesh *em, struct EditEdge *e1, struct EditEdge *e2);
 +/**
 + * findnearestvert
 + * 
 + * dist (in/out): minimal distance to the nearest and at the end, actual distance
 + * sel: selection bias
 + *            if SELECT, selected vertice are given a 5 pixel bias to make them farter than unselect verts
 + *            if 0, unselected vertice are given the bias
 + * strict: if 1, the vertice corresponding to the sel parameter are ignored and not just biased 
 + */
 +
 +struct BMVert *EDBM_findnearestvert(struct ViewContext *vc, int *dist, short sel, short strict);
 +struct BMEdge *EDBM_findnearestedge(struct ViewContext *vc, int *dist);
 +struct BMFace *EDBM_findnearestface(struct ViewContext *vc, int *dist);
  
  /* mesh_data.c */
  // void ED_mesh_geometry_add(struct Mesh *mesh, struct ReportList *reports, int verts, int edges, int faces);
 +void ED_mesh_polys_add(struct Mesh *mesh, struct ReportList *reports, int count);
  void ED_mesh_faces_add(struct Mesh *mesh, struct ReportList *reports, int count);
  void ED_mesh_edges_add(struct Mesh *mesh, struct ReportList *reports, int count);
 +void ED_mesh_loops_add(struct Mesh *mesh, struct ReportList *reports, int count);
  void ED_mesh_vertices_add(struct Mesh *mesh, struct ReportList *reports, int count);
  
  void ED_mesh_transform(struct Mesh *me, float *mat);
@@@ -293,16 -242,10 +299,16 @@@ void ED_mesh_update(struct Mesh *mesh, 
  
  int ED_mesh_uv_texture_add(struct bContext *C, struct Mesh *me, const char *name, int active_set);
  int ED_mesh_uv_texture_remove(struct bContext *C, struct Object *ob, struct Mesh *me);
 +int ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me);
  int ED_mesh_color_add(struct bContext *C, struct Scene *scene, struct Object *ob, struct Mesh *me, const char *name, int active_set);
  int ED_mesh_color_remove(struct bContext *C, struct Object *ob, struct Mesh *me);
  int ED_mesh_color_remove_named(struct bContext *C, struct Object *ob, struct Mesh *me, const char *name);
  
 +void EDBM_selectmode_to_scene(struct bContext *C);
 +void EDBM_ClearMesh(struct BMEditMesh *em);
 +
 +#include "../mesh/editbmesh_bvh.h"
 +
  
  /* mirrtopo */
  typedef struct MirrTopoStore_t {
@@@ -322,3 -265,4 +328,3 @@@ void ED_mesh_mirrtopo_free(MirrTopoStor
  #endif
  
  #endif /* ED_MESH_H */
 -
index 2f193292eecb5f41a64b2a870d1728062453b5f0,bc8a12c97cc3978bc076b8ba3b74e5712d02016b..c19872213cabd952952b2fe9037a084bb65279d7
@@@ -42,10 -42,6 +42,10 @@@ struct SpaceImage
  struct bContext;
  struct bNode;
  struct wmKeyConfig;
 +struct BMEditMesh;
 +struct BMLoop;
 +struct BMFace;
 +struct MTexPoly;
  
  /* uvedit_ops.c */
  void ED_operatortypes_uvedit(void);
@@@ -61,17 -57,18 +61,17 @@@ int ED_uvedit_test_silent(struct Objec
  int ED_uvedit_test(struct Object *obedit);
  
  /* visibility and selection */
 -int uvedit_edge_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
 -int uvedit_face_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf);
 -int uvedit_face_visible_nolocal(struct Scene *scene, struct EditFace *efa);
 -int uvedit_face_visible(struct Scene *scene, struct Image *ima, struct EditFace *efa, struct MTFace *tf);
 -int uvedit_uv_selected(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
 -void uvedit_edge_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
 -void uvedit_edge_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
 -void uvedit_face_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf);
 -void uvedit_face_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf);
 -void uvedit_uv_deselect(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
 -void uvedit_uv_select(struct Scene *scene, struct EditFace *efa, struct MTFace *tf, int i);
 -
 +int uvedit_face_visible(struct Scene *scene, struct Image *ima, struct BMFace *efa, struct MTexPoly *tf);
 +int uvedit_face_selected(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa);
 +int uvedit_edge_selected(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
 +int uvedit_uv_selected(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
 +
 +int uvedit_face_select(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa);
 +int uvedit_face_deselect(struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa);
 +void uvedit_edge_select(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
 +void uvedit_edge_deselect(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
 +void uvedit_uv_select(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
 +void uvedit_uv_deselect(struct BMEditMesh *em, struct Scene *scene, struct BMLoop *l);
  
  int ED_uvedit_nearest_uv(struct Scene *scene, struct Object *obedit, struct Image *ima, float co[2], float uv[2]);
  
@@@ -84,7 -81,7 +84,7 @@@ void ED_uvedit_live_unwrap_end(short ca
  void ED_unwrap_lscm(struct Scene *scene, struct Object *obedit, const short sel);
  
  /* uvedit_draw.c */
- void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit);
+ void draw_uvedit_main(struct SpaceImage *sima, struct ARegion *ar, struct Scene *scene, struct Object *obedit, struct Object *obact);
  
  /* uvedit_buttons.c */
  void ED_uvedit_buttons_register(struct ARegionType *art);
index 362fc9fcef93434b8cba6af76de718cd5cb7677b,f087cdc7442020800321ec717e4f107319449aa2..29585d1c5a381f7d9a31f3a800ef0650b34eaec0
@@@ -38,11 -38,8 +38,11 @@@ struct BezTriple
  struct bglMats;
  struct BoundBox;
  struct BPoint;
 -struct EditEdge;
 -struct EditFace;
 +struct Nurb;
 +struct BezTriple;
 +struct BMVert;
 +struct BMEdge;
 +struct BMFace;
  struct EditVert;
  struct ImBuf;
  struct Main;
@@@ -65,7 -62,7 +65,7 @@@ typedef struct ViewContext 
        struct ARegion *ar;
        struct View3D *v3d;
        struct RegionView3D *rv3d;
 -      struct EditMesh *em;
 +      struct BMEditMesh *em;
        int mval[2];
  } ViewContext;
  
@@@ -192,9 -189,9 +192,9 @@@ void ED_view3d_from_object(struct Objec
   */
  void ED_view3d_to_object(struct Object *ob, const float ofs[3], const float quat[4], const float dist);
  
 -#if 0 /* UNUSED */
 +//#if 0 /* UNUSED */
  void view3d_unproject(struct bglMats *mats, float out[3], const short x, const short y, const float z);
 -#endif
 +//#endif
  
  /* Depth buffer */
  void ED_view3d_depth_update(struct ARegion *ar);
@@@ -220,13 -217,12 +220,13 @@@ int ED_view3d_viewplane_get(struct View
  void ED_view3d_ob_project_mat_get(struct RegionView3D *v3d, struct Object *ob, float pmat[4][4]);
  void ED_view3d_project_float(const struct ARegion *a, const float vec[3], float adr[2], float mat[4][4]);
  void ED_view3d_calc_camera_border(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, struct rctf *viewborder_r, short no_shift);
 +void ED_view3d_project_float_v3(struct ARegion *a, float *vec, float *adr, float mat[4][4]);
  void ED_view3d_calc_camera_border_size(struct Scene *scene, struct ARegion *ar, struct View3D *v3d, struct RegionView3D *rv3d, float size_r[2]);
  
  /* drawobject.c iterators */
 -void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct EditVert *eve, int x, int y, int index), void *userData, eV3DClipTest clipVerts);
 -void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, eV3DClipTest clipVerts);
 -void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct EditFace *efa, int x, int y, int index), void *userData);
 +void mesh_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BMVert *eve, int x, int y, int index), void *userData, eV3DClipTest clipVerts);
 +void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, eV3DClipTest clipVerts);
 +void mesh_foreachScreenFace(struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, int x, int y, int index), void *userData);
  void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, struct BPoint *bp, struct BezTriple *bezt, int beztindex, int x, int y), void *userData);
  void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, int x, int y), void *userData);
  
@@@ -283,10 -279,10 +283,10 @@@ void ED_view3d_draw_offscreen(struct Sc
        int winx, int winy, float viewmat[][4], float winmat[][4]);
  
  struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Scene *scene, struct View3D *v3d, struct ARegion *ar, int sizex, int sizey, unsigned int flag, char err_out[256]);
- struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype, char err_out[256]);
+ struct ImBuf *ED_view3d_draw_offscreen_imbuf_simple(struct Scene *scene, struct Object *camera, int width, int height, unsigned int flag, int drawtype, char err_out[256]);
  
  
- Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
  void ED_view3d_quadview_update(struct ScrArea *sa, struct ARegion *ar, short do_clip);
  int ED_view3d_lock(struct RegionView3D *rv3d);
  
index 6defe21e6c2b547aa5e0ff13ad7914a5f7ea2cfe,0000000000000000000000000000000000000000..1d3851b2650ccfbd40a166ad76522749ae09affd
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;
 +                              }
 +                      }
 +              }
 +      }
 +}
index 5f313301e2e44d84f355767d9b45057621912e8a,2dc170a8a238ffbeeca17cbd012adbf95b5f7637..a7ac91d13dfff6a06ca06416024720f4dabaf32c
@@@ -79,7 -79,6 +79,7 @@@
  #include "BKE_sca.h"
  #include "BKE_softbody.h"
  #include "BKE_modifier.h"
 +#include "BKE_tessmesh.h"
  
  #include "ED_armature.h"
  #include "ED_curve.h"
@@@ -89,7 -88,7 +89,7 @@@
  #include "ED_object.h"
  #include "ED_screen.h"
  #include "ED_util.h"
+ #include "ED_image.h"
  
  #include "RNA_access.h"
  #include "RNA_define.h"
@@@ -322,18 -321,18 +322,18 @@@ void ED_object_exit_editmode(bContext *
                
  //            if(EM_texFaceCheck())
                
 -              if(me->edit_mesh->totvert>MESH_MAX_VERTS) {
 +              if(me->edit_btmesh->bm->totvert>MESH_MAX_VERTS) {
                        error("Too many vertices");
                        return;
                }
 -              load_editMesh(scene, obedit);
 +              
 +              EDBM_LoadEditBMesh(scene, obedit);
                
                if(freedata) {
 -                      free_editMesh(me->edit_mesh);
 -                      MEM_freeN(me->edit_mesh);
 -                      me->edit_mesh= NULL;
 +                      EDBM_FreeEditBMesh(me->edit_btmesh);
 +                      MEM_freeN(me->edit_btmesh);
 +                      me->edit_btmesh= NULL;
                }
 -              
                if(obedit->restore_mode & OB_MODE_WEIGHT_PAINT) {
                        mesh_octree_table(NULL, NULL, NULL, 'e');
                        mesh_mirrtopo_table(NULL, 'e');
@@@ -443,7 -442,7 +443,7 @@@ void ED_object_enter_editmode(bContext 
                ok= 1;
                scene->obedit= ob;      // context sees this
                
 -              make_editMesh(scene, ob);
 +              EDBM_MakeEditBMesh(CTX_data_tool_settings(C), scene, ob);
  
                WM_event_add_notifier(C, NC_SCENE|ND_MODE|NS_EDITMODE_MESH, scene);
        }
  
  static int editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op))
  {
+       ToolSettings *toolsettings =  CTX_data_tool_settings(C);
        if(!CTX_data_edit_object(C))
                ED_object_enter_editmode(C, EM_WAITCURSOR);
        else
                ED_object_exit_editmode(C, EM_FREEDATA|EM_FREEUNDO|EM_WAITCURSOR); /* had EM_DO_UNDO but op flag calls undo too [#24685] */
        
+       ED_space_image_uv_sculpt_update(CTX_wm_manager(C), toolsettings);
        return OPERATOR_FINISHED;
  }
  
index 30f49264e90f547a727ad178f6f28079d00d9c90,fb20b201567d2ef6fdbb9e0e94b7ffbe57549b03..29e97c77bece029bd6273adb49bfae584154b24f
@@@ -23,10 -23,11 +23,12 @@@ set(IN
        ../../blenkernel
        ../../blenlib
        ../../blenloader
++      ../../bmesh
        ../../gpu
        ../../imbuf
        ../../makesdna
        ../../makesrna
+       ../uvedit
        ../../render/extern/include
        ../../windowmanager
        ../../../../intern/guardedalloc
@@@ -45,6 -46,7 +47,7 @@@ set(SR
        paint_vertex.c
        sculpt.c
        sculpt_undo.c
+       sculpt_uv.c
  
        paint_intern.h
        sculpt_intern.h
index 8f1f47b5004bb4d994803cb313eb12d21959273d,dd82e01240b3ec8bef6c54d6502be73756e88ec1..8669ea6c6952e41f7a2667d74aa2b985ba2e81ac
@@@ -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'
index 5f4777331c3bc47802e26a86f81cf219e99faf58,a5b79d0c9741c83891de6e0034c5f37dceec4523..1e989cce14af20f698cc4d3dc73da4b9af45a00e
@@@ -50,6 -50,7 +50,7 @@@
  #include "BLI_memarena.h"
  #include "BLI_threads.h"
  #include "BLI_utildefines.h"
+ #include "BLI_editVert.h"
  
  #include "PIL_time.h"
  
  #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"
  
@@@ -91,6 -94,7 +96,7 @@@
  #include "ED_sculpt.h"
  #include "ED_uvedit.h"
  #include "ED_view3d.h"
+ #include "ED_mesh.h"
  
  #include "WM_api.h"
  #include "WM_types.h"
  #include "RNA_enum_types.h"
  
  #include "GPU_draw.h"
+ #include "GPU_extensions.h"
  
  #include "paint_intern.h"
  
@@@ -2971,11 -2976,11 +2978,11 @@@ static void project_paint_begin(ProjPai
        }
        
        ps->dm_mvert = ps->dm->getVertArray(ps->dm);
 -      ps->dm_mface = ps->dm->getFaceArray(ps->dm);
 -      ps->dm_mtface= ps->dm->getFaceDataArray(ps->dm, CD_MTFACE);
 +      ps->dm_mface = ps->dm->getTessFaceArray(ps->dm);
 +      ps->dm_mtface= ps->dm->getTessFaceDataArray(ps->dm, CD_MTFACE);
        
        ps->dm_totvert = ps->dm->getNumVerts(ps->dm);
 -      ps->dm_totface = ps->dm->getNumFaces(ps->dm);
 +      ps->dm_totface = ps->dm->getNumTessFaces(ps->dm);
        
        /* use clone mtface? */
        
@@@ -3742,15 -3747,13 +3749,13 @@@ static void do_projectpaint_smear(ProjP
  
  static void do_projectpaint_smear_f(ProjPaintState *ps, ProjPixel *projPixel, float alpha, float mask, MemArena *smearArena, LinkNode **smearPixels_f, float co[2])
  {
-       unsigned char rgba_ub[4];
-       unsigned char rgba_smear[4];
+       float rgba[4];
        
-       if (project_paint_PickColor(ps, co, NULL, rgba_ub, 1)==0)
+       if (project_paint_PickColor(ps, co, rgba, NULL, 1)==0)
                return;
        
-       IMAPAINT_FLOAT_RGBA_TO_CHAR(rgba_smear, projPixel->pixel.f_pt);
        /* (ProjPixelClone *)projPixel)->clonepx.uint = IMB_blend_color(*((unsigned int *)rgba_smear), *((unsigned int *)rgba_ub), (int)(alpha*mask*255), ps->blend); */
-       blend_color_mix(((ProjPixelClone *)projPixel)->clonepx.ch, rgba_smear, (rgba_ub), (int)(alpha*mask*255)); 
+       blend_color_mix_float(((ProjPixelClone *)projPixel)->clonepx.f, projPixel->pixel.f_pt, rgba, alpha*mask); 
        BLI_linklist_prepend_arena(smearPixels_f, (void *)projPixel, smearArena);
  }
  
@@@ -3782,8 -3785,8 +3787,8 @@@ static void do_projectpaint_draw_f(Proj
  {
        if (ps->is_texbrush) {
                /* rgba already holds a texture result here from higher level function */
-               float rgba_br[3];
                if(use_color_correction){
+                       float rgba_br[3];
                        srgb_to_linearrgb_v3_v3(rgba_br, ps->brush->rgb);
                        mul_v3_v3(rgba, rgba_br);
                }
@@@ -3999,7 -4002,7 +4004,7 @@@ static void *do_projectpaint_thread(voi
                
                for (node= smearPixels_f; node; node= node->next) {
                        projPixel = node->link;
-                       IMAPAINT_CHAR_RGBA_TO_FLOAT(projPixel->pixel.f_pt,  ((ProjPixelClone *)projPixel)->clonepx.ch);
+                       copy_v4_v4(projPixel->pixel.f_pt, ((ProjPixelClone *)projPixel)->clonepx.f);
                }
                
                BLI_memarena_free(smearArena);
@@@ -4167,7 -4170,8 +4172,8 @@@ static void imapaint_image_update(Space
        if(texpaint || (sima && sima->lock)) {
                int w = imapaintpartial.x2 - imapaintpartial.x1;
                int h = imapaintpartial.y2 - imapaintpartial.y1;
-               GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h, !texpaint);
+               /* Testing with partial update in uv editor too */
+               GPU_paint_update_image(image, imapaintpartial.x1, imapaintpartial.y1, w, h, 0);//!texpaint);
        }
  }
  
@@@ -4606,6 -4610,16 +4612,16 @@@ static Brush *image_paint_brush(bContex
        return paint_brush(&settings->imapaint.paint);
  }
  
+ static Brush *uv_sculpt_brush(bContext *C)
+ {
+       Scene *scene= CTX_data_scene(C);
+       ToolSettings *settings= scene->toolsettings;
+       if(!settings->uvsculpt)
+               return NULL;
+       return paint_brush(&settings->uvsculpt->paint);
+ }
  static int image_paint_poll(bContext *C)
  {
        Object *obact = CTX_data_active_object(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))
@@@ -5086,7 -5125,7 +5126,7 @@@ void PAINT_OT_image_paint(wmOperatorTyp
        RNA_def_collection_runtime(ot->srna, "stroke", &RNA_OperatorStrokeElement, "Stroke", "");
  }
  
static int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
+ int get_imapaint_zoom(bContext *C, float *zoomx, float *zoomy)
  {
        RegionView3D *rv3d= CTX_wm_region_view3d(C);
  
@@@ -5112,16 -5151,27 +5152,27 @@@ static void brush_drawcursor(bContext *
  #define PX_SIZE_FADE_MIN 4.0f
  
        Scene *scene= CTX_data_scene(C);
-       Brush *brush= image_paint_brush(C);
+       //Brush *brush= image_paint_brush(C);
        Paint *paint= paint_get_active(scene);
+       Brush *brush= paint_brush(paint);
  
        if(paint && brush && paint->flags & PAINT_SHOW_BRUSH) {
+               ToolSettings *ts;
                float zoomx, zoomy;
                const float size= (float)brush_size(scene, brush);
                const short use_zoom= get_imapaint_zoom(C, &zoomx, &zoomy);
-               const float pixel_size= MAX2(size * zoomx, size * zoomy);
+               float pixel_size;
                float alpha= 0.5f;
  
+               ts = scene->toolsettings;
+               if(use_zoom && !ts->use_uv_sculpt){
+                       pixel_size = MAX2(size * zoomx, size * zoomy);
+               }
+               else {
+                       pixel_size = size;
+               }
                /* fade out the brush (cheap trick to work around brush interfearing with sampling [#])*/
                if(pixel_size < PX_SIZE_FADE_MIN) {
                        return;
  
                glTranslatef((float)x, (float)y, 0.0f);
  
-               if(use_zoom)
+               /* No need to scale for uv sculpting, on the contrary it might be useful to keep unscaled */
+               if(use_zoom && !ts->use_uv_sculpt)
                        glScalef(zoomx, zoomy, 1.0f);
  
                glColor4f(brush->add_col[0], brush->add_col[1], brush->add_col[2], alpha);
  
  static void toggle_paint_cursor(bContext *C, int enable)
  {
-       ToolSettings *settings= CTX_data_scene(C)->toolsettings;
+       wmWindowManager *wm= CTX_wm_manager(C);
+       Scene *scene = CTX_data_scene(C);
+       ToolSettings *settings= scene->toolsettings;
  
        if(settings->imapaint.paintcursor && !enable) {
-               WM_paint_cursor_end(CTX_wm_manager(C), settings->imapaint.paintcursor);
+               WM_paint_cursor_end(wm, settings->imapaint.paintcursor);
                settings->imapaint.paintcursor = NULL;
        }
        else if(enable)
-               settings->imapaint.paintcursor= WM_paint_cursor_activate(CTX_wm_manager(C), image_paint_poll, brush_drawcursor, NULL);
+               settings->imapaint.paintcursor= WM_paint_cursor_activate(wm, image_paint_poll, brush_drawcursor, NULL);
  }
  
  /* enable the paint cursor if it isn't already.
@@@ -5178,6 -5231,27 +5232,27 @@@ void ED_space_image_paint_update(wmWind
        }
  }
  
+ void ED_space_image_uv_sculpt_update(wmWindowManager *wm, ToolSettings *settings)
+ {
+       if(settings->use_uv_sculpt) {
+               if(!settings->uvsculpt) {
+                       settings->uvsculpt = MEM_callocN(sizeof(*settings->uvsculpt), "UV Smooth paint");
+                       settings->uv_sculpt_tool = UV_SCULPT_TOOL_GRAB;
+                       settings->uv_sculpt_settings = UV_SCULPT_LOCK_BORDERS | UV_SCULPT_ALL_ISLANDS;
+                       settings->uv_relax_method = UV_SCULPT_TOOL_RELAX_LAPLACIAN;
+               }
+               paint_init(&settings->uvsculpt->paint, PAINT_CURSOR_SCULPT);
+               WM_paint_cursor_activate(wm, uv_sculpt_brush_poll,
+                       brush_drawcursor, NULL);
+       }
+       else {
+               if(settings->uvsculpt)
+                       settings->uvsculpt->paint.flags &= ~PAINT_SHOW_BRUSH;
+       }
+ }
  /************************ grab clone operator ************************/
  
  typedef struct GrabClone {
@@@ -5499,6 -5573,11 +5574,11 @@@ int image_texture_paint_poll(bContext *
        return (texture_paint_poll(C) || image_paint_poll(C));
  }
  
+ int uv_sculpt_poll(bContext *C)
+ {
+       return uv_sculpt_brush_poll(C);
+ }
  int facemask_paint_poll(bContext *C)
  {
        return paint_facesel_test(CTX_data_active_object(C));
index 0000000000000000000000000000000000000000,4023797b11a0d0111d4885882c9cdb8bb17eff82..21bbb014eb0bedbcf61612dc682629f0b1a8f705
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");
+ }
index 6fce836af988143024d90708fea7310e82fa1f9f,fd7895052f146b2935321755a01e0b0ca9bf135a..3d97972c82951266f36c643907b73d4e78e9d4bf
@@@ -52,7 -52,6 +52,7 @@@
  #include "BKE_mesh.h"
  #include "BKE_scene.h"
  #include "BKE_screen.h"
 +#include "BKE_tessmesh.h"
  
  #include "IMB_imbuf_types.h"
  
@@@ -276,11 -275,12 +276,11 @@@ int ED_space_image_show_uvedit(SpaceIma
                return 0;
  
        if(obedit && obedit->type == OB_MESH) {
 -              EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
 +              struct BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
                int ret;
                
 -              ret = EM_texFaceCheck(em);
 +              ret = EDBM_texFaceCheck(em);
                
 -              BKE_mesh_end_editmesh(obedit->data, em);
                return ret;
        }
        
@@@ -294,11 -294,12 +294,11 @@@ int ED_space_image_show_uvshadow(SpaceI
        
        if(ED_space_image_show_paint(sima))
                if(obedit && obedit->type == OB_MESH) {
 -                      EditMesh *em = BKE_mesh_get_editmesh(obedit->data);
 +                      struct BMEditMesh *em = ((Mesh*)obedit->data)->edit_btmesh;
                        int ret;
                        
 -                      ret = EM_texFaceCheck(em);
 +                      ret = EDBM_texFaceCheck(em);
                        
 -                      BKE_mesh_end_editmesh(obedit->data, em);
                        return ret;
                }
        
@@@ -586,12 -587,12 +586,12 @@@ static void image_refresh(const bContex
        if(ima && (ima->source==IMA_SRC_VIEWER || sima->pin));
        else if(obedit && obedit->type == OB_MESH) {
                Mesh *me= (Mesh*)obedit->data;
 -              EditMesh *em= BKE_mesh_get_editmesh(me);
 +              struct BMEditMesh *em= me->edit_btmesh;
                int sloppy= 1; /* partially selected face is ok */
  
                if(scene_use_new_shading_nodes(scene)) {
                        /* new shading system, get image from material */
 -                      EditFace *efa= EM_get_actFace(em, sloppy);
 +                      BMFace *efa = BM_get_actFace(em->bm, sloppy);
  
                        if(efa) {
                                Image *node_ima;
                }
                else {
                        /* old shading system, we set texface */
 -                      MTFace *tf;
 +                      MTexPoly *tf;
                        
 -                      if(em && EM_texFaceCheck(em)) {
 +                      if(em && EDBM_texFaceCheck(em)) {
                                sima->image= NULL;
                                
 -                              tf = EM_get_active_mtface(em, NULL, NULL, sloppy);
 +                              tf = EDBM_get_active_mtexpoly(em, NULL, 1); /* partially selected face is ok */
                                
                                if(tf) {
                                        /* don't need to check for pin here, see above */
                                }
                        }
                }
 -
 -              BKE_mesh_end_editmesh(obedit->data, em);
        }
  }
  
@@@ -770,6 -773,9 +770,9 @@@ static void image_main_area_init(wmWind
        keymap= WM_keymap_find(wm->defaultconf, "UV Editor", 0, 0);
        WM_event_add_keymap_handler(&ar->handlers, keymap);
        
+       keymap= WM_keymap_find(wm->defaultconf, "UV Sculpt", 0, 0);
+       WM_event_add_keymap_handler(&ar->handlers, keymap);
        /* own keymaps */
        keymap= WM_keymap_find(wm->defaultconf, "Image Generic", SPACE_IMAGE, 0);
        WM_event_add_keymap_handler(&ar->handlers, keymap);
@@@ -782,6 -788,7 +785,7 @@@ static void image_main_area_draw(const 
  {
        /* draw entirely, view changes should be handled here */
        SpaceImage *sima= CTX_wm_space_image(C);
+       Object *obact= CTX_data_active_object(C);
        Object *obedit= CTX_data_edit_object(C);
        Scene *scene= CTX_data_scene(C);
        View2D *v2d= &ar->v2d;
  
        /* and uvs in 0.0-1.0 space */
        UI_view2d_view_ortho(v2d);
-       draw_uvedit_main(sima, ar, scene, obedit);
+       draw_uvedit_main(sima, ar, scene, obedit, obact);
  
        ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_VIEW);
                
index d59cea3e77ef68b1a164dcfcff34c4a80548e64e,a747c2ac6bd8339a49f76330294604fd670cf679..1c69e569aa63ed7b4498a65a35ddd890edee2931
@@@ -23,7 -23,6 +23,7 @@@ set(IN
        ../../blenkernel
        ../../blenlib
        ../../blenloader
 +      ../../bmesh
        ../../makesdna
        ../../makesrna
        ../../windowmanager
@@@ -40,6 -39,7 +40,7 @@@ set(SR
        uvedit_draw.c
        uvedit_ops.c
        uvedit_parametrizer.c
+       uvedit_smart_stitch.c
        uvedit_unwrap_ops.c
  
        uvedit_intern.h
index 8f4a8ef540fa4e73dc769aa18e833a5608e5a782,6ced91f0d013518702e6ae4eadd5a58b9620eb2a..77609b9618b9de32e102400634df04f9269a5c9a
  #include <float.h>
  #include <math.h>
  #include <stdlib.h>
 +#include <string.h>
  
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_mesh_types.h"
  #include "DNA_meshdata_types.h"
  #include "DNA_object_types.h"
  #include "DNA_scene_types.h"
@@@ -48,9 -44,7 +48,9 @@@
  
  #include "BKE_DerivedMesh.h"
  #include "BKE_mesh.h"
 +#include "BKE_tessmesh.h"
  
 +#include "BLI_array.h"
  
  #include "BIF_gl.h"
  #include "BIF_glutil.h"
@@@ -127,33 -121,34 +127,33 @@@ static int draw_uvs_face_check(Scene *s
  
  static void draw_uvs_shadow(Object *obedit)
  {
 -      EditMesh *em;
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMEditMesh *em;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MLoopUV *luv;
        
 -      em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 +      em= ((Mesh*)obedit->data)->edit_btmesh;
  
        /* draws the grey mesh when painting */
        glColor3ub(112, 112, 112);
  
 -      for(efa= em->faces.first; efa; efa= efa->next) {
 -              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
                glBegin(GL_LINE_LOOP);
 -                      glVertex2fv(tf->uv[0]);
 -                      glVertex2fv(tf->uv[1]);
 -                      glVertex2fv(tf->uv[2]);
 -                      if(efa->v4) glVertex2fv(tf->uv[3]);
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +
 +                      glVertex2fv(luv->uv);
 +              }
                glEnd();
        }
 -
 -      BKE_mesh_end_editmesh(obedit->data, em);
  }
  
  static int draw_uvs_dm_shadow(DerivedMesh *dm)
  {
        /* draw shadow mesh - this is the mesh with the modifier applied */
  
 -      if(dm && dm->drawUVEdges && CustomData_has_layer(&dm->faceData, CD_MTFACE)) {
 +      if(dm && dm->drawUVEdges && CustomData_has_layer(&dm->loopData, CD_MLOOPUV)) {
                glColor3ub(112, 112, 112);
                dm->drawUVEdges(dm);
                return 1;
        return 0;
  }
  
 -static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, EditMesh *em, MTFace *activetf)
 +static void draw_uvs_stretch(SpaceImage *sima, Scene *scene, BMEditMesh *em, MTexPoly *activetf)
  {
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        Image *ima= sima->image;
 -      float aspx, aspy, col[4], tf_uv[4][2];
 -      
 +      BLI_array_declare(tf_uv);
 +      BLI_array_declare(tf_uvorig);
 +      float aspx, aspy, col[4], (*tf_uv)[2] = NULL, (*tf_uvorig)[2] = NULL;
 +      int i;
 +
        ED_space_image_uv_aspect(sima, &aspx, &aspy);
        
        switch(sima->dt_uvstretch) {
                {
                        float totarea=0.0f, totuvarea=0.0f, areadiff, uvarea, area;
                        
 -                      for(efa= em->faces.first; efa; efa= efa->next) {
 -                              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -                              uv_copy_aspect(tf->uv, tf_uv, aspx, aspy);
 +                      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                              tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +                              
 +                              BLI_array_empty(tf_uv);
 +                              BLI_array_empty(tf_uvorig);
 +                              
 +                              i = 0;
 +                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                      luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                      BLI_array_growone(tf_uv);
 +                                      BLI_array_growone(tf_uvorig);
 +
 +                                      tf_uvorig[i][0] = luv->uv[0];
 +                                      tf_uvorig[i][1] = luv->uv[1];
  
 -                              totarea += EM_face_area(efa);
 +                                      i++;
 +                              }
 +
 +                              poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len);
 +
 +                              totarea += BM_Compute_Face_Area(em->bm, efa);
                                //totuvarea += tf_area(tf, efa->v4!=0);
 -                              totuvarea += uv_area(tf_uv, efa->v4 != NULL);
 +                              totuvarea += poly_uv_area(tf_uv, efa->len);
                                
                                if(uvedit_face_visible(scene, ima, efa, tf)) {
 -                                      efa->tmp.p = tf;
 +                                      BM_SetHFlag(efa, BM_TMP_TAG);
                                }
                                else {
                                        if(tf == activetf)
                                                activetf= NULL;
 -                                      efa->tmp.p = NULL;
 +                                      BM_ClearHFlag(efa, BM_TMP_TAG);
                                }
                        }
                        
                                col[0] = 1.0;
                                col[1] = col[2] = 0.0;
                                glColor3fv(col);
 -                              for(efa= em->faces.first; efa; efa= efa->next) {
 -                                      if((tf=(MTFace *)efa->tmp.p)) {
 -                                              glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 -                                                      glVertex2fv(tf->uv[0]);
 -                                                      glVertex2fv(tf->uv[1]);
 -                                                      glVertex2fv(tf->uv[2]);
 -                                                      if(efa->v4) glVertex2fv(tf->uv[3]);
 +                              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                                      if(BM_TestHFlag(efa, BM_TMP_TAG)) {
 +                                              glBegin(GL_POLYGON);
 +                                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                                      glVertex2fv(luv->uv);
 +                                              }
                                                glEnd();
                                        }
                                }
                        }
                        else {
 -                              for(efa= em->faces.first; efa; efa= efa->next) {
 -                                      if((tf=(MTFace *)efa->tmp.p)) {
 -                                              area = EM_face_area(efa) / totarea;
 -                                              uv_copy_aspect(tf->uv, tf_uv, aspx, aspy);
 +                              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                                      if(BM_TestHFlag(efa, BM_TMP_TAG)) {
 +                                              area = BM_Compute_Face_Area(em->bm, efa) / totarea;
 +
 +                                              BLI_array_empty(tf_uv);
 +                                              BLI_array_empty(tf_uvorig);
 +
 +                                              i = 0;
 +                                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                                      luv= CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                                      BLI_array_growone(tf_uv);
 +                                                      BLI_array_growone(tf_uvorig);
 +
 +                                                      tf_uvorig[i][0] = luv->uv[0];
 +                                                      tf_uvorig[i][1] = luv->uv[1];
 +
 +                                                      i++;
 +                                              }
 +
 +                                              poly_copy_aspect(tf_uvorig, tf_uv, aspx, aspy, efa->len);
 +
                                                //uvarea = tf_area(tf, efa->v4!=0) / totuvarea;
 -                                              uvarea = uv_area(tf_uv, efa->v4 != NULL) / totuvarea;
 +                                              uvarea = poly_uv_area(tf_uv, efa->len) / totuvarea;
                                                
                                                if(area < FLT_EPSILON || uvarea < FLT_EPSILON)
                                                        areadiff = 1.0f;
                                                weight_to_rgb(col, areadiff);
                                                glColor3fv(col);
                                                
 -                                              glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 -                                                      glVertex2fv(tf->uv[0]);
 -                                                      glVertex2fv(tf->uv[1]);
 -                                                      glVertex2fv(tf->uv[2]);
 -                                                      if(efa->v4) glVertex2fv(tf->uv[3]);
 +                                              glBegin(GL_POLYGON);
 +                                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                                      glVertex2fv(luv->uv);
 +                                              }
                                                glEnd();
                                        }
                                }
                }
                case SI_UVDT_STRETCH_ANGLE:
                {
 +#if 0 //BMESH_TODO
                        float uvang1,uvang2,uvang3,uvang4;
                        float ang1,ang2,ang3,ang4;
                        float av1[3], av2[3], av3[3], av4[3]; /* use for 2d and 3d  angle vectors */
                        glShadeModel(GL_SMOOTH);
                        
                        for(efa= em->faces.first; efa; efa= efa->next) {
 -                              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 +                              tf= CustomData_em_get(&em->fdata, efa->head.data, CD_MTFACE);
                                
                                if(uvedit_face_visible(scene, ima, efa, tf)) {
                                        efa->tmp.p = tf;
  
                        glShadeModel(GL_FLAT);
                        break;
 +
 +#endif
                }
        }
  }
  
- static void draw_uvs_other(Scene *scene, Object *obedit, MTexPoly *activetf)
+ static void draw_uvs_other(Scene *scene, Object *obedit, Image *curimage)
  {
        Base *base;
-       Image *curimage;
-       curimage= (activetf)? activetf->tpage: NULL;
  
        glColor3ub(96, 96, 96);
  
                        Mesh *me= ob->data;
  
                        if(me->mtface) {
 -                              MFace *mface= me->mface;
 -                              MTFace *tface= me->mtface;
 -                              int a;
 +                              MPoly *mface= me->mpoly;
 +                              MTexPoly *tface= me->mtpoly;
 +                              MLoopUV *mloopuv;
 +                              int a, b;
  
 -                              for(a=me->totface; a>0; a--, tface++, mface++) {
 +                              for(a=me->totpoly; a>0; a--, tface++, mface++) {
                                        if(tface->tpage == curimage) {
                                                glBegin(GL_LINE_LOOP);
 -                                              glVertex2fv(tface->uv[0]);
 -                                              glVertex2fv(tface->uv[1]);
 -                                              glVertex2fv(tface->uv[2]);
 -                                              if(mface->v4) glVertex2fv(tface->uv[3]);
 +
 +                                              mloopuv = me->mloopuv + mface->loopstart;
 +                                              for (b=0; b<mface->totloop; b++, mloopuv++) {
 +                                                      glVertex2fv(mloopuv->uv);
 +                                              }
                                                glEnd();
                                        }
                                }
        }
  }
  
 -              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)
  {
        ToolSettings *ts;
        Mesh *me= obedit->data;
 -      EditMesh *em;
 -      EditFace *efa, *efa_act;
 -      MTFace *tf, *activetf = NULL;
 +      BMEditMesh *em;
 +      BMFace *efa, *efa_act, *activef;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MTexPoly *tf, *activetf = NULL;
 +      MLoopUV *luv;
        DerivedMesh *finaldm, *cagedm;
        unsigned char col1[4], col2[4];
        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);
                interpedges= (ts->uv_selectmode == UV_SELECT_VERTEX);
        
        /* draw other uvs */
-       if(sima->flag & SI_DRAW_OTHER)
-               draw_uvs_other(scene, obedit, activetf);
+       if(sima->flag & SI_DRAW_OTHER) {
+               Image *curimage= (activetf)? activetf->tpage: NULL;
+               draw_uvs_other(scene, obedit, curimage);
+       }
  
        /* 1. draw shadow mesh */
        
                /* first try existing derivedmesh */
                if(!draw_uvs_dm_shadow(em->derivedFinal)) {
                        /* create one if it does not exist */
 -                      cagedm = editmesh_get_derived_cage_and_final(scene, obedit, em, &finaldm, CD_MASK_BAREMESH|CD_MASK_MTFACE);
 +                      cagedm = editbmesh_get_derived_cage_and_final(scene, obedit, me->edit_btmesh, &finaldm, CD_MASK_BAREMESH|CD_MASK_MTFACE);
  
                        /* when sync selection is enabled, all faces are drawn (except for hidden)
                         * so if cage is the same as the final, theres no point in drawing this */
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                glEnable(GL_BLEND);
                
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 +              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)) {
 -                              efa->tmp.p = tf;
 -                              if(tf==activetf) continue; /* important the temp pointer is set above */
 +                              BM_SetHFlag(efa, BM_TMP_TAG);
 +                              if(tf==activetf) continue; /* important the temp boolean is set above */
  
 -                              if(uvedit_face_selected(scene, efa, tf))
 +                              if(uvedit_face_selected(scene, em, efa))
                                        glColor4ubv((GLubyte *)col2);
                                else
                                        glColor4ubv((GLubyte *)col1);
 -                                      
 -                              glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 -                                      glVertex2fv(tf->uv[0]);
 -                                      glVertex2fv(tf->uv[1]);
 -                                      glVertex2fv(tf->uv[2]);
 -                                      if(efa->v4) glVertex2fv(tf->uv[3]);
 +                              
 +                              glBegin(GL_POLYGON);
 +                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                      glVertex2fv(luv->uv);
 +                              }
                                glEnd();
                        }
                        else {
                                if(tf == activetf)
                                        activetf= NULL;
 -                              efa->tmp.p = NULL;
 +                              BM_ClearHFlag(efa, BM_TMP_TAG);
                        }
                }
                glDisable(GL_BLEND);
        }
        else {
                /* would be nice to do this within a draw loop but most below are optional, so it would involve too many checks */
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 +              
 +              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)) {          
 -                              efa->tmp.p = tf;
 +                              BM_SetHFlag(efa, BM_TMP_TAG);
                        }
                        else {
                                if(tf == activetf)
                                        activetf= NULL;
 -                              efa->tmp.p = NULL;
 +                              BM_ClearHFlag(efa, BM_TMP_TAG);
                        }
                }
                
        }
-       
        /* 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);
                glEnable(GL_POLYGON_STIPPLE);
                glPolygonStipple(stipple_quarttone);
  
 -              glBegin(efa_act->v4? GL_QUADS: GL_TRIANGLES);
 -                      glVertex2fv(activetf->uv[0]);
 -                      glVertex2fv(activetf->uv[1]);
 -                      glVertex2fv(activetf->uv[2]);
 -                      if(efa_act->v4) glVertex2fv(activetf->uv[3]);
 +              glBegin(GL_POLYGON);
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, activef) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      glVertex2fv(luv->uv);
 +              }
                glEnd();
  
                glDisable(GL_POLYGON_STIPPLE);
        
        switch(sima->dt_uv) {
                case SI_UVDT_DASH:
 -                      for(efa= em->faces.first; efa; efa= efa->next) {
 -                              tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 +                      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                              if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                                      continue;
 +                              tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  
                                if(tf) {
                                        cpack(0x111111);
  
                                        glBegin(GL_LINE_LOOP);
 -                                              glVertex2fv(tf->uv[0]);
 -                                              glVertex2fv(tf->uv[1]);
 -                                              glVertex2fv(tf->uv[2]);
 -                                              if(efa->v4) glVertex2fv(tf->uv[3]);
 +                                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                              glVertex2fv(luv->uv);
 +                                      }
                                        glEnd();
 -                              
 +
                                        setlinestyle(2);
                                        cpack(0x909090);
  
 -                                      glBegin(GL_LINE_STRIP);
 -                                              glVertex2fv(tf->uv[0]);
 -                                              glVertex2fv(tf->uv[1]);
 -                                      glEnd();
 -              
 -                                      glBegin(GL_LINE_STRIP);
 -                                              glVertex2fv(tf->uv[0]);
 -                                              if(efa->v4) glVertex2fv(tf->uv[3]);
 -                                              else glVertex2fv(tf->uv[2]);
 -                                      glEnd();
 -              
 -                                      glBegin(GL_LINE_STRIP);
 -                                              glVertex2fv(tf->uv[1]);
 -                                              glVertex2fv(tf->uv[2]);
 -                                              if(efa->v4) glVertex2fv(tf->uv[3]);
 +                                      glBegin(GL_LINE_LOOP);
 +                                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                              glVertex2fv(luv->uv);
 +                                      }
                                        glEnd();
  
 +                                      /*glBegin(GL_LINE_STRIP);
 +                                              luv = CustomData_bmesh_get(&em->bm->ldata, efa->lbase->head.data, CD_MLOOPUV);
 +                                              glVertex2fv(luv->uv);
 +                                              luv = CustomData_bmesh_get(&em->bm->ldata, efa->lbase->next->head.data, CD_MLOOPUV);
 +                                              glVertex2fv(luv->uv);
 +                                      glEnd();*/
 +
                                        setlinestyle(0);
                                }
                        }
                        if(sima->dt_uv==SI_UVDT_WHITE) glColor3f(1.0f, 1.0f, 1.0f);
                        else glColor3f(0.0f, 0.0f, 0.0f);
  
 -                      for(efa= em->faces.first; efa; efa= efa->next) {
 -                              tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 +                      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                              if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                                      continue;
  
 -                              if(tf) {
 -                                      glBegin(GL_LINE_LOOP);
 -                                              glVertex2fv(tf->uv[0]);
 -                                              glVertex2fv(tf->uv[1]);
 -                                              glVertex2fv(tf->uv[2]);
 -                                              if(efa->v4) glVertex2fv(tf->uv[3]);
 -                                      glEnd();
 +                              glBegin(GL_LINE_LOOP);
 +                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                      glVertex2fv(luv->uv);
                                }
 +                              glEnd();
                        }
                        break;
                case SI_UVDT_OUTLINE:
                        glLineWidth(3);
                        cpack(0x0);
                        
 -                      for(efa= em->faces.first; efa; efa= efa->next) {
 -                              tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 +                      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                              if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                                      continue;
  
 -                              if(tf) {
 -                                      glBegin(GL_LINE_LOOP);
 -                                              glVertex2fv(tf->uv[0]);
 -                                              glVertex2fv(tf->uv[1]);
 -                                              glVertex2fv(tf->uv[2]);
 -                                              if(efa->v4) glVertex2fv(tf->uv[3]);
 -                                      glEnd();
 +                              glBegin(GL_LINE_LOOP);
 +                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                      glVertex2fv(luv->uv);
                                }
 +                              glEnd();
                        }
                        
                        glLineWidth(1);
                        glColor4ubv((unsigned char *)col2); 
                        
                        if(me->drawflag & ME_DRAWEDGES) {
 -                              int lastsel= 0, sel;
 +                              int sel, lastsel = -1;
                                UI_GetThemeColor4ubv(TH_VERTEX_SELECT, col1);
  
                                if(interpedges) {
                                        glShadeModel(GL_SMOOTH);
  
 -                                      for(efa= em->faces.first; efa; efa= efa->next) {
 -                                              tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 -
 -                                              if(tf) {
 -                                                      glBegin(GL_LINE_LOOP);
 -                                                      sel = (uvedit_uv_selected(scene, efa, tf, 0)? 1 : 0);
 -                                                      if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
 -                                                      glVertex2fv(tf->uv[0]);
 -                                                      
 -                                                      sel = uvedit_uv_selected(scene, efa, tf, 1)? 1 : 0;
 -                                                      if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
 -                                                      glVertex2fv(tf->uv[1]);
 -                                                      
 -                                                      sel = uvedit_uv_selected(scene, efa, tf, 2)? 1 : 0;
 -                                                      if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
 -                                                      glVertex2fv(tf->uv[2]);
 -                                                      
 -                                                      if(efa->v4) {
 -                                                              sel = uvedit_uv_selected(scene, efa, tf, 3)? 1 : 0;
 -                                                              if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
 -                                                              glVertex2fv(tf->uv[3]);
 -                                                      }
 -                                                      
 -                                                      glEnd();
 +                                      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                                              if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                                                      continue;
 +
 +                                              glBegin(GL_LINE_LOOP);
 +                                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                                      sel = (uvedit_uv_selected(em, scene, l)? 1 : 0);
 +                                                      glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2);
 +
 +                                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                                      glVertex2fv(luv->uv);
                                                }
 +                                              glEnd();
                                        }
  
                                        glShadeModel(GL_FLAT);
                                }
                                else {
 -                                      for(efa= em->faces.first; efa; efa= efa->next) {
 -                                              tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 -
 -                                              if(tf) {
 -                                                      glBegin(GL_LINES);
 -                                                      sel = (uvedit_edge_selected(scene, efa, tf, 0)? 1 : 0);
 -                                                      if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
 -                                                      glVertex2fv(tf->uv[0]);
 -                                                      glVertex2fv(tf->uv[1]);
 -                                                      
 -                                                      sel = uvedit_edge_selected(scene, efa, tf, 1)? 1 : 0;
 -                                                      if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
 -                                                      glVertex2fv(tf->uv[1]);
 -                                                      glVertex2fv(tf->uv[2]);
 -                                                      
 -                                                      sel = uvedit_edge_selected(scene, efa, tf, 2)? 1 : 0;
 -                                                      if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
 -                                                      glVertex2fv(tf->uv[2]);
 -                                                      
 -                                                      if(efa->v4) {
 -                                                              glVertex2fv(tf->uv[3]);
 -
 -                                                              sel = uvedit_edge_selected(scene, efa, tf, 3)? 1 : 0;
 -                                                              if(sel != lastsel) { glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2); lastsel = sel; }
 -                                                              glVertex2fv(tf->uv[3]);
 +                                      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                                              if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                                                      continue;
 +
 +                                              glBegin(GL_LINES);
 +                                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                                      sel = (uvedit_edge_selected(em, scene, l)? 1 : 0);
 +                                                      if(sel != lastsel){
 +                                                              glColor4ubv(sel ? (GLubyte *)col1 : (GLubyte *)col2);
 +                                                              lastsel = sel;
                                                        }
 -
 -                                                      glVertex2fv(tf->uv[0]);
 -                                                      
 -                                                      glEnd();
 +                                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                                      glVertex2fv(luv->uv);
 +                                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
 +                                                      glVertex2fv(luv->uv);
                                                }
 +                                              glEnd();
                                        }
                                }
                        }
                        else {
                                /* no nice edges */
 -                              for(efa= em->faces.first; efa; efa= efa->next) {
 -                                      tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 -
 -                                      if(tf) {
 -                                              glBegin(GL_LINE_LOOP);
 -                                                      glVertex2fv(tf->uv[0]);
 -                                                      glVertex2fv(tf->uv[1]);
 -                                                      glVertex2fv(tf->uv[2]);
 -                                                      if(efa->v4) glVertex2fv(tf->uv[3]);
 -                                              glEnd();
 +                              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                                      if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                                              continue;
 +                              
 +                                      glBegin(GL_LINE_LOOP);
 +                                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                                              glVertex2fv(luv->uv);
                                        }
 +                                      glEnd();
                                }
                        }
                        
                UI_ThemeColor(TH_WIRE);
  
                bglBegin(GL_POINTS);
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                              continue;
  
 -                      if(tf && !uvedit_face_selected(scene, efa, tf)) {
 -                              uv_center(tf->uv, cent, efa->v4 != NULL);
 +                      if(!uvedit_face_selected(scene, em, efa)) {
 +                              poly_uv_center(em, efa, cent);
                                bglVertex2fv(cent);
                        }
                }
                UI_ThemeColor(TH_FACE_DOT);
  
                bglBegin(GL_POINTS);
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                              continue;
  
 -                      if(tf && uvedit_face_selected(scene, efa, tf)) {
 -                              uv_center(tf->uv, cent, efa->v4 != NULL);
 +                      if(uvedit_face_selected(scene, em, efa)) {
 +                              poly_uv_center(em, efa, cent);
                                bglVertex2fv(cent);
                        }
                }
                glPointSize(pointsize);
        
                bglBegin(GL_POINTS);
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 -
 -                      if(tf) {
 -                              if(!uvedit_uv_selected(scene, efa, tf, 0))
 -                                      bglVertex2fv(tf->uv[0]);
 -                              if(!uvedit_uv_selected(scene, efa, tf, 1))
 -                                      bglVertex2fv(tf->uv[1]);
 -                              if(!uvedit_uv_selected(scene, efa, tf, 2))
 -                                      bglVertex2fv(tf->uv[2]);
 -                              if(efa->v4 && !uvedit_uv_selected(scene, efa, tf, 3))
 -                                      bglVertex2fv(tf->uv[3]);
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                              continue;
 +
 +                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                              if(!uvedit_uv_selected(em, scene, l))
 +                                      bglVertex2fv(luv->uv);
                        }
                }
                bglEnd();
                cpack(0xFF);
        
                bglBegin(GL_POINTS);
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 -
 -                      if(tf) {
 -                              if(tf->unwrap & TF_PIN1)
 -                                      bglVertex2fv(tf->uv[0]);
 -                              if(tf->unwrap & TF_PIN2)
 -                                      bglVertex2fv(tf->uv[1]);
 -                              if(tf->unwrap & TF_PIN3)
 -                                      bglVertex2fv(tf->uv[2]);
 -                              if(efa->v4 && (tf->unwrap & TF_PIN4))
 -                                      bglVertex2fv(tf->uv[3]);
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                              continue;
 +
 +                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +
 +                              if(luv->flag & MLOOPUV_PINNED)
 +                                      bglVertex2fv(luv->uv);
                        }
                }
                bglEnd();
                glPointSize(pointsize);
        
                bglBegin(GL_POINTS);
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      tf= (MTFace *)efa->tmp.p; /* visible faces cached */
 -
 -                      if(tf) {
 -                              if(uvedit_uv_selected(scene, efa, tf, 0))
 -                                      bglVertex2fv(tf->uv[0]);
 -                              if(uvedit_uv_selected(scene, efa, tf, 1))
 -                                      bglVertex2fv(tf->uv[1]);
 -                              if(uvedit_uv_selected(scene, efa, tf, 2))
 -                                      bglVertex2fv(tf->uv[2]);
 -                              if(efa->v4 && uvedit_uv_selected(scene, efa, tf, 3))
 -                                      bglVertex2fv(tf->uv[3]);
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      if (!BM_TestHFlag(efa, BM_TMP_TAG))
 +                              continue;
 +
 +                      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +
 +                              if(uvedit_uv_selected(em, scene, l))
 +                                      bglVertex2fv(luv->uv);
                        }
                }
                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);
  
-       if(show_uvedit || show_uvshadow) {
+       if(show_uvedit || show_uvshadow || show_texpaint_uvshadow) {
                if(show_uvshadow)
                        draw_uvs_shadow(obedit);
-               else
+               else if(show_uvedit)
                        draw_uvs(sima, scene, obedit);
+               else
+                       draw_uvs_texpaint(sima, scene, obact);
  
-               if(show_uvedit)
+               if(show_uvedit && !(toolsettings->use_uv_sculpt))
                        drawcursor_sima(sima, ar);
        }
  }
index e7156c6549116e507586d69fcf4801907defc6cb,ef25159a3af1c284bed5b838a5d3165b5566183f..58bdd8c3265c262fe651dc9dd6d74254ce1d3ab7
  #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);
@@@ -70,6 -109,7 +123,7 @@@ void UV_OT_pack_islands(struct wmOperat
  void UV_OT_reset(struct wmOperatorType *ot);
  void UV_OT_sphere_project(struct wmOperatorType *ot);
  void UV_OT_unwrap(struct wmOperatorType *ot);
+ void UV_OT_stitch(struct wmOperatorType *ot);
  
  #endif /* ED_UVEDIT_INTERN_H */
  
index a11d5935e220c8f67a834cb390768a6da619a758,612b46746b88bc7260f0b35e298072803b9e1051..c468da6b937980ea0737413af736767fbe1799de
@@@ -20,7 -20,7 +20,7 @@@
   *
   * The Original Code is: all of this file.
   *
-  * Contributor(s): none yet.
+  * Contributor(s): Antony Riakiotakis.
   *
   * ***** END GPL LICENSE BLOCK *****
   */
@@@ -33,7 -33,6 +33,7 @@@
  #include <stdlib.h>
  #include <string.h>
  #include <math.h>
 +#include <string.h>
  
  #include "MEM_guardedalloc.h"
  
  #include "DNA_material_types.h"
  #include "DNA_meshdata_types.h"
  #include "DNA_node_types.h"
 +#include "DNA_image_types.h"
 +#include "DNA_space_types.h"
  #include "DNA_scene_types.h"
  
  #include "BLI_math.h"
  #include "BLI_blenlib.h"
  #include "BLI_editVert.h"
 +#include "BLI_array.h"
  #include "BLI_utildefines.h"
  
  #include "BKE_context.h"
@@@ -62,7 -58,6 +62,7 @@@
  #include "BKE_node.h"
  #include "BKE_report.h"
  #include "BKE_scene.h"
 +#include "BKE_tessmesh.h"
  
  #include "ED_image.h"
  #include "ED_mesh.h"
  
  #include "uvedit_intern.h"
  
 +#define EFA_F1_FLAG   2
 +
  /************************* state testing ************************/
  
  int ED_uvedit_test(Object *obedit)
  {
 -      EditMesh *em;
 +      BMEditMesh *em;
        int ret;
  
 -      if(!obedit || obedit->type != OB_MESH)
 +      if (!obedit)
 +              return 0;
 +      
 +      if(obedit->type != OB_MESH)
                return 0;
  
 -      em = BKE_mesh_get_editmesh(obedit->data);
 -      ret = EM_texFaceCheck(em);
 -      BKE_mesh_end_editmesh(obedit->data, em);
 +      em = ((Mesh*)obedit->data)->edit_btmesh;
 +      ret = EDBM_texFaceCheck(em);
        
        return ret;
  }
  
+ static int ED_operator_uvedit_can_uv_sculpt(struct bContext *C)
+ {
+       SpaceImage *sima= CTX_wm_space_image(C);
+       ToolSettings *toolsettings = CTX_data_tool_settings(C);
+       Object *obedit= CTX_data_edit_object(C);
+       return ED_space_image_show_uvedit(sima, obedit) && !(toolsettings->use_uv_sculpt);
+ }
+ static int ED_operator_uvmap_mesh(bContext *C)
+ {
+       Object *ob= CTX_data_active_object(C);
+       if(ob && ob->type==OB_MESH) {
+               Mesh *me = ob->data;
+               if(CustomData_get_layer(&me->fdata, CD_MTFACE) != NULL)
+                       return 1;
+       }
+       return 0;
+ }
  /**************************** object active image *****************************/
  
  static int is_image_texture_node(bNode *node)
@@@ -144,10 -157,9 +166,10 @@@ void ED_object_assign_active_image(Mai
  
  void ED_uvedit_assign_image(Main *bmain, Scene *scene, Object *obedit, Image *ima, Image *previma)
  {
 -      EditMesh *em;
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMEditMesh *em;
 +      BMFace *efa;
 +      BMIter iter;
 +      MTexPoly *tf;
        int update= 0;
        
        /* skip assigning these procedural images... */
        if(!obedit || (obedit->type != OB_MESH))
                return;
  
 -      em= BKE_mesh_get_editmesh(((Mesh*)obedit->data));
 -      if(!em || !em->faces.first) {
 -              BKE_mesh_end_editmesh(obedit->data, em);
 +      em= ((Mesh*)obedit->data)->edit_btmesh;
 +      if(!em || !em->bm->totface) {
                return;
        }
  
        if(scene_use_new_shading_nodes(scene)) {
                /* new shading system, assign image in material */
                int sloppy= 1;
 -              EditFace *efa= EM_get_actFace(em, sloppy);
 +              BMFace *efa= BM_get_actFace(em->bm, sloppy);
  
                if(efa)
                        ED_object_assign_active_image(bmain, obedit, efa->mat_nr, ima);
                /* old shading system, assign image to selected faces */
                
                /* ensure we have a uv map */
 -              if(!CustomData_has_layer(&em->fdata, CD_MTFACE)) {
 -                      EM_add_data_layer(em, &em->fdata, CD_MTFACE, NULL);
 +              if(!CustomData_has_layer(&em->bm->pdata, CD_MTEXPOLY)) {
 +                      BM_add_data_layer(em->bm, &em->bm->pdata, CD_MTEXPOLY);
 +                      BM_add_data_layer(em->bm, &em->bm->ldata, CD_MLOOPUV);
                        update= 1;
                }
  
                /* now assign to all visible faces */
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 +              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, previma, efa, tf)) {
                                if(ima) {
                                        if(ima->id.us==0) id_us_plus(&ima->id);
                                        else id_lib_extern(&ima->id);
                                }
 -                              else
 +                              else {
                                        tf->tpage= NULL;
 +                              }
  
                                update = 1;
                        }
                        DAG_id_tag_update(obedit->data, 0);
        }
  
 -      BKE_mesh_end_editmesh(obedit->data, em);
  }
  
  /* dotile -   1, set the tile flag (from the space image)
   *                    2, set the tile index for the faces. */
  static int uvedit_set_tile(Object *obedit, Image *ima, int curtile)
  {
 -      EditMesh *em;
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMEditMesh *em;
 +      BMFace *efa;
 +      BMIter iter;
 +      MTexPoly *tf;
        
        /* verify if we have something to do */
        if(!ima || !ED_uvedit_test(obedit))
        if(ima->type==IMA_TYPE_R_RESULT || ima->type==IMA_TYPE_COMPOSITE)
                return 0;
        
 -      em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 +      em= ((Mesh*)obedit->data)->edit_btmesh;
  
 -      for(efa= em->faces.first; efa; efa= efa->next) {
 -              tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +              tf = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  
 -              if(efa->h==0 && efa->f & SELECT)
 +              if(!BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT))
                        tf->tile= curtile; /* set tile index */
        }
  
        DAG_id_tag_update(obedit->data, 0);
 -      BKE_mesh_end_editmesh(obedit->data, em);
  
        return 1;
  }
@@@ -247,7 -259,13 +269,13 @@@ static void uvedit_pixel_to_float(Space
  {
        int width, height;
  
-       ED_space_image_size(sima, &width, &height);
+       if(sima) {
+               ED_space_image_size(sima, &width, &height);
+       }
+       else {
+               width= 256;
+               height= 256;
+       }
  
        dist[0]= pixeldist/width;
        dist[1]= pixeldist/height;
  
  /*************** visibility and selection utilities **************/
  
 -int uvedit_face_visible_nolocal(Scene *scene, EditFace *efa)
 +int uvedit_face_visible_nolocal(Scene *scene, BMFace *efa)
  {
        ToolSettings *ts= scene->toolsettings;
  
        if(ts->uv_flag & UV_SYNC_SELECTION)
 -              return (efa->h==0);
 +              return (BM_TestHFlag(efa, BM_HIDDEN)==0);
        else
 -              return (efa->h==0 && (efa->f & SELECT));
 +              return (BM_TestHFlag(efa, BM_HIDDEN)==0 && BM_TestHFlag(efa, BM_SELECT));
  }
  
 -int uvedit_face_visible(Scene *scene, Image *ima, EditFace *efa, MTFace *tf)
 -{
 +int uvedit_face_visible(Scene *scene, Image *ima, BMFace *efa, MTexPoly *tf) {
        ToolSettings *ts= scene->toolsettings;
  
        if(ts->uv_flag & UV_SHOW_SAME_IMAGE)
                return uvedit_face_visible_nolocal(scene, efa);
  }
  
 -int uvedit_face_selected(Scene *scene, EditFace *efa, MTFace *tf)
 +int uvedit_face_selected(Scene *scene, BMEditMesh *em, BMFace *efa)
  {
        ToolSettings *ts= scene->toolsettings;
  
        if(ts->uv_flag & UV_SYNC_SELECTION)
 -              return (efa->f & SELECT);
 -      else
 -              return (!(~tf->flag & (TF_SEL1|TF_SEL2|TF_SEL3)) &&(!efa->v4 || tf->flag & TF_SEL4));
 +              return (BM_TestHFlag(efa, BM_SELECT));
 +      else {
 +              BMLoop *l;
 +              MLoopUV *luv;
 +              BMIter liter;
 +
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      if (!(luv->flag & MLOOPUV_VERTSEL))
 +                              return 0;
 +              }
 +
 +              return 1;
 +      }
  }
  
 -void uvedit_face_select(Scene *scene, EditFace *efa, MTFace *tf)
 +int uvedit_face_select(Scene *scene, BMEditMesh *em, BMFace *efa)
  {
        ToolSettings *ts= scene->toolsettings;
  
        if(ts->uv_flag & UV_SYNC_SELECTION)
 -              EM_select_face(efa, 1);
 -      else
 -              tf->flag |= (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
 +              BM_Select(em->bm, efa, TRUE);
 +      else {
 +              BMLoop *l;
 +              MLoopUV *luv;
 +              BMIter liter;
 +
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      luv->flag |= MLOOPUV_VERTSEL;
 +              }
 +
 +              return 1;
 +      }
 +
 +      return 0;
  }
  
 -void uvedit_face_deselect(Scene *scene, EditFace *efa, MTFace *tf)
 +int uvedit_face_deselect(Scene *scene, BMEditMesh *em, BMFace *efa)
  {
        ToolSettings *ts= scene->toolsettings;
  
 -      if(ts->uv_flag & UV_SYNC_SELECTION)
 -              EM_select_face(efa, 0);
 -      else
 -              tf->flag &= ~(TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4);
 +      if(ts->uv_flag & UV_SYNC_SELECTION) {
 +              BM_Select(em->bm, efa, FALSE);
 +      }
 +      else {
 +              BMLoop *l;
 +              MLoopUV *luv;
 +              BMIter liter;
 +
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      luv->flag &= ~MLOOPUV_VERTSEL;
 +              }
 +
 +              return 1;
 +      }
 +
 +      return 0;
  }
  
 -int uvedit_edge_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
 +int uvedit_edge_selected(BMEditMesh *em, Scene *scene, BMLoop *l)
  {
        ToolSettings *ts= scene->toolsettings;
 -      int nvert= (efa->v4)? 4: 3;
  
        if(ts->uv_flag & UV_SYNC_SELECTION) {
                if(ts->selectmode & SCE_SELECT_FACE)
 -                      return (efa->f & SELECT);
 -              else if(ts->selectmode & SCE_SELECT_EDGE)
 -                      return (*(&efa->e1 + i))->f & SELECT;
 -              else
 -                      return (((efa->v1 + i)->f & SELECT) && ((efa->v1 + (i+1)%nvert)->f & SELECT));
 +                      return BM_TestHFlag(l->f, BM_SELECT);
 +              else if(ts->selectmode == SCE_SELECT_EDGE) {
 +                      return BM_TestHFlag(l->e, BM_SELECT);
 +              } else
 +                      return BM_TestHFlag(l->v, BM_SELECT) && 
 +                             BM_TestHFlag(l->next->v, BM_SELECT);
 +      }
 +      else {
 +              MLoopUV *luv1, *luv2;
 +
 +              luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +              luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
 +
 +              return (luv1->flag & MLOOPUV_VERTSEL) && (luv2->flag & MLOOPUV_VERTSEL);
        }
 -      else
 -              return (tf->flag & TF_SEL_MASK(i)) && (tf->flag & TF_SEL_MASK((i+1)%nvert));
  }
  
 -void uvedit_edge_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
 +void uvedit_edge_select(BMEditMesh *em, Scene *scene, BMLoop *l)
 +
  {
        ToolSettings *ts= scene->toolsettings;
 -      int nvert= (efa->v4)? 4: 3;
  
        if(ts->uv_flag & UV_SYNC_SELECTION) {
                if(ts->selectmode & SCE_SELECT_FACE)
 -                      EM_select_face(efa, 1);
 +                      BM_Select(em->bm, l->f, TRUE);
                else if(ts->selectmode & SCE_SELECT_EDGE)
 -                      EM_select_edge((*(&efa->e1 + i)), 1);
 +                      BM_Select(em->bm, l->e, TRUE);
                else {
 -                      (efa->v1 + i)->f |= SELECT;
 -                      (efa->v1 + (i+1)%nvert)->f |= SELECT;
 +                      BM_Select(em->bm, l->e->v1, TRUE);
 +                      BM_Select(em->bm, l->e->v2, TRUE);
                }
        }
 -      else
 -              tf->flag |= TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert);
 +      else {
 +              MLoopUV *luv1, *luv2;
 +
 +              luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +              luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
 +              
 +              luv1->flag |= MLOOPUV_VERTSEL;
 +              luv2->flag |= MLOOPUV_VERTSEL;
 +      }
  }
  
 -void uvedit_edge_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
 +void uvedit_edge_deselect(BMEditMesh *em, Scene *scene, BMLoop *l)
 +
  {
        ToolSettings *ts= scene->toolsettings;
 -      int nvert= (efa->v4)? 4: 3;
  
        if(ts->uv_flag & UV_SYNC_SELECTION) {
                if(ts->selectmode & SCE_SELECT_FACE)
 -                      EM_select_face(efa, 0);
 +                      BM_Select(em->bm, l->f, FALSE);
                else if(ts->selectmode & SCE_SELECT_EDGE)
 -                      EM_select_edge((*(&efa->e1 + i)), 0);
 +                      BM_Select(em->bm, l->e, FALSE);
                else {
 -                      (efa->v1 + i)->f &= ~SELECT;
 -                      (efa->v1 + (i+1)%nvert)->f &= ~SELECT;
 +                      BM_Select(em->bm, l->e->v1, FALSE);
 +                      BM_Select(em->bm, l->e->v2, FALSE);
                }
        }
 -      else
 -              tf->flag &= ~(TF_SEL_MASK(i)|TF_SEL_MASK((i+1)%nvert));
 +      else {
 +              MLoopUV *luv1, *luv2;
 +
 +              luv1 = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +              luv2 = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
 +              
 +              luv1->flag &= ~MLOOPUV_VERTSEL;
 +              luv2->flag &= ~MLOOPUV_VERTSEL;
 +      }
  }
  
 -int uvedit_uv_selected(Scene *scene, EditFace *efa, MTFace *tf, int i)
 +int uvedit_uv_selected(BMEditMesh *em, Scene *scene, BMLoop *l)
  {
        ToolSettings *ts= scene->toolsettings;
  
        if(ts->uv_flag & UV_SYNC_SELECTION) {
                if(ts->selectmode & SCE_SELECT_FACE)
 -                      return (efa->f & SELECT);
 +                      return BM_TestHFlag(l->f, BM_SELECT);
                else
 -                      return (*(&efa->v1 + i))->f & SELECT;
 +                      return BM_TestHFlag(l->v, BM_SELECT);
 +      }
 +      else {
 +              MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +
 +              return luv->flag & MLOOPUV_VERTSEL;
        }
 -      else
 -              return tf->flag & TF_SEL_MASK(i);
  }
  
 -void uvedit_uv_select(Scene *scene, EditFace *efa, MTFace *tf, int i)
 +void uvedit_uv_select(BMEditMesh *em, Scene *scene, BMLoop *l)
  {
        ToolSettings *ts= scene->toolsettings;
  
        if(ts->uv_flag & UV_SYNC_SELECTION) {
                if(ts->selectmode & SCE_SELECT_FACE)
 -                      EM_select_face(efa, 1);
 +                      BM_Select(em->bm, l->f, TRUE);
                else
 -                      (*(&efa->v1 + i))->f |= SELECT;
 +                      BM_Select(em->bm, l->v, TRUE);
 +      }
 +      else {
 +              MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +              
 +              luv->flag |= MLOOPUV_VERTSEL;
        }
 -      else
 -              tf->flag |= TF_SEL_MASK(i);
  }
  
 -void uvedit_uv_deselect(Scene *scene, EditFace *efa, MTFace *tf, int i)
 +void uvedit_uv_deselect(BMEditMesh *em, Scene *scene, BMLoop *l)
  {
        ToolSettings *ts= scene->toolsettings;
  
        if(ts->uv_flag & UV_SYNC_SELECTION) {
                if(ts->selectmode & SCE_SELECT_FACE)
 -                      EM_select_face(efa, 0);
 +                      BM_Select(em->bm, l->f, FALSE);
                else
 -                      (*(&efa->v1 + i))->f &= ~SELECT;
 +                      BM_Select(em->bm, l->v, FALSE);
 +      }
 +      else {
 +              MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +              
 +              luv->flag &= ~MLOOPUV_VERTSEL;
        }
 -      else
 -              tf->flag &= ~TF_SEL_MASK(i);
  }
  
  /*********************** live unwrap utilities ***********************/
  
static void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
+ void uvedit_live_unwrap_update(SpaceImage *sima, Scene *scene, Object *obedit)
  {
        if(sima && (sima->flag & SI_LIVE_UNWRAP)) {
                ED_uvedit_live_unwrap_begin(scene, obedit);
  }
  
  /*********************** geometric utilities ***********************/
 +void poly_uv_center(BMEditMesh *em, BMFace *f, float cent[2])
 +{
 +      BMLoop *l;
 +      MLoopUV *luv;
 +      BMIter liter;
 +
 +      cent[0] = cent[1] = 0.0f;
 +
 +      BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, f) {
 +              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +              cent[0] += luv->uv[0];
 +              cent[1] += luv->uv[1];
 +      }
 +
 +      cent[0] /= (float) f->len;
 +      cent[1] /= (float) f->len;
 +}
 +
  
  void uv_center(float uv[][2], float cent[2], int quad)
  {
@@@ -517,28 -453,6 +545,28 @@@ float uv_area(float uv[][2], int quad
                return area_tri_v2(uv[0], uv[1], uv[2]); 
  }
  
 +float poly_uv_area(float uv[][2], int len)
 +{
 +      //BMESH_TODO: make this not suck
 +      //maybe use scanfill? I dunno.
 +
 +      if(len >= 4)
 +              return area_tri_v2(uv[0], uv[1], uv[2]) + area_tri_v2(uv[0], uv[2], uv[3]); 
 +      else
 +              return area_tri_v2(uv[0], uv[1], uv[2]); 
 +
 +      return 1.0;
 +}
 +
 +void poly_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy, int len)
 +{
 +      int i;
 +      for (i=0; i<len; i++) {
 +              uv[i][0] = uv_orig[i][0]*aspx;
 +              uv[i][1] = uv_orig[i][1]*aspy;
 +      }
 +}
 +
  void uv_copy_aspect(float uv_orig[][2], float uv[][2], float aspx, float aspy)
  {
        uv[0][0] = uv_orig[0][0]*aspx;
  
  int ED_uvedit_minmax(Scene *scene, Image *ima, Object *obedit, float *min, float *max)
  {
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        int sel;
  
        INIT_MINMAX2(min, max);
  
        sel= 0;
 -      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)) {
 -                      if(uvedit_uv_selected(scene, efa, tf, 0))                               { DO_MINMAX2(tf->uv[0], min, max); sel = 1; }
 -                      if(uvedit_uv_selected(scene, efa, tf, 1))                               { DO_MINMAX2(tf->uv[1], min, max); sel = 1; }
 -                      if(uvedit_uv_selected(scene, efa, tf, 2))                               { DO_MINMAX2(tf->uv[2], min, max); sel = 1; }
 -                      if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3)))  { DO_MINMAX2(tf->uv[3], min, max); sel = 1; }
 +      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);
 +                              DO_MINMAX2(luv->uv, min, max); 
 +                              sel = 1;
 +                      }
                }
        }
 -      
 -      BKE_mesh_end_editmesh(obedit->data, em);
 +
        return sel;
  }
  
  static int ED_uvedit_median(Scene *scene, Image *ima, Object *obedit, float co[3])
  {
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        unsigned int sel= 0;
  
        zero_v3(co);
 -
 -      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)) {
 -                      if(uvedit_uv_selected(scene, efa, tf, 0))                               { add_v3_v3(co, tf->uv[0]); sel++; }
 -                      if(uvedit_uv_selected(scene, efa, tf, 1))                               { add_v3_v3(co, tf->uv[1]); sel++; }
 -                      if(uvedit_uv_selected(scene, efa, tf, 2))                               { add_v3_v3(co, tf->uv[2]); sel++; }
 -                      if(efa->v4 && (uvedit_uv_selected(scene, efa, tf, 3)))  { add_v3_v3(co, tf->uv[3]); sel++; }
 +      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) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      if (uvedit_uv_selected(em, scene, l)) {
 +                              add_v2_v2(co, luv->uv);
 +                              sel++;
 +                      }
                }
        }
  
        mul_v3_fl(co, 1.0f/(float)sel);
  
 -      BKE_mesh_end_editmesh(obedit->data, em);
        return (sel != 0);
  }
  
  static int uvedit_center(Scene *scene, Image *ima, Object *obedit, float *cent, char mode)
  {
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
        float min[2], max[2];
        int change= 0;
        
        }
  
        if(change) {
 -              BKE_mesh_end_editmesh(obedit->data, em);
                return 1;
        }
  
 -      BKE_mesh_end_editmesh(obedit->data, em);
        return 0;
  }
  
  /************************** 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));
  
 -      for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
 -              eve->tmp.l = i;
 +      BM_ElemIndex_Ensure(em->bm, BM_VERT);
        
 -      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;
 -
 -                      for(i=0; i<nverts; i++) {
 -                              dist= dist_to_line_segment_v2(co, tf->uv[i], tf->uv[(i+1)%nverts]);
 +      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;
 +              
 +              i = 0;
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
  
 -                              if(dist < mindist) {
 -                                      hit->tf= tf;
 -                                      hit->efa= efa;
 -                                      hit->edge= i;
 -                                      mindist= dist;
 +                      dist= dist_to_line_segment_v2(co, luv->uv, nextluv->uv);
  
 -                                      hit->vert= (*(&efa->v1 + i))->tmp.l;
 -                                      hit->vert2= (*(&efa->v1 + ((i+1)%nverts)))->tmp.l;
 -                              }
 +                      if(dist < mindist) {
 +                              hit->tf= tf;
 +                              hit->efa= efa;
 +                              
 +                              hit->l = l;
 +                              hit->nextl = l->next;
 +                              hit->luv = luv;
 +                              hit->nextluv = nextluv;
 +                              hit->lindex = i;
 +                              hit->vert1 = BM_GetIndex(hit->l->v);
 +                              hit->vert2 = BM_GetIndex(hit->l->next->v);
 +
 +                              mindist = dist;
                        }
 +
 +                      i++;
                }
        }
  }
  
 -static void find_nearest_uv_face(Scene *scene, Image *ima, EditMesh *em, float co[2], NearestHit *hit)
 +static void find_nearest_uv_face(Scene *scene, Image *ima, BMEditMesh *em, float co[2], NearestHit *hit)
  {
 -      MTFace *tf;
 -      EditFace *efa;
 +      MTexPoly *tf;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MLoopUV *luv;
        float mindist, dist, cent[2];
 -      int i, nverts;
  
        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;
                }
        }
  }
  
 -static int nearest_uv_between(MTFace *tf, int nverts, int id, float co[2], float uv[2])
 +static int nearest_uv_between(BMEditMesh *em, BMFace *efa, int UNUSED(nverts), int id,
 +                            float co[2], float uv[2])
  {
 -      float m[3], v1[3], v2[3], c1, c2;
 -      int id1, id2;
 +      BMLoop *l;
 +      MLoopUV *luv;
 +      BMIter iter;
 +      float m[3], v1[3], v2[3], c1, c2, *uv1, *uv2, *uv3;
 +      int id1, id2, i;
  
 -      id1= (id+nverts-1)%nverts;
 -      id2= (id+nverts+1)%nverts;
 +      id1= (id+efa->len-1)%efa->len;
 +      id2= (id+efa->len+1)%efa->len;
  
        m[0]= co[0]-uv[0];
        m[1]= co[1]-uv[1];
 -      sub_v2_v2v2(v1, tf->uv[id1], tf->uv[id]);
 -      sub_v2_v2v2(v2, tf->uv[id2], tf->uv[id]);
 +
 +      i = 0;
 +      BM_ITER(l, &iter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +              luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +              
 +              if (i == id1)
 +                      uv1 = luv->uv;
 +              else if (i == id)
 +                      uv2 = luv->uv;
 +              else if (i == id2)
 +                      uv3 = luv->uv;
 +
 +              i++;
 +      }
 +
 +      sub_v3_v3v3(v1, uv1, uv);
 +      sub_v3_v3v3(v2, uv3, uv);
  
        /* m and v2 on same side of v-v1? */
        c1= v1[0]*m[1] - v1[1]*m[0];
        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));
        
 -      for(i=0, eve=em->verts.first; eve; eve=eve->next, i++)
 -              eve->tmp.l = i;
 -      
 -      for(efa= em->faces.first; efa; efa= efa->next) {
 -              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 +      BM_ElemIndex_Ensure(em->bm, BM_VERT);
  
 -              if(uvedit_face_visible(scene, ima, efa, tf)) {
 -                      nverts= efa->v4? 4: 3;
 -
 -                      for(i=0; i<nverts; i++) {
 -                              if(penalty && uvedit_uv_selected(scene, efa, tf, i))
 -                                      dist= fabsf(co[0]-tf->uv[i][0])+penalty[0] + fabsf(co[1]-tf->uv[i][1]) + penalty[1];
 -                              else
 -                                      dist= fabsf(co[0]-tf->uv[i][0]) + fabsf(co[1]-tf->uv[i][1]);
 +      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;
 +              
 +              i = 0;
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
  
 -                              if(dist<=mindist) {
 -                                      if(dist==mindist)
 -                                              if(!nearest_uv_between(tf, nverts, i, co, tf->uv[i]))
 -                                                      continue;
 +                      if(penalty && uvedit_uv_selected(em, scene, l))
 +                              dist= fabs(co[0]-luv->uv[0])+penalty[0] + fabs(co[1]-luv->uv[1])+penalty[1];
 +                      else
 +                              dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
  
 -                                      mindist= dist;
 +                      if(dist<=mindist) {
 +                              if(dist==mindist)
 +                                      if(!nearest_uv_between(em, efa, efa->len, i, co, luv->uv)) {
 +                                              i++;
 +                                              continue;
 +                                      }
  
 -                                      hit->uv= i;
 -                                      hit->tf= tf;
 -                                      hit->efa= efa;
 +                              mindist= dist;
  
 -                                      hit->vert= (*(&efa->v1 + i))->tmp.l;
 -                              }
 +                              hit->l = l;
 +                              hit->nextl = l->next;
 +                              hit->luv = luv;
 +                              hit->nextluv = CustomData_bmesh_get(&em->bm->ldata, l->next->head.data, CD_MLOOPUV);
 +                              hit->tf= tf;
 +                              hit->efa= efa;
 +                              hit->lindex = i;
 +                              hit->vert1 = BM_GetIndex(hit->l->v);
                        }
 +
 +                      i++;
                }
        }
  }
  
  int ED_uvedit_nearest_uv(Scene *scene, Object *obedit, Image *ima, float co[2], float uv[2])
  {
 -      EditMesh *em= BKE_mesh_get_editmesh((Mesh*)obedit->data);
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMEditMesh *em= ((Mesh*)obedit->data)->edit_btmesh;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        float mindist, dist;
 -      int i, nverts, found= 0;
 +      int found= 0;
  
        mindist= 1e10f;
        uv[0]= co[0];
        uv[1]= co[1];
        
 -      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;
 -
 -                      for(i=0; i<nverts; i++) {
 -                              if(uvedit_uv_selected(scene, efa, tf, i))
 -                                      continue;
 -
 -                              dist= fabs(co[0]-tf->uv[i][0]) + fabs(co[1]-tf->uv[i][1]);
 +      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) {
 +                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      dist= fabs(co[0]-luv->uv[0]) + fabs(co[1]-luv->uv[1]);
  
 -                              if(dist<=mindist) {
 -                                      mindist= dist;
 +                      if(dist<=mindist) {
 +                              mindist= dist;
  
 -                                      uv[0]= tf->uv[i][0];
 -                                      uv[1]= tf->uv[i][1];
 -                                      found= 1;
 -                              }
 +                              uv[0]= luv->uv[0];
 +                              uv[1]= luv->uv[1];
 +                              found= 1;
                        }
                }
        }
  
 -      BKE_mesh_end_editmesh(obedit->data, em);
        return found;
  }
  
@@@ -900,28 -748,37 +919,49 @@@ static void uv_vertex_loop_flag(UvMapVe
                first->flag= 1;
  }
  
 -static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, EditFace *efa, int a)
 +static UvMapVert *uv_vertex_map_get(UvVertMap *vmap, BMFace *efa, int a)
  {
        UvMapVert *iterv, *first;
 -      
 -      first= EM_get_uv_map_vert(vmap, (*(&efa->v1 + a))->tmp.l);
 +      BMLoop *l;
 +
 +      l = BMIter_AtIndex(NULL, BM_LOOPS_OF_FACE, efa, a);
 +      first= EDBM_get_uv_map_vert(vmap,  BM_GetIndex(l->v));
  
        for(iterv=first; iterv; iterv=iterv->next) {
                if(iterv->separate)
                        first= iterv;
 -              if(iterv->f == efa->tmp.l)
 +              if(iterv->f == BM_GetIndex(efa))
                        return first;
        }
        
        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 */
  
                        if(iterv1->f == iterv2->f) {
                                /* if face already tagged, don't do this edge */
 -                              efa= EM_get_face_for_index(iterv1->f);
 -                              if(efa->f1)
 +                              efa= EDBM_get_face_for_index(em, iterv1->f);
 +                              if(BMO_TestFlag(em->bm, efa, EFA_F1_FLAG))
                                        return 0;
  
                                tot++;
                                break;
  
                        if(iterv1->f == iterv2->f) {
 -                              efa= EM_get_face_for_index(iterv1->f);
 -                              efa->f1= 1;
 +                              efa= EDBM_get_face_for_index(em, iterv1->f);
 +                              BMO_SetFlag(em->bm, efa, EFA_F1_FLAG);
                                break;
                        }
                }
        return 1;
  }
  
 -static int select_edgeloop(Scene *scene, Image *ima, EditMesh *em, NearestHit *hit, float limit[2], int extend)
 +static int select_edgeloop(Scene *scene, Image *ima, BMEditMesh *em, NearestHit *hit, float limit[2], int extend)
  {
 -      EditVert *eve;
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMFace *efa;
 +      BMIter iter, liter;
 +      BMLoop *l;
 +      MTexPoly *tf;
        UvVertMap *vmap;
        UvMapVert *iterv1, *iterv2;
        int a, count, looking, nverts, starttotf, select;
  
        /* setup */
 -      EM_init_index_arrays(em, 0, 0, 1);
 -      vmap= EM_make_uv_vert_map(em, 0, 0, limit);
 +      EDBM_init_index_arrays(em, 0, 0, 1);
 +      vmap= EDBM_make_uv_vert_map(em, 0, 0, limit);
  
 -      for(count=0, eve=em->verts.first; eve; count++, eve= eve->next)
 -              eve->tmp.l = count;
 +      BM_ElemIndex_Ensure(em->bm, BM_VERT);
  
 -      for(count=0, efa= em->faces.first; efa; count++, efa= efa->next) {
 +      count = 0;
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
                if(!extend) {
 -                      tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -                      uvedit_face_deselect(scene, efa, tf);
 +                      uvedit_face_deselect(scene, em, efa);
                }
 +              
 +              BMO_ClearFlag(em->bm, efa, EFA_F1_FLAG);
  
 -              efa->tmp.l= count;
 -              efa->f1= 0;
 +              BM_SetIndex(efa, count); /* set_inline */
 +
 +              count++;
        }
 -      
 +      em->bm->elem_index_dirty &= ~BM_FACE;
 +
        /* set flags for first face and verts */
 -      nverts= (hit->efa->v4)? 4: 3;
 -      iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
 -      iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
 +      nverts= hit->efa->len;
 +      iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
 +      iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
        uv_vertex_loop_flag(iterv1);
        uv_vertex_loop_flag(iterv2);
  
        starttotf= 0;
 -      uv_edge_tag_faces(iterv1, iterv2, &starttotf);
 +      uv_edge_tag_faces(em, iterv1, iterv2, &starttotf);
  
        /* sorry, first edge isnt even ok */
        if(iterv1->flag==0 && iterv2->flag==0) looking= 0;
                looking= 0;
  
                /* find correct valence edges which are not tagged yet, but connect to tagged one */
 -              for(efa= em->faces.first; efa; efa=efa->next) {
 -                      tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
  
 -                      if(!efa->f1 && uvedit_face_visible(scene, ima, efa, tf)) {
 -                              nverts= (efa->v4)? 4: 3;
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +
 +                      if(!BMO_TestFlag(em->bm, efa, EFA_F1_FLAG) && uvedit_face_visible(scene, ima, efa, tf)) {
 +                              nverts= efa->len;
                                for(a=0; a<nverts; a++) {
                                        /* check face not hidden and not tagged */
                                        iterv1= uv_vertex_map_get(vmap, efa, a);
                                        iterv2= uv_vertex_map_get(vmap, efa, (a+1)%nverts);
 +                                      
 +                                      if (!iterv1 || !iterv2)
 +                                              continue;
  
                                        /* check if vertex is tagged and has right valence */
                                        if(iterv1->flag || iterv2->flag) {
 -                                              if(uv_edge_tag_faces(iterv1, iterv2, &starttotf)) {
 +                                              if(uv_edge_tag_faces(em, iterv1, iterv2, &starttotf)) {
                                                        looking= 1;
 -                                                      efa->f1= 1;
 +                                                      BMO_SetFlag(em->bm, efa, EFA_F1_FLAG);
  
                                                        uv_vertex_loop_flag(iterv1);
                                                        uv_vertex_loop_flag(iterv2);
        }
  
        /* do the actual select/deselect */
 -      nverts= (hit->efa->v4)? 4: 3;
 -      iterv1= uv_vertex_map_get(vmap, hit->efa, hit->edge);
 -      iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->edge+1)%nverts);
 +      nverts= hit->efa->len;
 +      iterv1= uv_vertex_map_get(vmap, hit->efa, hit->lindex);
 +      iterv2= uv_vertex_map_get(vmap, hit->efa, (hit->lindex+1)%nverts);
        iterv1->flag= 1;
        iterv2->flag= 1;
  
        if(extend) {
 -              tf= CustomData_em_get(&em->fdata, hit->efa->data, CD_MTFACE);
 -
 -              if(uvedit_uv_selected(scene, hit->efa, tf, hit->edge))
 +              if(uvedit_uv_selected(em, scene, hit->l))
                        select= 0;
                else
                        select= 1;
        else
                select= 1;
        
 -      for(efa= em->faces.first; efa; efa=efa->next) {
 -              tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +              tf= CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
  
 -              nverts= (efa->v4)? 4: 3;
 -              for(a=0; a<nverts; a++) {
 +              a = 0;
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
                        iterv1= uv_vertex_map_get(vmap, efa, a);
  
                        if(iterv1->flag) {
 -                              if(select) uvedit_uv_select(scene, efa, tf, a);
 -                              else uvedit_uv_deselect(scene, efa, tf, a);
 +                              if(select) uvedit_uv_select(em, scene, l);
 +                              else uvedit_uv_deselect(em, scene, l);
                        }
 +
 +                      a++;
                }
        }
  
        /* cleanup */
 -      EM_free_uv_vert_map(vmap);
 -      EM_free_index_arrays();
 +      EDBM_free_uv_vert_map(vmap);
 +      EDBM_free_index_arrays(em);
  
        return (select)? 1: -1;
  }
  
  /*********************** linked select ***********************/
  
 -static void select_linked(Scene *scene, Image *ima, EditMesh *em, float limit[2], NearestHit *hit, int extend)
 +static void select_linked(Scene *scene, Image *ima, BMEditMesh *em, float limit[2], NearestHit *hit, int extend)
  {
 -      EditFace *efa;
 -      MTFace *tf;
 +      BMFace *efa;
 +      BMLoop *l;
 +      BMIter iter, liter;
 +      MTexPoly *tf;
 +      MLoopUV *luv;
        UvVertMap *vmap;
        UvMapVert *vlist, *iterv, *startv;
        int i, nverts, stacksize= 0, *stack;
        unsigned int a;
        char *flag;
  
 -      EM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
 -      vmap= EM_make_uv_vert_map(em, 1, 0, limit);
 +      EDBM_init_index_arrays(em, 0, 0, 1); /* we can use this too */
 +      vmap= EDBM_make_uv_vert_map(em, 1, 1, limit);
 +
        if(vmap == NULL)
                return;
  
 -      stack= MEM_mallocN(sizeof(*stack) * em->totface, "UvLinkStack");
 -      flag= MEM_callocN(sizeof(*flag) * em->totface, "UvLinkFlag");
 +      stack= MEM_mallocN(sizeof(*stack)*(em->bm->totface+1), "UvLinkStack");
 +      flag= MEM_callocN(sizeof(*flag)*em->bm->totface, "UvLinkFlag");
  
        if(!hit) {
 -              for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
 -                      tf = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 +              a = 0;
 +              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)) {
 -                              const char select_flag= efa->v4 ? (TF_SEL1|TF_SEL2|TF_SEL3|TF_SEL4) : (TF_SEL1|TF_SEL2|TF_SEL3);
 -                              if(tf->flag & select_flag) {
 -                                      stack[stacksize]= a;
 -                                      stacksize++;
 -                                      flag[a]= 1;
 +                      if(uvedit_face_visible(scene, ima, efa, tf)) { 
 +                              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                                      luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +
 +                                      if (luv->flag & MLOOPUV_VERTSEL) {
 +                                              stack[stacksize]= a;
 +                                              stacksize++;
 +                                              flag[a]= 1;
 +
 +                                              break;
 +                                      }
                                }
                        }
                }
 +              a++;
        }
        else {
 -              for(a=0, efa= em->faces.first; efa; efa= efa->next, a++) {
 +              a = 0;
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
                        if(efa == hit->efa) {
                                stack[stacksize]= a;
                                stacksize++;
                                flag[a]= 1;
                                break;
                        }
 +
 +                      a++;
                }
        }
  
        while(stacksize > 0) {
 +              int j;
 +
                stacksize--;
                a= stack[stacksize];
 +              
 +              j = 0;
 +              BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +                      if(j==a)
 +                              break;
 +
 +                      j++;
 +              }
  
 -              efa = EM_get_face_for_index(a);
 +              nverts= efa->len;
  
 -              nverts= efa->v4? 4: 3;
 +              i = 0;
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
  
 -              for(i=0; i<nverts; i++) {
                        /* make_uv_vert_map_EM sets verts tmp.l to the indices */
 -                      vlist= EM_get_uv_map_vert(vmap, (*(&efa->v1 + i))->tmp.l);
 +                      vlist= EDBM_get_uv_map_vert(vmap, BM_GetIndex(l->v));
                        
                        startv= vlist;
  
                                        stacksize++;
                                }
                   &nbs