svn merge -r37078:37335 https://svn.blender.org/svnroot/bf-blender/trunk/blender
authorCampbell Barton <ideasman42@gmail.com>
Thu, 9 Jun 2011 15:20:29 +0000 (15:20 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 9 Jun 2011 15:20:29 +0000 (15:20 +0000)
51 files changed:
1  2 
release/scripts/startup/bl_ui/space_view3d.py
source/blender/blenkernel/BKE_blender.h
source/blender/blenkernel/BKE_multires.h
source/blender/blenkernel/intern/blender.c
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/deform.c
source/blender/blenkernel/intern/multires.c
source/blender/blenkernel/intern/object.c
source/blender/blenkernel/intern/particle.c
source/blender/blenlib/BLI_math_geom.h
source/blender/blenlib/BLI_math_vector.h
source/blender/blenlib/BLI_utildefines.h
source/blender/blenlib/intern/math_geom.c
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_util.h
source/blender/editors/include/ED_view3d.h
source/blender/editors/object/object_add.c
source/blender/editors/object/object_bake.c
source/blender/editors/object/object_modifier.c
source/blender/editors/object/object_shapekey.c
source/blender/editors/object/object_vgroup.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/screen/screen_ops.c
source/blender/editors/sculpt_paint/paint_image.c
source/blender/editors/sculpt_paint/paint_vertex.c
source/blender/editors/sculpt_paint/sculpt.c
source/blender/editors/space_api/spacetypes.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_header.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/editors/space_view3d/view3d_view.c
source/blender/editors/transform/transform.c
source/blender/editors/transform/transform_conversions.c
source/blender/editors/util/editmode_undo.c
source/blender/editors/uvedit/uvedit_ops.c
source/blender/editors/uvedit/uvedit_parametrizer.c
source/blender/makesdna/DNA_userdef_types.h
source/blender/makesrna/intern/rna_mesh.c
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_object.c
source/blender/makesrna/intern/rna_scene.c
source/blender/modifiers/CMakeLists.txt
source/blender/modifiers/intern/MOD_edgesplit.c
source/blender/modifiers/intern/MOD_meshdeform.c
source/blender/windowmanager/CMakeLists.txt
source/creator/CMakeLists.txt
source/creator/creator.c

index 1aeb2b5fce6dda5ec164b57716e03934b8998dd0,07f0885372a4e4fe3f5b91ea1197655578db2a00..ba9036e1b05ef2a91628c1e3d7a05fc34a2bcf81
@@@ -89,7 -89,7 +89,8 @@@ extern int BKE_undo_valid(const char *n
  extern void BKE_reset_undo(void);
  extern char *BKE_undo_menu_string(void);
  extern void BKE_undo_number(struct bContext *C, int nr);
+ extern char *BKE_undo_get_name(int nr, int *active);
 +void BKE_undo_save(char *fname);
  extern void BKE_undo_save_quit(void);
  extern struct Main *BKE_undo_get_main(struct Scene **scene);
  
index 6e255438fa8d7c4f02c277381f3fa4fa6b813f56,45faba8439c728e72e16643cadf511d771edbb9f..bb01de6e8d586c18394c86463a17789df1508623
@@@ -470,20 -438,120 +470,138 @@@ static void layerSwap_mdisps(void *data
        }
  }
  
-       
++#if 1 /* BMESH_TODO: place holder function, dont actually interp */
 +static void layerInterp_mdisps(void **sources, float *UNUSED(weights),
 +                              float *UNUSED(sub_weights), int UNUSED(count), void *dest)
 +{
 +      MDisps *d = dest;
 +
 +      /* happens when flipping normals of newly created mesh */
 +      if(!d->totdisp) {
 +              d->totdisp = ((MDisps*)sources[0])->totdisp;
 +      }
++
 +      if (!d->disps && d->totdisp)
 +              d->disps = BLI_cellalloc_calloc(sizeof(float)*3*d->totdisp, "blank mdisps in layerInterp_mdisps");
 +}
 +
++#else // BMESH_TODO
++
+ static void layerInterp_mdisps(void **sources, float *UNUSED(weights),
+                               float *sub_weights, int count, void *dest)
+ {
+       MDisps *d = dest;
+       MDisps *s = NULL;
+       int st, stl;
+       int i, x, y;
+       int side, S, dst_corners, src_corners;
+       float crn_weight[4][2];
+       float (*sw)[4] = (void*)sub_weights;
+       float (*disps)[3], (*out)[3];
+       /* happens when flipping normals of newly created mesh */
+       if(!d->totdisp)
+               return;
+       s = sources[0];
+       dst_corners = multires_mdisp_corners(d);
+       src_corners = multires_mdisp_corners(s);
+       if(sub_weights && count == 2 && src_corners == 3) {
+               src_corners = multires_mdisp_corners(sources[1]);
+               /* special case -- converting two triangles to quad */
+               if(src_corners == 3 && dst_corners == 4) {
+                       MDisps tris[2];
+                       int vindex[4] = {0};
+                       S = 0;
+                       for(i = 0; i < 2; i++)
+                               for(y = 0; y < 4; y++)
+                                       for(x = 0; x < 4; x++)
+                                               if(sw[x+i*4][y])
+                                                       vindex[x] = y;
+                       for(i = 0; i < 2; i++) {
+                               float sw_m4[4][4] = {{0}};
+                               int a = 7 & ~(1 << vindex[i*2] | 1 << vindex[i*2+1]);
+                               sw_m4[0][vindex[i*2+1]] = 1;
+                               sw_m4[1][vindex[i*2]] = 1;
+                               for(x = 0; x < 3; x++)
+                                       if(a & (1 << x))
+                                               sw_m4[2][x] = 1;
+                               tris[i] = *((MDisps*)sources[i]);
+                               tris[i].disps = MEM_dupallocN(tris[i].disps);
+                               layerInterp_mdisps(&sources[i], NULL, (float*)sw_m4, 1, &tris[i]);
+                       }
+                       mdisp_join_tris(d, &tris[0], &tris[1]);
+                       for(i = 0; i < 2; i++)
+                               MEM_freeN(tris[i].disps);
+                       return;
+               }
+       }
+       /* For now, some restrictions on the input */
+       if(count != 1 || !sub_weights) {
+               for(i = 0; i < d->totdisp; ++i)
+                       zero_v3(d->disps[i]);
+               return;
+       }
+       /* Initialize the destination */
+       disps = MEM_callocN(3*d->totdisp*sizeof(float), "iterp disps");
+       side = sqrt(d->totdisp / dst_corners);
+       st = (side<<1)-1;
+       stl = st - 1;
+       sw= (void*)sub_weights;
+       for(i = 0; i < 4; ++i) {
+               crn_weight[i][0] = 0 * sw[i][0] + stl * sw[i][1] + stl * sw[i][2] + 0 * sw[i][3];
+               crn_weight[i][1] = 0 * sw[i][0] + 0 * sw[i][1] + stl * sw[i][2] + stl * sw[i][3];
+       }
+       multires_mdisp_smooth_bounds(s);
+       out = disps;
+       for(S = 0; S < dst_corners; S++) {
+               float base[2], axis_x[2], axis_y[2];
+               mdisp_apply_weight(S, dst_corners, 0, 0, st, crn_weight, &base[0], &base[1]);
+               mdisp_apply_weight(S, dst_corners, side-1, 0, st, crn_weight, &axis_x[0], &axis_x[1]);
+               mdisp_apply_weight(S, dst_corners, 0, side-1, st, crn_weight, &axis_y[0], &axis_y[1]);
+               sub_v2_v2(axis_x, base);
+               sub_v2_v2(axis_y, base);
+               normalize_v2(axis_x);
+               normalize_v2(axis_y);
+               for(y = 0; y < side; ++y) {
+                       for(x = 0; x < side; ++x, ++out) {
+                               int crn;
+                               float face_u, face_v, crn_u, crn_v;
+                               mdisp_apply_weight(S, dst_corners, x, y, st, crn_weight, &face_u, &face_v);
+                               crn = mdisp_rot_face_to_quad_crn(src_corners, st, face_u, face_v, &crn_u, &crn_v);
+                               old_mdisps_bilinear((*out), &s->disps[crn*side*side], side, crn_u, crn_v);
+                               mdisp_flip_disp(crn, dst_corners, axis_x, axis_y, *out);
+                       }
+               }
+       }
+       MEM_freeN(d->disps);
+       d->disps = disps;
+ }
++#endif // BMESH_TODO
  static void layerCopy_mdisps(const void *source, void *dest, int count)
  {
        int i;
index 01ef39487d64daf5fa28f30204635955941490c1,5802bb2b697ef06977ce10340fa44b0dbb99068d..3dfec66d2e5fe91fa52d9e434aa0d882d8f8003d
@@@ -444,10 -438,10 +443,10 @@@ void multiresModifier_del_levels(Multir
        int lvl = multires_get_level(ob, mmd, 0);
        int levels = mmd->totlvl - lvl;
        MDisps *mdisps;
-       
        multires_set_tot_mdisps(me, mmd->totlvl);
 -      CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
 -      mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
 +      CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
 +      mdisps= CustomData_get_layer(&me->ldata, CD_MDISPS);
  
        multires_force_update(ob);
  
@@@ -833,10 -810,9 +832,9 @@@ static void multiresModifier_update(Der
        ob = ccgdm->multires.ob;
        me = ccgdm->multires.ob->data;
        mmd = ccgdm->multires.mmd;
        multires_set_tot_mdisps(me, mmd->totlvl);
 -      CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
 -      mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
 +      CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop);
 +      mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
  
        if(mdisps) {
                int lvl = ccgdm->multires.lvl;
@@@ -1769,8 -1601,7 +1767,8 @@@ static void multires_apply_smat(Scene *
        DerivedMesh *dm= NULL, *cddm= NULL, *subdm= NULL;
        DMGridData **gridData, **subGridData;
        Mesh *me= (Mesh*)ob->data;
 -      MFace *mface= me->mface;
 +      MPoly *mpoly= me->mpoly;
-       MLoop *mloop = me->mloop;
++      /* MLoop *mloop = me->mloop; */ /* UNUSED */
        MDisps *mdisps;
        int *gridOffset;
        int i, /*numGrids,*/ gridSize, dGridSize, dSkip, totvert;
@@@ -1895,6 -1726,58 +1893,60 @@@ void multiresModifier_prepare_join(Scen
        multires_apply_smat(scene, ob, mat);
  }
  
+ /* update multires data after topology changing */
++#if 0 // BMESH_TODO
+ void multires_topology_changed(Scene *scene, Object *ob)
+ {
+       Mesh *me= (Mesh*)ob->data;
+       MDisps *mdisp= NULL, *cur= NULL;
+       int i, grid= 0, corners;
+       MultiresModifierData *mmd= get_multires_modifier(scene, ob, 1);
+       if(mmd)
+               multires_set_tot_mdisps(me, mmd->totlvl);
+       CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
+       mdisp= CustomData_get_layer(&me->fdata, CD_MDISPS);
+       if(!mdisp) return;
+       cur= mdisp;
+       for(i = 0; i < me->totface; i++, cur++) {
+               if(mdisp->totdisp) {
+                       corners= multires_mdisp_corners(mdisp);
+                       grid= mdisp->totdisp / corners;
+                       break;
+               }
+       }
+       for(i = 0; i < me->totface; i++, mdisp++) {
+               int nvert= me->mface[i].v4 ? 4 : 3;
+               /* allocate memory for mdisp, the whole disp layer would be erased otherwise */
+               if(!mdisp->totdisp || !mdisp->disps) {
+                       if(grid) {
+                               mdisp->totdisp= nvert*grid;
+                               mdisp->disps= MEM_callocN(mdisp->totdisp*sizeof(float)*3, "mdisp topology");
+                       }
+                       continue;
+               }
+               corners= multires_mdisp_corners(mdisp);
+               if(corners!=nvert) {
+                       mdisp->totdisp= (mdisp->totdisp/corners)*nvert;
+                       if(mdisp->disps)
+                               MEM_freeN(mdisp->disps);
+                       mdisp->disps= MEM_callocN(mdisp->totdisp*sizeof(float)*3, "mdisp topology");
+               }
+       }
+ }
++#endif // BMESH_TODO
  /* makes displacement along grid boundary symmetrical */
  void multires_mdisp_smooth_bounds(MDisps *disps)
  {
index b513bab3924f4edac875f9f2635201c014d477c0,565c5810cff82c284d7d1cc3e084f90b31914d97..5dc161c6267088e7b8d467fcf000fdf86ba7c72a
  
  #include "object_intern.h"
  
 -              dm= CDDM_copy(tmp_dm);
+ /* ****************** multires BAKING ********************** */
+ /* holder of per-object data needed for bake job
+    needed to make job totally thread-safe */
+ typedef struct MultiresBakerJobData {
+       struct MultiresBakerJobData *next, *prev;
+       DerivedMesh *lores_dm, *hires_dm;
+       int simple, lvl, tot_lvl;
+ } MultiresBakerJobData;
+ /* data passing to multires-baker job */
+ typedef struct {
+       ListBase data;
+       int bake_clear, bake_filter;
+       short mode, use_lores_mesh;
+ } MultiresBakeJob;
+ /* data passing to multires baker */
+ typedef struct {
+       DerivedMesh *lores_dm, *hires_dm;
+       int simple, lvl, tot_lvl, bake_filter;
+       short mode, use_lores_mesh;
+       int tot_obj, tot_image;
+       ListBase image;
+       int baked_objects, baked_faces;
+       short *stop;
+       short *do_update;
+       float *progress;
+ } MultiresBakeRender;
+ typedef void (*MPassKnownData)(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data,
+                                const int face_index, const int lvl, const float st[2],
+                                float tangmat[3][3], const int x, const int y);
+ typedef void* (*MInitBakeData)(MultiresBakeRender *bkr, Image* ima);
+ typedef void (*MApplyBakeData)(void *bake_data);
+ typedef void (*MFreeBakeData)(void *bake_data);
+ typedef struct {
+       MVert *mvert;
+       MFace *mface;
+       MTFace *mtface;
+       float *pvtangent;
+       float *precomputed_normals;
+       int w, h;
+       int face_index;
+       int i0, i1, i2;
+       DerivedMesh *lores_dm, *hires_dm;
+       int lvl;
+       void *bake_data;
+       MPassKnownData pass_data;
+ } MResolvePixelData;
+ typedef void (*MFlushPixel)(const MResolvePixelData *data, const int x, const int y);
+ typedef struct {
+       int w, h;
+       char *texels;
+       const MResolvePixelData *data;
+       MFlushPixel flush_pixel;
+ } MBakeRast;
+ typedef struct {
+       float *heights;
+       float height_min, height_max;
+       Image *ima;
+       DerivedMesh *ssdm;
+ } MHeightBakeData;
+ static void multiresbake_get_normal(const MResolvePixelData *data, float norm[], const int face_num, const int vert_index)
+ {
+       unsigned int indices[]= {data->mface[face_num].v1, data->mface[face_num].v2,
+                              data->mface[face_num].v3, data->mface[face_num].v4};
+       const int smoothnormal= (data->mface[face_num].flag & ME_SMOOTH);
+       if(!smoothnormal)  { /* flat */
+               if(data->precomputed_normals) {
+                       copy_v3_v3(norm, &data->precomputed_normals[3*face_num]);
+               } else {
+                       float nor[3];
+                       float *p0, *p1, *p2;
+                       const int iGetNrVerts= data->mface[face_num].v4!=0 ? 4 : 3;
+                       p0= data->mvert[indices[0]].co;
+                       p1= data->mvert[indices[1]].co;
+                       p2= data->mvert[indices[2]].co;
+                       if(iGetNrVerts==4) {
+                               float *p3= data->mvert[indices[3]].co;
+                               normal_quad_v3(nor, p0, p1, p2, p3);
+                       } else {
+                               normal_tri_v3(nor, p0, p1, p2);
+                       }
+                       copy_v3_v3(norm, nor);
+               }
+       } else {
+               short *no= data->mvert[indices[vert_index]].no;
+               normal_short_to_float_v3(norm, no);
+               normalize_v3(norm);
+       }
+ }
+ static void init_bake_rast(MBakeRast *bake_rast, const ImBuf *ibuf, const MResolvePixelData *data, MFlushPixel flush_pixel)
+ {
+       memset(bake_rast, 0, sizeof(MBakeRast));
+       bake_rast->texels = ibuf->userdata;
+       bake_rast->w= ibuf->x;
+       bake_rast->h= ibuf->y;
+       bake_rast->data= data;
+       bake_rast->flush_pixel= flush_pixel;
+ }
+ static void flush_pixel(const MResolvePixelData *data, const int x, const int y)
+ {
+       float st[2]= {(x+0.5f)/data->w, (y+0.5f)/data->h};
+       float *st0, *st1, *st2;
+       float *tang0, *tang1, *tang2;
+       float no0[3], no1[3], no2[3];
+       float fUV[2], from_tang[3][3], to_tang[3][3];
+       float u, v, w, sign;
+       int r;
+       const int i0= data->i0;
+       const int i1= data->i1;
+       const int i2= data->i2;
+       st0= data->mtface[data->face_index].uv[i0];
+       st1= data->mtface[data->face_index].uv[i1];
+       st2= data->mtface[data->face_index].uv[i2];
+       tang0= data->pvtangent + data->face_index*16 + i0*4;
+       tang1= data->pvtangent + data->face_index*16 + i1*4;
+       tang2= data->pvtangent + data->face_index*16 + i2*4;
+       multiresbake_get_normal(data, no0, data->face_index, i0);       /* can optimize these 3 into one call */
+       multiresbake_get_normal(data, no1, data->face_index, i1);
+       multiresbake_get_normal(data, no2, data->face_index, i2);
+       resolve_tri_uv(fUV, st, st0, st1, st2);
+       u= fUV[0];
+       v= fUV[1];
+       w= 1-u-v;
+       /* the sign is the same at all face vertices for any non degenerate face.
+          Just in case we clamp the interpolated value though. */
+       sign= (tang0[3]*u + tang1[3]*v + tang2[3]*w)<0 ? (-1.0f) : 1.0f;
+       /* this sequence of math is designed specifically as is with great care
+          to be compatible with our shader. Please don't change without good reason. */
+       for(r= 0; r<3; r++) {
+               from_tang[0][r]= tang0[r]*u + tang1[r]*v + tang2[r]*w;
+               from_tang[2][r]= no0[r]*u + no1[r]*v + no2[r]*w;
+       }
+       cross_v3_v3v3(from_tang[1], from_tang[2], from_tang[0]);  /* B = sign * cross(N, T)  */
+       mul_v3_fl(from_tang[1], sign);
+       invert_m3_m3(to_tang, from_tang);
+       /* sequence end */
+       data->pass_data(data->lores_dm, data->hires_dm, data->bake_data,
+                       data->face_index, data->lvl, st, to_tang, x, y);
+ }
+ static void set_rast_triangle(const MBakeRast *bake_rast, const int x, const int y)
+ {
+       const int w= bake_rast->w;
+       const int h= bake_rast->h;
+       if(x>=0 && x<w && y>=0 && y<h) {
+               if((bake_rast->texels[y*w+x])==0) {
+                       flush_pixel(bake_rast->data, x, y);
+                       bake_rast->texels[y*w+x]= FILTER_MASK_USED;
+               }
+       }
+ }
+ static void rasterize_half(const MBakeRast *bake_rast,
+                            const float s0_s, const float t0_s, const float s1_s, const float t1_s,
+                            const float s0_l, const float t0_l, const float s1_l, const float t1_l,
+                            const int y0_in, const int y1_in, const int is_mid_right)
+ {
+       const int s_stable= fabsf(t1_s-t0_s)>FLT_EPSILON ? 1 : 0;
+       const int l_stable= fabsf(t1_l-t0_l)>FLT_EPSILON ? 1 : 0;
+       const int w= bake_rast->w;
+       const int h= bake_rast->h;
+       int y, y0, y1;
+       if(y1_in<=0 || y0_in>=h)
+               return;
+       y0= y0_in<0 ? 0 : y0_in;
+       y1= y1_in>=h ? h : y1_in;
+       for(y= y0; y<y1; y++) {
+               /*-b(x-x0) + a(y-y0) = 0 */
+               int iXl, iXr, x;
+               float x_l= s_stable!=0 ? (s0_s + (((s1_s-s0_s)*(y-t0_s))/(t1_s-t0_s))) : s0_s;
+               float x_r= l_stable!=0 ? (s0_l + (((s1_l-s0_l)*(y-t0_l))/(t1_l-t0_l))) : s0_l;
+               if(is_mid_right!=0)
+                       SWAP(float, x_l, x_r);
+               iXl= (int)ceilf(x_l);
+               iXr= (int)ceilf(x_r);
+               if(iXr>0 && iXl<w) {
+                       iXl= iXl<0?0:iXl;
+                       iXr= iXr>=w?w:iXr;
+                       for(x= iXl; x<iXr; x++)
+                               set_rast_triangle(bake_rast, x, y);
+               }
+       }
+ }
+ static void bake_rasterize(const MBakeRast *bake_rast, const float st0_in[2], const float st1_in[2], const float st2_in[2])
+ {
+       const int w= bake_rast->w;
+       const int h= bake_rast->h;
+       float slo= st0_in[0]*w - 0.5f;
+       float tlo= st0_in[1]*h - 0.5f;
+       float smi= st1_in[0]*w - 0.5f;
+       float tmi= st1_in[1]*h - 0.5f;
+       float shi= st2_in[0]*w - 0.5f;
+       float thi= st2_in[1]*h - 0.5f;
+       int is_mid_right= 0, ylo, yhi, yhi_beg;
+       /* skip degenerates */
+       if((slo==smi && tlo==tmi) || (slo==shi && tlo==thi) || (smi==shi && tmi==thi))
+               return;
+       /* sort by T */
+       if(tlo>tmi && tlo>thi) {
+               SWAP(float, shi, slo);
+               SWAP(float, thi, tlo);
+       } else if(tmi>thi) {
+               SWAP(float, shi, smi);
+               SWAP(float, thi, tmi);
+       }
+       if(tlo>tmi) {
+               SWAP(float, slo, smi);
+               SWAP(float, tlo, tmi);
+       }
+       /* check if mid point is to the left or to the right of the lo-hi edge */
+       is_mid_right= (-(shi-slo)*(tmi-thi) + (thi-tlo)*(smi-shi))>0 ? 1 : 0;
+       ylo= (int) ceilf(tlo);
+       yhi_beg= (int) ceilf(tmi);
+       yhi= (int) ceilf(thi);
+       /*if(fTmi>ceilf(fTlo))*/
+       rasterize_half(bake_rast, slo, tlo, smi, tmi, slo, tlo, shi, thi, ylo, yhi_beg, is_mid_right);
+       rasterize_half(bake_rast, smi, tmi, shi, thi, slo, tlo, shi, thi, yhi_beg, yhi, is_mid_right);
+ }
+ static int multiresbake_test_break(MultiresBakeRender *bkr)
+ {
+       if(!bkr->stop) {
+               /* this means baker is executed outside from job system */
+               return 0;
+       }
+       return G.afbreek;
+ }
+ static void do_multires_bake(MultiresBakeRender *bkr, Image* ima, MPassKnownData passKnownData,
+                              MInitBakeData initBakeData, MApplyBakeData applyBakeData, MFreeBakeData freeBakeData)
+ {
++#if 1 // BMESH_TODO
++      (void)bkr;
++      (void)ima;
++      (void)passKnownData;
++      (void)initBakeData;
++      (void)applyBakeData;
++      (void)freeBakeData;
++
++      printf("BMESH_TODO" AT "\n");
++#else
+       DerivedMesh *dm= bkr->lores_dm;
+       ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+       const int lvl= bkr->lvl;
+       const int tot_face= dm->getNumFaces(dm);
+       MVert *mvert= dm->getVertArray(dm);
+       MFace *mface= dm->getFaceArray(dm);
+       MTFace *mtface= dm->getFaceDataArray(dm, CD_MTFACE);
+       float *pvtangent= NULL;
+       if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) == -1)
+               DM_add_tangent_layer(dm);
+       pvtangent= DM_get_face_data_layer(dm, CD_TANGENT);
+       if(tot_face > 0) {  /* sanity check */
+               int f= 0;
+               MBakeRast bake_rast;
+               MResolvePixelData data={NULL};
+               data.mface= mface;
+               data.mvert= mvert;
+               data.mtface= mtface;
+               data.pvtangent= pvtangent;
+               data.precomputed_normals= dm->getFaceDataArray(dm, CD_NORMAL);  /* don't strictly need this */
+               data.w= ibuf->x;
+               data.h= ibuf->y;
+               data.lores_dm= dm;
+               data.hires_dm= bkr->hires_dm;
+               data.lvl= lvl;
+               data.pass_data= passKnownData;
+               if(initBakeData)
+                       data.bake_data= initBakeData(bkr, ima);
+               init_bake_rast(&bake_rast, ibuf, &data, flush_pixel);
+               for(f= 0; f<tot_face; f++) {
+                       MTFace *mtfate= &mtface[f];
+                       int verts[3][2], nr_tris, t;
+                       if(multiresbake_test_break(bkr))
+                               break;
+                       if(mtfate->tpage!=ima)
+                               continue;
+                       data.face_index= f;
+                       /* might support other forms of diagonal splits later on such as
+                          split by shortest diagonal.*/
+                       verts[0][0]=0;
+                       verts[1][0]=1;
+                       verts[2][0]=2;
+                       verts[0][1]=0;
+                       verts[1][1]=2;
+                       verts[2][1]=3;
+                       nr_tris= mface[f].v4!=0 ? 2 : 1;
+                       for(t= 0; t<nr_tris; t++) {
+                               data.i0= verts[0][t];
+                               data.i1= verts[1][t];
+                               data.i2 =verts[2][t];
+                               bake_rasterize(&bake_rast, mtfate->uv[data.i0], mtfate->uv[data.i1], mtfate->uv[data.i2]);
+                       }
+                       bkr->baked_faces++;
+                       if(bkr->do_update)
+                               *bkr->do_update= 1;
+                       if(bkr->progress)
+                               *bkr->progress= ((float)bkr->baked_objects + (float)bkr->baked_faces / tot_face) / bkr->tot_obj;
+               }
+               if(applyBakeData)
+                       applyBakeData(data.bake_data);
+               if(freeBakeData)
+                       freeBakeData(data.bake_data);
+       }
++#endif // BMESH_TODO
+ }
+ static void interp_bilinear_quad_data(float data[4][3], float u, float v, float res[3])
+ {
+       float vec[3];
+       copy_v3_v3(res, data[0]);
+       mul_v3_fl(res, (1-u)*(1-v));
+       copy_v3_v3(vec, data[1]);
+       mul_v3_fl(vec, u*(1-v)); add_v3_v3(res, vec);
+       copy_v3_v3(vec, data[2]);
+       mul_v3_fl(vec, u*v); add_v3_v3(res, vec);
+       copy_v3_v3(vec, data[3]);
+       mul_v3_fl(vec, (1-u)*v); add_v3_v3(res, vec);
+ }
+ static void interp_barycentric_tri_data(float data[3][3], float u, float v, float res[3])
+ {
+       float vec[3];
+       copy_v3_v3(res, data[0]);
+       mul_v3_fl(res, u);
+       copy_v3_v3(vec, data[1]);
+       mul_v3_fl(vec, v); add_v3_v3(res, vec);
+       copy_v3_v3(vec, data[2]);
+       mul_v3_fl(vec, 1.0f-u-v); add_v3_v3(res, vec);
+ }
+ /* mode = 0: interpolate normals,
+    mode = 1: interpolate coord */
+ static void interp_bilinear_grid(DMGridData *grid, int grid_size, float crn_x, float crn_y, int mode, float res[3])
+ {
+       int x0, x1, y0, y1;
+       float u, v;
+       float data[4][3];
+       x0= (int) crn_x;
+       x1= x0>=(grid_size-1) ? (grid_size-1) : (x0+1);
+       y0= (int) crn_y;
+       y1= y0>=(grid_size-1) ? (grid_size-1) : (y0+1);
+       u= crn_x-x0;
+       v= crn_y-y0;
+       if(mode == 0) {
+               copy_v3_v3(data[0], grid[y0 * grid_size + x0].no);
+               copy_v3_v3(data[1], grid[y0 * grid_size + x1].no);
+               copy_v3_v3(data[2], grid[y1 * grid_size + x1].no);
+               copy_v3_v3(data[3], grid[y1 * grid_size + x0].no);
+       } else {
+               copy_v3_v3(data[0], grid[y0 * grid_size + x0].co);
+               copy_v3_v3(data[1], grid[y0 * grid_size + x1].co);
+               copy_v3_v3(data[2], grid[y1 * grid_size + x1].co);
+               copy_v3_v3(data[3], grid[y1 * grid_size + x0].co);
+       }
+       interp_bilinear_quad_data(data, u, v, res);
+ }
+ static void get_ccgdm_data(DerivedMesh *lodm, DerivedMesh *hidm,  const int lvl, const int face_index, const float u, const float v, float co[3], float n[3])
+ {
++#if 1 // BMESH_TODO
++      (void)lodm;
++      (void)hidm;
++      (void)lvl;
++      (void)face_index;
++      (void)u;
++      (void)v;
++      (void)co;
++      (void)n;
++#else
+       MFace mface;
+       DMGridData **grid_data;
+       float crn_x, crn_y;
+       int grid_size, S, face_side;
+       int *grid_offset, g_index;
+       lodm->getFace(lodm, face_index, &mface);
+       grid_size= hidm->getGridSize(hidm);
+       grid_data= hidm->getGridData(hidm);
+       grid_offset= hidm->getGridOffset(hidm);
+       face_side= (grid_size<<1)-1;
+       if(lvl==0) {
+               g_index= grid_offset[face_index];
+               S= mdisp_rot_face_to_crn(mface.v4 ? 4 : 3, face_side, u*(face_side-1), v*(face_side-1), &crn_x, &crn_y);
+       } else {
+               const int *index= lodm->getFaceDataArray(lodm, CD_ORIGINDEX);
+               int side= (1 << (lvl-1)) + 1;
+               int grid_index= index[face_index];
+               int loc_offs= face_index % (1<<(2*lvl));
+               int cell_index= loc_offs % ((side-1)*(side-1));
+               int cell_side= grid_size / (side-1);
+               int row= cell_index / (side-1);
+               int col= cell_index % (side-1);
+               S= face_index / (1<<(2*(lvl-1))) - grid_offset[grid_index];
+               g_index= grid_offset[grid_index];
+               crn_y= (row * cell_side) + u * cell_side;
+               crn_x= (col * cell_side) + v * cell_side;
+       }
+       CLAMP(crn_x, 0.0f, grid_size);
+       CLAMP(crn_y, 0.0f, grid_size);
+       if(n != NULL)
+               interp_bilinear_grid(grid_data[g_index + S], grid_size, crn_x, crn_y, 0, n);
+       if(co != NULL)
+               interp_bilinear_grid(grid_data[g_index + S], grid_size, crn_x, crn_y, 1, co);
++#endif
+ }
+ /* mode = 0: interpolate normals,
+    mode = 1: interpolate coord */
+ static void interp_bilinear_mface(DerivedMesh *dm, MFace *mface, const float u, const float v, const int mode, float res[3])
+ {
+       float data[4][3];
+       if(mode == 0) {
+               dm->getVertNo(dm, mface->v1, data[0]);
+               dm->getVertNo(dm, mface->v2, data[1]);
+               dm->getVertNo(dm, mface->v3, data[2]);
+               dm->getVertNo(dm, mface->v4, data[3]);
+       } else {
+               dm->getVertCo(dm, mface->v1, data[0]);
+               dm->getVertCo(dm, mface->v2, data[1]);
+               dm->getVertCo(dm, mface->v3, data[2]);
+               dm->getVertCo(dm, mface->v4, data[3]);
+       }
+       interp_bilinear_quad_data(data, u, v, res);
+ }
+ /* mode = 0: interpolate normals,
+    mode = 1: interpolate coord */
+ static void interp_barycentric_mface(DerivedMesh *dm, MFace *mface, const float u, const float v, const int mode, float res[3])
+ {
+       float data[3][3];
+       if(mode == 0) {
+               dm->getVertNo(dm, mface->v1, data[0]);
+               dm->getVertNo(dm, mface->v2, data[1]);
+               dm->getVertNo(dm, mface->v3, data[2]);
+       } else {
+               dm->getVertCo(dm, mface->v1, data[0]);
+               dm->getVertCo(dm, mface->v2, data[1]);
+               dm->getVertCo(dm, mface->v3, data[2]);
+       }
+       interp_barycentric_tri_data(data, u, v, res);
+ }
+ static void *init_heights_data(MultiresBakeRender *bkr, Image* ima)
+ {
+       MHeightBakeData *height_data;
+       ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+       height_data= MEM_callocN(sizeof(MHeightBakeData), "MultiresBake heightData");
+       height_data->ima= ima;
+       height_data->heights= MEM_callocN(sizeof(float)*ibuf->x*ibuf->y, "MultiresBake heights");
+       height_data->height_max= -FLT_MAX;
+       height_data->height_min= FLT_MAX;
+       if(!bkr->use_lores_mesh) {
+               SubsurfModifierData smd= {{NULL}};
+               int ss_lvl= bkr->tot_lvl - bkr->lvl;
+               CLAMP(ss_lvl, 0, 6);
+               smd.levels= smd.renderLevels= ss_lvl;
+               smd.flags|= eSubsurfModifierFlag_SubsurfUv;
+               if(bkr->simple)
+                       smd.subdivType= ME_SIMPLE_SUBSURF;
+               height_data->ssdm= subsurf_make_derived_from_derived(bkr->lores_dm, &smd, 0, NULL, 0, 0, 0);
+       }
+       return (void*)height_data;
+ }
+ static void apply_heights_data(void *bake_data)
+ {
+       MHeightBakeData *height_data= (MHeightBakeData*)bake_data;
+       ImBuf *ibuf= BKE_image_get_ibuf(height_data->ima, NULL);
+       int x, y, i;
+       float height, *heights= height_data->heights;
+       float min= height_data->height_min, max= height_data->height_max;
+       for(x= 0; x<ibuf->x; x++) {
+               for(y =0; y<ibuf->y; y++) {
+                       i= ibuf->x*y + x;
+                       if(((char*)ibuf->userdata)[i] != FILTER_MASK_USED)
+                               continue;
+                       if(ibuf->rect_float) {
+                               float *rrgbf= ibuf->rect_float + i*4;
+                               if(max-min > 1e-5) height= (heights[i]-min)/(max-min);
+                               else height= 0;
+                               rrgbf[0]=rrgbf[1]=rrgbf[2]= height;
+                       } else {
+                               char *rrgb= (char*)ibuf->rect + i*4;
+                               if(max-min > 1e-5) height= (heights[i]-min)/(max-min);
+                               else height= 0;
+                               rrgb[0]=rrgb[1]=rrgb[2]= FTOCHAR(height);
+                       }
+               }
+       }
+       ibuf->userflags= IB_RECT_INVALID;
+ }
+ static void free_heights_data(void *bake_data)
+ {
+       MHeightBakeData *height_data= (MHeightBakeData*)bake_data;
+       if(height_data->ssdm)
+               height_data->ssdm->release(height_data->ssdm);
+       MEM_freeN(height_data->heights);
+       MEM_freeN(height_data);
+ }
+ /* MultiresBake callback for heights baking
+    general idea:
+      - find coord of point with specified UV in hi-res mesh (let's call it p1)
+      - find coord of point and normal with specified UV in lo-res mesh (or subdivided lo-res
+        mesh to make texture smoother) let's call this point p0 and n.
+      - height wound be dot(n, p1-p0) */
+ static void apply_heights_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *bake_data,
+                                    const int face_index, const int lvl, const float st[2],
+                                    float UNUSED(tangmat[3][3]), const int x, const int y)
+ {
++#if 1 // BMESH_TODO
++      (void)lores_dm;
++      (void)hires_dm;
++      (void)bake_data;
++      (void)face_index;
++      (void)lvl;
++      (void)st;
++      (void)x;
++      (void)y;
++#else
+       MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
+       MFace mface;
+       Image *ima= mtface[face_index].tpage;
+       ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+       MHeightBakeData *height_data= (MHeightBakeData*)bake_data;
+       float uv[2], *st0, *st1, *st2, *st3;
+       int pixel= ibuf->x*y + x;
+       float vec[3], p0[3], p1[3], n[3], len;
+       lores_dm->getFace(lores_dm, face_index, &mface);
+       st0= mtface[face_index].uv[0];
+       st1= mtface[face_index].uv[1];
+       st2= mtface[face_index].uv[2];
+       if(mface.v4) {
+               st3= mtface[face_index].uv[3];
+               resolve_quad_uv(uv, st, st0, st1, st2, st3);
+       } else
+               resolve_tri_uv(uv, st, st0, st1, st2);
+       CLAMP(uv[0], 0.0f, 1.0f);
+       CLAMP(uv[1], 0.0f, 1.0f);
+       get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], p1, 0);
+       if(height_data->ssdm) {
+               //get_ccgdm_data_ss(lores_dm, height_data->ssdm, lvl, face_index, uv[0], uv[1], p0, n);
+               get_ccgdm_data(lores_dm, height_data->ssdm, 0, face_index, uv[0], uv[1], p0, n);
+       } else {
+               MFace mface;
+               lores_dm->getFace(lores_dm, face_index, &mface);
+               if(mface.v4) {
+                       interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
+                       interp_bilinear_mface(lores_dm, &mface, uv[0], uv[1], 0, n);
+               } else {
+                       interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 1, p0);
+                       interp_barycentric_mface(lores_dm, &mface, uv[0], uv[1], 0, n);
+               }
+       }
+       sub_v3_v3v3(vec, p1, p0);
+       //len= len_v3(vec);
+       len= dot_v3v3(n, vec);
+       height_data->heights[pixel]= len;
+       if(len<height_data->height_min) height_data->height_min= len;
+       if(len>height_data->height_max) height_data->height_max= len;
+       if(ibuf->rect_float) {
+               float *rrgbf= ibuf->rect_float + pixel*4;
+               rrgbf[3]= 1.0f;
+               ibuf->userflags= IB_RECT_INVALID;
+       } else {
+               char *rrgb= (char*)ibuf->rect + pixel*4;
+               rrgb[3]= 255;
+       }
++#endif // BMESH_TODO
+ }
+ /* MultiresBake callback for normals' baking
+    general idea:
+      - find coord and normal of point with specified UV in hi-res mesh
+      - multiply it by tangmat
+      - vector in color space would be norm(vec) /2 + (0.5, 0.5, 0.5) */
+ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, const void *UNUSED(bake_data),
+                                    const int face_index, const int lvl, const float st[2],
+                                    float tangmat[3][3], const int x, const int y)
+ {
++#if 1 // BMESH_TODO
++      (void)lores_dm;
++      (void)hires_dm;
++      (void)face_index;
++      (void)lvl;
++      (void)st;
++      (void)tangmat;
++      (void)y;
++      (void)x;
++#else
+       MTFace *mtface= CustomData_get_layer(&lores_dm->faceData, CD_MTFACE);
+       MFace mface;
+       Image *ima= mtface[face_index].tpage;
+       ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+       float uv[2], *st0, *st1, *st2, *st3;
+       int pixel= ibuf->x*y + x;
+       float n[3], vec[3], tmp[3]= {0.5, 0.5, 0.5};
+       lores_dm->getFace(lores_dm, face_index, &mface);
+       st0= mtface[face_index].uv[0];
+       st1= mtface[face_index].uv[1];
+       st2= mtface[face_index].uv[2];
+       if(mface.v4) {
+               st3= mtface[face_index].uv[3];
+               resolve_quad_uv(uv, st, st0, st1, st2, st3);
+       } else
+               resolve_tri_uv(uv, st, st0, st1, st2);
+       CLAMP(uv[0], 0.0f, 1.0f);
+       CLAMP(uv[1], 0.0f, 1.0f);
+       get_ccgdm_data(lores_dm, hires_dm, lvl, face_index, uv[0], uv[1], NULL, n);
+       mul_v3_m3v3(vec, tangmat, n);
+       normalize_v3(vec);
+       mul_v3_fl(vec, 0.5);
+       add_v3_v3(vec, tmp);
+       if(ibuf->rect_float) {
+               float *rrgbf= ibuf->rect_float + pixel*4;
+               rrgbf[0]= vec[0];
+               rrgbf[1]= vec[1];
+               rrgbf[2]= vec[2];
+               rrgbf[3]= 1.0f;
+               ibuf->userflags= IB_RECT_INVALID;
+       } else {
+               char *rrgb= (char*)ibuf->rect + pixel*4;
+               rrgb[0]= FTOCHAR(vec[0]);
+               rrgb[1]= FTOCHAR(vec[1]);
+               rrgb[2]= FTOCHAR(vec[2]);
+               rrgb[3]= 255;
+       }
++#endif
+ }
+ static void count_images(MultiresBakeRender *bkr)
+ {
+       int a, totface;
+       DerivedMesh *dm= bkr->lores_dm;
+       MTFace *mtface= CustomData_get_layer(&dm->faceData, CD_MTFACE);
+       bkr->image.first= bkr->image.last= NULL;
+       bkr->tot_image= 0;
+       totface= dm->getNumFaces(dm);
+       for(a= 0; a<totface; a++)
+               mtface[a].tpage->id.flag&= ~LIB_DOIT;
+       for(a= 0; a<totface; a++) {
+               Image *ima= mtface[a].tpage;
+               if((ima->id.flag&LIB_DOIT)==0) {
+                       LinkData *data= BLI_genericNodeN(ima);
+                       BLI_addtail(&bkr->image, data);
+                       bkr->tot_image++;
+                       ima->id.flag|= LIB_DOIT;
+               }
+       }
+       for(a= 0; a<totface; a++)
+               mtface[a].tpage->id.flag&= ~LIB_DOIT;
+ }
+ static void bake_images(MultiresBakeRender *bkr)
+ {
+       LinkData *link;
+       for(link= bkr->image.first; link; link= link->next) {
+               Image *ima= (Image*)link->data;
+               ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+               if(ibuf->x>0 && ibuf->y>0) {
+                       ibuf->userdata= MEM_callocN(ibuf->y*ibuf->x, "MultiresBake imbuf mask");
+                       switch(bkr->mode) {
+                               case RE_BAKE_NORMALS:
+                                       do_multires_bake(bkr, ima, apply_tangmat_callback, NULL, NULL, NULL);
+                                       break;
+                               case RE_BAKE_DISPLACEMENT:
+                                       do_multires_bake(bkr, ima, apply_heights_callback, init_heights_data,
+                                                        apply_heights_data, free_heights_data);
+                                       break;
+                       }
+               }
+               ima->id.flag|= LIB_DOIT;
+       }
+ }
+ static void finish_images(MultiresBakeRender *bkr)
+ {
+       LinkData *link;
+       for(link= bkr->image.first; link; link= link->next) {
+               Image *ima= (Image*)link->data;
+               int i;
+               ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+               if(ibuf->x<=0 || ibuf->y<=0)
+                       continue;
+               /* Margin */
+               if(bkr->bake_filter) {
+                       char *temprect;
+                       /* extend the mask +2 pixels from the image,
+                        * this is so colors dont blend in from outside */
+                       for(i=0; i<bkr->bake_filter; i++)
+                               IMB_mask_filter_extend((char *)ibuf->userdata, ibuf->x, ibuf->y);
+                       temprect = MEM_dupallocN(ibuf->userdata);
+                       /* expand twice to clear this many pixels, so they blend back in */
+                       IMB_mask_filter_extend(temprect, ibuf->x, ibuf->y);
+                       IMB_mask_filter_extend(temprect, ibuf->x, ibuf->y);
+                       /* clear all pixels in the margin */
+                       IMB_mask_clear(ibuf, temprect, FILTER_MASK_MARGIN);
+                       MEM_freeN(temprect);
+                       for(i= 0; i<bkr->bake_filter; i++)
+                               IMB_filter_extend(ibuf, (char *)ibuf->userdata);
+               }
+               ibuf->userflags|= IB_BITMAPDIRTY;
+               if(ibuf->mipmap[0]) {
+                       ibuf->userflags|= IB_MIPMAP_INVALID;
+                       imb_freemipmapImBuf(ibuf);
+               }
+               if(ibuf->userdata) {
+                       MEM_freeN(ibuf->userdata);
+                       ibuf->userdata= NULL;
+               }
+       }
+ }
+ static void multiresbake_start(MultiresBakeRender *bkr)
+ {
+       count_images(bkr);
+       bake_images(bkr);
+       finish_images(bkr);
+ }
+ static int multiresbake_check(bContext *C, wmOperator *op) {
+       Scene *scene= CTX_data_scene(C);
+       Object *ob;
+       Mesh *me;
+       MultiresModifierData *mmd;
+       int ok= 1, a;
+       CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
+               ob= base->object;
+               if(ob->type != OB_MESH) {
+                       BKE_report(op->reports, RPT_ERROR, "Basking of multires data only works with active object which is a mesh");
+                       ok= 0;
+                       break;
+               }
+               me= (Mesh*)ob->data;
+               mmd= get_multires_modifier(scene, ob, 0);
+               /* Multi-resolution should be and be last in the stack */
+               if(ok && mmd) {
+                       ModifierData *md;
+                       ok= mmd->totlvl>0;
+                       for(md = (ModifierData*)mmd->modifier.next; md && ok; md = md->next) {
+                               if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) {
+                                       ok= 0;
+                               }
+                       }
+               } else ok= 0;
+               if(!ok) {
+                       BKE_report(op->reports, RPT_ERROR, "Multires data baking requires multi-resolution object");
+                       break;
+               }
+               if(!me->mtface) {
+                       BKE_report(op->reports, RPT_ERROR, "Mesh should be unwrapped before multires data baking");
+                       ok= 0;
+               } else {
+                       a= me->totface;
+                       while (ok && a--) {
+                               Image *ima= me->mtface[a].tpage;
+                               if(!ima) {
+                                       BKE_report(op->reports, RPT_ERROR, "You should have active texture to use multires baker");
+                                       ok= 0;
+                               } else {
+                                       ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+                                       if(!ibuf) {
+                                               BKE_report(op->reports, RPT_ERROR, "Baking should happend to image with image buffer");
+                                               ok= 0;
+                                       } else {
+                                               if(ibuf->rect==NULL && ibuf->rect_float==NULL)
+                                                       ok= 0;
+                                               if(ibuf->rect_float && !(ibuf->channels==0 || ibuf->channels==4))
+                                                       ok= 0;
+                                               if(!ok)
+                                                       BKE_report(op->reports, RPT_ERROR, "Baking to unsupported image type");
+                                       }
+                               }
+                       }
+               }
+               if(!ok)
+                       break;
+       }
+       CTX_DATA_END;
+       return ok;
+ }
+ static DerivedMesh *multiresbake_create_loresdm(Scene *scene, Object *ob, int *lvl)
+ {
+       DerivedMesh *dm;
+       MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0);
+       Mesh *me= (Mesh*)ob->data;
+       *lvl= mmd->lvl;
+       if(mmd->lvl==0) {
+               DerivedMesh *tmp_dm= CDDM_from_mesh(me, ob);
++              dm= CDDM_copy(tmp_dm, 0);
+               tmp_dm->release(tmp_dm);
+       } else {
+               MultiresModifierData tmp_mmd= *mmd;
+               DerivedMesh *cddm= CDDM_from_mesh(me, ob);
+               tmp_mmd.lvl= mmd->lvl;
+               dm= multires_dm_create_from_derived(&tmp_mmd, 1, cddm, ob, 0, 0);
+               cddm->release(cddm);
+       }
+       return dm;
+ }
+ static DerivedMesh *multiresbake_create_hiresdm(Scene *scene, Object *ob, int *lvl, int *simple)
+ {
+       Mesh *me= (Mesh*)ob->data;
+       MultiresModifierData *mmd= get_multires_modifier(scene, ob, 0);
+       MultiresModifierData tmp_mmd= *mmd;
+       DerivedMesh *cddm= CDDM_from_mesh(me, ob);
+       DerivedMesh *dm;
+       *lvl= mmd->totlvl;
+       *simple= mmd->simple;
+       tmp_mmd.lvl= mmd->totlvl;
+       dm= multires_dm_create_from_derived(&tmp_mmd, 1, cddm, ob, 0, 0);
+       cddm->release(cddm);
+       return dm;
+ }
+ static void clear_images(MTFace *mtface, int totface)
+ {
+       int a;
+       float vec[4]= {0.0f, 0.0f, 0.0f, 0.0f};
+       for(a= 0; a<totface; a++)
+               mtface[a].tpage->id.flag&= ~LIB_DOIT;
+       for(a= 0; a<totface; a++) {
+               Image *ima= mtface[a].tpage;
+               if((ima->id.flag&LIB_DOIT)==0) {
+                       ImBuf *ibuf= BKE_image_get_ibuf(ima, NULL);
+                       IMB_rectfill(ibuf, vec);
+                       ima->id.flag|= LIB_DOIT;
+               }
+       }
+       for(a= 0; a<totface; a++)
+               mtface[a].tpage->id.flag&= ~LIB_DOIT;
+ }
+ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op)
+ {
+       Object *ob;
+       Scene *scene= CTX_data_scene(C);
+       if(!multiresbake_check(C, op))
+               return OPERATOR_CANCELLED;
+       if(scene->r.bake_flag&R_BAKE_CLEAR) {  /* clear images */
+               CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
+                       Mesh *me;
+                       ob= base->object;
+                       me= (Mesh*)ob->data;
+                       clear_images(me->mtface, me->totface);
+               }
+               CTX_DATA_END;
+       }
+       CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
+               MultiresBakeRender bkr= {0};
+               ob= base->object;
+               /* copy data stored in job descriptor */
+               bkr.bake_filter= scene->r.bake_filter;
+               bkr.mode= scene->r.bake_mode;
+               bkr.use_lores_mesh= scene->r.bake_flag&R_BAKE_LORES_MESH;
+               /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
+               bkr.lores_dm= multiresbake_create_loresdm(scene, ob, &bkr.lvl);
+               bkr.hires_dm= multiresbake_create_hiresdm(scene, ob, &bkr.tot_lvl, &bkr.simple);
+               multiresbake_start(&bkr);
+               BLI_freelistN(&bkr.image);
+               bkr.lores_dm->release(bkr.lores_dm);
+               bkr.hires_dm->release(bkr.hires_dm);
+       }
+       CTX_DATA_END;
+       return OPERATOR_FINISHED;
+ }
+ /* Multiresbake adopted for job-system executing */
+ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj)
+ {
+       Scene *scene= CTX_data_scene(C);
+       Object *ob;
+       /* backup scene settings, so their changing in UI would take no effect on baker */
+       bkj->bake_filter= scene->r.bake_filter;
+       bkj->mode= scene->r.bake_mode;
+       bkj->use_lores_mesh= scene->r.bake_flag&R_BAKE_LORES_MESH;
+       bkj->bake_clear= scene->r.bake_flag&R_BAKE_CLEAR;
+       CTX_DATA_BEGIN(C, Base*, base, selected_editable_bases) {
+               MultiresBakerJobData *data;
+               ob= base->object;
+               data= MEM_callocN(sizeof(MultiresBakerJobData), "multiresBaker derivedMesh_data");
+               data->lores_dm = multiresbake_create_loresdm(scene, ob, &data->lvl);
+               data->hires_dm = multiresbake_create_hiresdm(scene, ob, &data->tot_lvl, &data->simple);
+               BLI_addtail(&bkj->data, data);
+       }
+       CTX_DATA_END;
+ }
+ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, float *progress)
+ {
+       MultiresBakerJobData *data;
+       MultiresBakeJob *bkj= bkv;
+       int baked_objects= 0, tot_obj;
+       tot_obj= BLI_countlist(&bkj->data);
+       if(bkj->bake_clear) {  /* clear images */
+               for(data= bkj->data.first; data; data= data->next) {
+                       DerivedMesh *dm= data->lores_dm;
+                       MTFace *mtface= CustomData_get_layer(&dm->faceData, CD_MTFACE);
+                       clear_images(mtface, dm->getNumFaces(dm));
+               }
+       }
+       for(data= bkj->data.first; data; data= data->next) {
+               MultiresBakeRender bkr= {0};
+               /* copy data stored in job descriptor */
+               bkr.bake_filter= bkj->bake_filter;
+               bkr.mode= bkj->mode;
+               bkr.use_lores_mesh= bkj->use_lores_mesh;
+               /* create low-resolution DM (to bake to) and hi-resolution DM (to bake from) */
+               bkr.lores_dm= data->lores_dm;
+               bkr.hires_dm= data->hires_dm;
+               bkr.tot_lvl= data->tot_lvl;
+               bkr.lvl= data->lvl;
+               bkr.simple= data->simple;
+               /* needed for proper progress bar */
+               bkr.tot_obj= tot_obj;
+               bkr.baked_objects= baked_objects;
+               bkr.stop= stop;
+               bkr.do_update= do_update;
+               bkr.progress= progress;
+               multiresbake_start(&bkr);
+               BLI_freelistN(&bkr.image);
+               baked_objects++;
+       }
+ }
+ static void multiresbake_freejob(void *bkv)
+ {
+       MultiresBakeJob *bkj= bkv;
+       MultiresBakerJobData *data, *next;
+       data= bkj->data.first;
+       while (data) {
+               next= data->next;
+               data->lores_dm->release(data->lores_dm);
+               data->hires_dm->release(data->hires_dm);
+               MEM_freeN(data);
+               data= next;
+       }
+       MEM_freeN(bkj);
+ }
+ static int multiresbake_image_exec(bContext *C, wmOperator *op)
+ {
+       Scene *scene= CTX_data_scene(C);
+       MultiresBakeJob *bkr;
+       wmJob *steve;
+       if(!multiresbake_check(C, op))
+               return OPERATOR_CANCELLED;
+       bkr= MEM_callocN(sizeof(MultiresBakeJob), "MultiresBakeJob data");
+       init_multiresbake_job(C, bkr);
+       /* setup job */
+       steve= WM_jobs_get(CTX_wm_manager(C), CTX_wm_window(C), scene, "Multires Bake", WM_JOB_EXCL_RENDER|WM_JOB_PRIORITY|WM_JOB_PROGRESS);
+       WM_jobs_customdata(steve, bkr, multiresbake_freejob);
+       WM_jobs_timer(steve, 0.2, NC_IMAGE, 0); /* TODO - only draw bake image, can we enforce this */
+       WM_jobs_callbacks(steve, multiresbake_startjob, NULL, NULL, NULL);
+       G.afbreek= 0;
+       WM_jobs_start(CTX_wm_manager(C), steve);
+       WM_cursor_wait(0);
+       /* add modal handler for ESC */
+       WM_event_add_modal_handler(C, op);
+       return OPERATOR_RUNNING_MODAL;
+ }
  /* ****************** render BAKING ********************** */
  
  /* threaded break test */
index a277c99c7ed64f5e84bbaaee695291bf827ba6b2,fd2e7fd7c998540b2056159573a3ccbf18341afb..a7b73b21865b837d1009e71a3875413b63a2cb33
@@@ -215,9 -215,48 +215,48 @@@ static int object_shape_key_mirror(bCon
                                }
                        }
  
 -                      mesh_octree_table(ob, NULL, NULL, 'e');
 +                      //BMESH_TODO mesh_octree_table(ob, NULL, NULL, 'e');
                }
-               /* todo, other types? */
+               else if (ob->type == OB_LATTICE) {
+                       Lattice *lt= ob->data;
+                       int i1, i2;
+                       float *fp1, *fp2;
+                       int u, v, w;
+                       /* half but found up odd value */
+                       const int pntsu_half = (((lt->pntsu / 2) + (lt->pntsu % 2))) ;
+                       /* currently editmode isnt supported by mesh so
+                        * ignore here for now too */
+                       /* if(lt->editlatt) lt= lt->editlatt->latt; */
+                       for(w=0; w<lt->pntsw; w++) {
+                               for(v=0; v<lt->pntsv; v++) {
+                                       for(u=0; u<pntsu_half; u++) {
+                                               int u_inv= (lt->pntsu - 1) - u;
+                                               float tvec[3];
+                                               if(u == u_inv) {
+                                                       i1= LT_INDEX(lt, u, v, w);
+                                                       fp1= ((float *)kb->data) + i1*3;
+                                                       fp1[0]= -fp1[0];
+                                               }
+                                               else {
+                                                       i1= LT_INDEX(lt, u, v, w);
+                                                       i2= LT_INDEX(lt, u_inv, v, w);
+                                                       fp1= ((float *)kb->data) + i1*3;
+                                                       fp2= ((float *)kb->data) + i2*3;
+                                                       copy_v3_v3(tvec, fp1);
+                                                       copy_v3_v3(fp1, fp2);
+                                                       copy_v3_v3(fp2, tvec);
+                                                       fp1[0]= -fp1[0];
+                                                       fp2[0]= -fp2[0];
+                                               }
+                                       }
+                               }
+                       }
+               }
  
                MEM_freeN(tag_elem);
        }
index 881643a01ea2d7bb4d0ab26a5092ed025fd56c8c,52ba9460818d26c0aec13f36172afcb6aacf36f7..92fab15987539de8b34f2ebf1aca7e6225e884f8
@@@ -162,15 -169,12 +171,13 @@@ static int ED_vgroup_give_parray(ID *id
                        {
                                Mesh *me = (Mesh *)id;
  
 -                              if(me->edit_mesh) {
 -                                      EditMesh *em = me->edit_mesh;
 -                                      EditVert *eve;
 +                              if(me->edit_btmesh) {
 +                                      BMEditMesh *em = me->edit_btmesh;
 +                                      BMIter iter;
 +                                      BMVert *eve;
                                        int i;
  
 -                                      if (!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
 +                                      if (!CustomData_has_layer(&em->bm->vdata, CD_MDEFORMVERT)) {
-                                               *dvert_tot = 0;
-                                               *dvert_arr = NULL;
                                                return 0;
                                        }
  
@@@ -1018,35 -1032,63 +1035,71 @@@ static void vgroup_clean_all(Object *ob
        if (dvert_array) MEM_freeN(dvert_array);
  }
  
- void ED_vgroup_mirror(Object *ob, int mirror_weights, int flip_vgroups)
+ static void dvert_mirror_op(MDeformVert *dvert, MDeformVert *dvert_mirr,
+                             const char sel, const char sel_mirr,
+                             const int *flip_map,
+                             const short mirror_weights, const short flip_vgroups)
+ {
+       BLI_assert(sel || sel_mirr);
+       if(sel_mirr && sel) {
+               /* swap */
+               if(mirror_weights)
+                       SWAP(MDeformVert, *dvert, *dvert_mirr);
+               if(flip_vgroups) {
+                       defvert_flip(dvert, flip_map);
+                       defvert_flip(dvert_mirr, flip_map);
+               }
+       }
+       else {
+               /* dvert should always be the target */
+               if(sel_mirr) {
+                       SWAP(MDeformVert *, dvert, dvert_mirr);
+               }
+               if(mirror_weights)
+                       defvert_copy(dvert, dvert_mirr);
+               if(flip_vgroups) {
+                       defvert_flip(dvert, flip_map);
+               }
+       }
+ }
+ void ED_vgroup_mirror(Object *ob, const short mirror_weights, const short flip_vgroups)
  {
-       BMVert *eve, *eve_mirr;
+ #define VGROUP_MIRR_OP dvert_mirror_op(dvert, dvert_mirr, sel, sel_mirr, flip_map, mirror_weights, flip_vgroups)
++#if 0
+       EditVert *eve, *eve_mirr;
++#endif
++
        MDeformVert *dvert, *dvert_mirr;
+       short sel, sel_mirr;
        int     *flip_map;
  
        if(mirror_weights==0 && flip_vgroups==0)
                return;
  
+       flip_map= defgroup_flip_map(ob, 0);
        /* only the active group */
        if(ob->type == OB_MESH) {
-               Mesh *me= ob->data;
-               BMEditMesh *em = me->edit_btmesh;
-               BMIter iter;
 +#if 1 //BMESH_TODO
-               (void)eve;
-               (void)eve_mirr;
 +              (void)dvert;
 +              (void)dvert_mirr;
 +              (void)flip_map;
-               (void)iter;
-               (void)em;
 +#else
-               EM_cache_x_mirror_vert(ob, em);
+               Mesh *me= ob->data;
+               EditMesh *em = BKE_mesh_get_editmesh(me);
  
-               if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT))
+               if(!CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
+                       MEM_freeN(flip_map);
                        return;
+               }
  
-               flip_map= defgroup_flip_map(ob, 0);
+               EM_cache_x_mirror_vert(ob, em);
  
                /* Go through the list of editverts and assign them */
                for(eve=em->verts.first; eve; eve=eve->next){
                        }
                }
  
-               MEM_freeN(flip_map);
                BKE_mesh_end_editmesh(me, em);
- #endif
++#endif // BMESH_TODO
        }
+       else if (ob->type == OB_LATTICE) {
+               Lattice *lt= ob->data;
+               int i1, i2;
+               int u, v, w;
+               int pntsu_half;
+               /* half but found up odd value */
+               if(lt->editlatt) lt= lt->editlatt->latt;
+               if(lt->pntsu == 1 || lt->dvert == NULL) {
+                       MEM_freeN(flip_map);
+                       return;
+               }
+               /* unlike editmesh we know that by only looping over the first hald of
+                * the 'u' indicies it will cover all points except the middle which is
+                * ok in this case */
+               pntsu_half= lt->pntsu / 2;
+               for(w=0; w<lt->pntsw; w++) {
+                       for(v=0; v<lt->pntsv; v++) {
+                               for(u=0; u<pntsu_half; u++) {
+                                       int u_inv= (lt->pntsu - 1) - u;
+                                       if(u != u_inv) {
+                                               BPoint *bp, *bp_mirr;
+                                               i1= LT_INDEX(lt, u, v, w);
+                                               i2= LT_INDEX(lt, u_inv, v, w);
+                                               bp= &lt->def[i1];
+                                               bp_mirr= &lt->def[i2];
+                                               sel= bp->f1 & SELECT;
+                                               sel_mirr= bp_mirr->f1 & SELECT;
+                                               if(sel || sel_mirr) {
+                                                       dvert= &lt->dvert[i1];
+                                                       dvert_mirr= &lt->dvert[i2];
+                                                       VGROUP_MIRR_OP;
+                                               }
+                                       }
+                               }
+                       }
+               }
+       }
+       MEM_freeN(flip_map);
+ #undef VGROUP_MIRR_OP
  }
  
  static void vgroup_remap_update_users(Object *ob, int *map)
index 60c863b4be364e6aafbdbefebb61a31c66770f2b,75c8d5cae73110c7628f60d629da4f8c3f7042e0..1df851923894f89d72c10ad8c7222fe8321c3060
@@@ -442,9 -445,11 +442,9 @@@ void uiTemplateEditModeSelection(uiLayo
  
                row= uiLayoutRow(layout, 1);
                block= uiLayoutGetBlock(row);
-               uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode");
-               uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Edge select mode");
-               uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, 0,0,XIC,YIC, &em->selectmode, 1.0, 0.0, 0, 0, "Face select mode");
+               uiDefIconButBitS(block, TOG, SCE_SELECT_VERTEX, B_SEL_VERT, ICON_VERTEXSEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Vertex select mode");
+               uiDefIconButBitS(block, TOG, SCE_SELECT_EDGE, B_SEL_EDGE, ICON_EDGESEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Edge select mode");
+               uiDefIconButBitS(block, TOG, SCE_SELECT_FACE, B_SEL_FACE, ICON_FACESEL, 0,0,UI_UNIT_X,UI_UNIT_Y, &em->selectmode, 1.0, 0.0, 0, 0, "Face select mode");
 -
 -              BKE_mesh_end_editmesh(obedit->data, em);
        }
  }
  
@@@ -473,20 -478,14 +473,20 @@@ void uiTemplateHeader3D(uiLayout *layou
        uiBlockSetEmboss(block, UI_EMBOSS);
        
        /* mode */
 -      if(ob)
 +      if(ob) {
 +              /*sanity point checkpoint, put here to avoid seeding
 +                this same code in 10 different other places.*/
 +              if (!ob->mode)
 +                      ob->mode = OB_MODE_OBJECT;
 +
                v3d->modeselect = ob->mode;
 -      else
 +      } else {
                v3d->modeselect = OB_MODE_OBJECT;
 -
 +      }
 +      
        uiBlockBeginAlign(block);
        uiDefIconTextButS(block, MENU, B_MODESELECT, object_mode_icon(v3d->modeselect), view3d_modeselect_pup(scene) , 
-                         0,0,126 * dpi_fac,20, &(v3d->modeselect), 0, 0, 0, 0, "Mode");
+                         0,0,126 * dpi_fac, UI_UNIT_Y, &(v3d->modeselect), 0, 0, 0, 0, "Mode");
        uiBlockEndAlign(block);
        
        /* Draw type */
index da5eff8a31e52a30160732b49b75a97acecbfd15,9290e1fc631748db451a00e595aaa126c00abc01..32fc7f123591ef5283a4ba35d71f92444481c816
@@@ -489,22 -483,19 +489,19 @@@ static void do_lasso_select_mesh(ViewCo
        data.pass = 0;
  
        if (extend == 0 && select)
 -              EM_deselect_all(vc->em);
 +              EDBM_clear_flag_all(vc->em, BM_SELECT);
  
-       /* workaround: init mats first, EM_mask_init_backbuf_border can change
-          view matrix to pixel space, breaking edge select with backbuf. fixes bug [#20936] */
-       /* [#21018] breaks zbuf select. run below. only if bbsel fails */
-       /* ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d) */
+        /* for non zbuf projections, dont change the GL state */
+       ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
  
        glLoadMatrixf(vc->rv3d->viewmat);
 -      bbsel= EM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
 +      bbsel= EDBM_mask_init_backbuf_border(vc, mcords, moves, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
        
        if(ts->selectmode & SCE_SELECT_VERTEX) {
                if (bbsel) {
 -                      EM_backbuf_checkAndSelectVerts(vc->em, select);
 +                      EDBM_backbuf_checkAndSelectVerts(vc->em, select);
-               } else {
-                       ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
+               }
+               else {
                        mesh_foreachScreenVert(vc, do_lasso_select_mesh__doSelectVert, &data, 1);
                }
        }
        
        if(ts->selectmode & SCE_SELECT_FACE) {
                if (bbsel) {
 -                      EM_backbuf_checkAndSelectFaces(vc->em, select);
 +                      EDBM_backbuf_checkAndSelectFaces(vc->em, select);
-               } else {
-                       ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d); /* for foreach's screen/vert projection */
+               }
+               else {
                        mesh_foreachScreenFace(vc, do_lasso_select_mesh__doSelectFace, &data);
                }
        }
@@@ -1494,23 -1484,18 +1490,18 @@@ static int do_mesh_box_select(ViewConte
        data.done = 0;
  
        if (extend == 0 && select)
 -              EM_deselect_all(vc->em);
 +              EDBM_clear_flag_all(vc->em, BM_SELECT);
  
-       /* workaround: init mats first, EM_mask_init_backbuf_border can change
-          view matrix to pixel space, breaking edge select with backbuf. fixes bug #20936 */
-       /*ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);*/ /* for foreach's screen/vert projection */
-       /* [#21018] breaks zbuf select. run below. only if bbsel fails */
-       /* ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d) */
+       /* for non zbuf projections, dont change the GL state */
+       ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
  
        glLoadMatrixf(vc->rv3d->viewmat);
 -      bbsel= EM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
 +      bbsel= EDBM_init_backbuf_border(vc, rect->xmin, rect->ymin, rect->xmax, rect->ymax);
  
        if(ts->selectmode & SCE_SELECT_VERTEX) {
                if (bbsel) {
 -                      EM_backbuf_checkAndSelectVerts(vc->em, select);
 +                      EDBM_backbuf_checkAndSelectVerts(vc->em, select);
                } else {
-                       ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
                        mesh_foreachScreenVert(vc, do_mesh_box_select__doSelectVert, &data, 1);
                }
        }
        
        if(ts->selectmode & SCE_SELECT_FACE) {
                if(bbsel) {
 -                      EM_backbuf_checkAndSelectFaces(vc->em, select);
 +                      EDBM_backbuf_checkAndSelectFaces(vc->em, select);
                } else {
-                       ED_view3d_init_mats_rv3d(vc->obedit, vc->rv3d);
                        mesh_foreachScreenFace(vc, do_mesh_box_select__doSelectFace, &data);
                }
        }
index 1b7df335e68d3ed2b4071e5fb6e0c7866fc53292,ff277b6d9b0c6fa03f8be7df70ce81f419832d1f..5635c04793dccb4448156813f69a9b724bcadd99
@@@ -1368,10 -1393,16 +1396,16 @@@ static void rna_def_modifier_edgesplit(
        RNA_def_struct_sdna(srna, "EdgeSplitModifierData");
        RNA_def_struct_ui_icon(srna, ICON_MOD_EDGESPLIT);
  
-       // XXX, convert to radians.
+ #if 1 /* expose as radians */
+       prop= RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_ANGLE);
+       RNA_def_property_float_funcs(prop, "rna_EdgeSplitModifier_split_angle_get", "rna_EdgeSplitModifier_split_angle_set", NULL);
+       RNA_def_property_range(prop, 0, DEG2RAD(180));
+       RNA_def_property_ui_range(prop, 0, DEG2RAD(180), 100, 2);
+ #else
        prop= RNA_def_property(srna, "split_angle", PROP_FLOAT, PROP_NONE);
 -      RNA_def_property_range(prop, 0, 180);
 -      RNA_def_property_ui_range(prop, 0, 180, 100, 2);
 +      RNA_def_property_range(prop, 0, 90);
 +      RNA_def_property_ui_range(prop, 0, 90, 100, 2);
+ #endif
        RNA_def_property_ui_text(prop, "Split Angle", "Angle above which to split edges");
        RNA_def_property_update(prop, 0, "rna_Modifier_update");
  
index 2fcf352e20b99498186d29770b0fbad91ca0a021,8d0aea41b5ceb7757c4498db85d125cd7b74f810..90faff5c68cbbf4147f6810e1f23b61acaa25af1
  
  #include "MEM_guardedalloc.h"
  
 -#include "MOD_util.h"
 -
 -#if 0
 -#define EDGESPLIT_DEBUG_3
 -#define EDGESPLIT_DEBUG_2
 -#define EDGESPLIT_DEBUG_1
 -#define EDGESPLIT_DEBUG_0
 -#endif
 -
 -static void initData(ModifierData *md)
 -{
 -      EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
 -
 -      /* default to 30-degree split angle, sharpness from both angle & flag
 -      */
 -      emd->split_angle = 30;
 -      emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
 -}
 -
 -static void copyData(ModifierData *md, ModifierData *target)
 -{
 -      EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
 -      EdgeSplitModifierData *temd = (EdgeSplitModifierData*) target;
 -
 -      temd->split_angle = emd->split_angle;
 -      temd->flags = emd->flags;
 -}
 -
 -/* Mesh data for edgesplit operation */
 -typedef struct SmoothVert {
 -      LinkNode *faces;     /* all faces which use this vert */
 -      int oldIndex; /* the index of the original DerivedMesh vert */
 -      int newIndex; /* the index of the new DerivedMesh vert */
 -} SmoothVert;
 -
 -#define SMOOTHEDGE_NUM_VERTS 2
 -
 -typedef struct SmoothEdge {
 -      SmoothVert *verts[SMOOTHEDGE_NUM_VERTS]; /* the verts used by this edge */
 -      LinkNode *faces;     /* all faces which use this edge */
 -      int oldIndex; /* the index of the original DerivedMesh edge */
 -      int newIndex; /* the index of the new DerivedMesh edge */
 -      short flag; /* the flags from the original DerivedMesh edge */
 -} SmoothEdge;
 -
 -#define SMOOTHFACE_MAX_EDGES 4
 -
 -typedef struct SmoothFace {
 -      SmoothEdge *edges[SMOOTHFACE_MAX_EDGES]; /* nonexistent edges == NULL */
 -      int flip[SMOOTHFACE_MAX_EDGES]; /* 1 = flip edge dir, 0 = don't flip */
 -      float normal[3]; /* the normal of this face */
 -      int oldIndex; /* the index of the original DerivedMesh face */
 -      int newIndex; /* the index of the new DerivedMesh face */
 -} SmoothFace;
 -
 -typedef struct SmoothMesh {
 -      SmoothVert *verts;
 -      SmoothEdge *edges;
 -      SmoothFace *faces;
 -      int num_verts, num_edges, num_faces;
 -      int max_verts, max_edges, max_faces;
 -      DerivedMesh *dm;
 -      float threshold; /* the cosine of the smoothing angle */
 -      int flags;
 -      MemArena *arena;
 -      ListBase propagatestack, reusestack;
 -} SmoothMesh;
 -
 -static SmoothVert *smoothvert_copy(SmoothVert *vert, SmoothMesh *mesh)
 -{
 -      SmoothVert *copy = &mesh->verts[mesh->num_verts];
 -
 -      assert(vert != NULL);
 -
 -      if(mesh->num_verts >= mesh->max_verts) {
 -              printf("Attempted to add a SmoothMesh vert beyond end of array\n");
 -              return NULL;
 -      }
 -
 -      *copy = *vert;
 -      copy->faces = NULL;
 -      copy->newIndex = mesh->num_verts;
 -      ++mesh->num_verts;
 -
 -#ifdef EDGESPLIT_DEBUG_2
 -      printf("copied vert %4d to vert %4d\n", vert->newIndex, copy->newIndex);
 -#endif
 -      return copy;
 -}
 -
 -static SmoothEdge *smoothedge_copy(SmoothEdge *edge, SmoothMesh *mesh)
 -{
 -      SmoothEdge *copy = &mesh->edges[mesh->num_edges];
 -
 -      if(mesh->num_edges >= mesh->max_edges) {
 -              printf("Attempted to add a SmoothMesh edge beyond end of array\n");
 -              return NULL;
 -      }
 -
 -      *copy = *edge;
 -      copy->faces = NULL;
 -      copy->newIndex = mesh->num_edges;
 -      ++mesh->num_edges;
 -
 -#ifdef EDGESPLIT_DEBUG_2
 -      printf("copied edge %4d to edge %4d\n", edge->newIndex, copy->newIndex);
 -#endif
 -      return copy;
 -}
 -
 -static int smoothedge_has_vert(SmoothEdge *edge, SmoothVert *vert)
 -{
 -      int i;
 -      for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++)
 -              if(edge->verts[i] == vert) return 1;
 -
 -      return 0;
 -}
 -
 -static SmoothMesh *smoothmesh_new(int num_verts, int num_edges, int num_faces,
 -                                int max_verts, int max_edges, int max_faces)
 -{
 -      SmoothMesh *mesh = MEM_callocN(sizeof(*mesh), "smoothmesh");
 -      mesh->verts = MEM_callocN(sizeof(*mesh->verts) * max_verts,
 -                      "SmoothMesh.verts");
 -      mesh->edges = MEM_callocN(sizeof(*mesh->edges) * max_edges,
 -                      "SmoothMesh.edges");
 -      mesh->faces = MEM_callocN(sizeof(*mesh->faces) * max_faces,
 -                      "SmoothMesh.faces");
 -
 -      mesh->num_verts = num_verts;
 -      mesh->num_edges = num_edges;
 -      mesh->num_faces = num_faces;
 -
 -      mesh->max_verts = max_verts;
 -      mesh->max_edges = max_edges;
 -      mesh->max_faces = max_faces;
 +/* EdgeSplit */
 +/* EdgeSplit modifier: Splits edges in the mesh according to sharpness flag
 + * or edge angle (can be used to achieve autosmoothing)
 +*/
  
 -      return mesh;
 -}
 +#define EDGE_MARK     1
  
 -static void smoothmesh_free(SmoothMesh *mesh)
 +DerivedMesh *doEdgeSplit(DerivedMesh *dm, EdgeSplitModifierData *emd, Object *ob)
  {
 -      int i;
 -
 -      for(i = 0; i < mesh->num_verts; ++i)
 -              BLI_linklist_free(mesh->verts[i].faces, NULL);
 -
 -      for(i = 0; i < mesh->num_edges; ++i)
 -              BLI_linklist_free(mesh->edges[i].faces, NULL);
 +      BMesh *bm;
 +      BMEditMesh *em;
-       DerivedMesh *cddm, *bmdm;
++      DerivedMesh *cddm;
 +      BMIter iter, liter;
 +      BMFace *f;
 +      BMLoop *l;
 +      BMEdge *e;
-       int allocsize[] = {512, 512, 2048, 512};
++      /* int allocsize[] = {512, 512, 2048, 512}; */ /* UNUSED */
 +      float threshold = cos((emd->split_angle + 0.00001) * M_PI / 180.0);
        
 -      if(mesh->arena)
 -              BLI_memarena_free(mesh->arena);
 -
 -      MEM_freeN(mesh->verts);
 -      MEM_freeN(mesh->edges);
 -      MEM_freeN(mesh->faces);
 -      MEM_freeN(mesh);
 -}
 -
 -static void smoothmesh_resize_verts(SmoothMesh *mesh, int max_verts)
 -{
 -      int i;
 -      SmoothVert *tmp;
 -
 -      if(max_verts <= mesh->max_verts) return;
 -
 -      tmp = MEM_callocN(sizeof(*tmp) * max_verts, "SmoothMesh.verts");
 -
 -      memcpy(tmp, mesh->verts, sizeof(*tmp) * mesh->num_verts);
 -
 -      /* remap vert pointers in edges */
 -      for(i = 0; i < mesh->num_edges; ++i) {
 -              int j;
 -              SmoothEdge *edge = &mesh->edges[i];
 -
 -              for(j = 0; j < SMOOTHEDGE_NUM_VERTS; ++j)
 -                      /* pointer arithmetic to get vert array index */
 -                      edge->verts[j] = &tmp[edge->verts[j] - mesh->verts];
 -      }
 -
 -      MEM_freeN(mesh->verts);
 -      mesh->verts = tmp;
 -      mesh->max_verts = max_verts;
 -}
 -
 -static void smoothmesh_resize_edges(SmoothMesh *mesh, int max_edges)
 -{
 -      int i;
 -      SmoothEdge *tmp;
 -
 -      if(max_edges <= mesh->max_edges) return;
 -
 -      tmp = MEM_callocN(sizeof(*tmp) * max_edges, "SmoothMesh.edges");
 -
 -      memcpy(tmp, mesh->edges, sizeof(*tmp) * mesh->num_edges);
 -
 -      /* remap edge pointers in faces */
 -      for(i = 0; i < mesh->num_faces; ++i) {
 -              int j;
 -              SmoothFace *face = &mesh->faces[i];
 -
 -              for(j = 0; j < SMOOTHFACE_MAX_EDGES; ++j)
 -                      if(face->edges[j])
 -                              /* pointer arithmetic to get edge array index */
 -                              face->edges[j] = &tmp[face->edges[j] - mesh->edges];
 -      }
 -
 -      MEM_freeN(mesh->edges);
 -      mesh->edges = tmp;
 -      mesh->max_edges = max_edges;
 -}
 -
 -#ifdef EDGESPLIT_DEBUG_0
 -static void smoothmesh_print(SmoothMesh *mesh)
 -{
 -      int i, j;
 -      DerivedMesh *dm = mesh->dm;
 -
 -      printf("--- SmoothMesh ---\n");
 -      printf("--- Vertices ---\n");
 -      for(i = 0; i < mesh->num_verts; i++) {
 -              SmoothVert *vert = &mesh->verts[i];
 -              LinkNode *node;
 -              MVert mv;
 -
 -              dm->getVert(dm, vert->oldIndex, &mv);
 -
 -              printf("%3d: ind={%3d, %3d}, pos={% 5.1f, % 5.1f, % 5.1f}",
 -                      i, vert->oldIndex, vert->newIndex,
 -                      mv.co[0], mv.co[1], mv.co[2]);
 -              printf(", faces={");
 -              for(node = vert->faces; node != NULL; node = node->next) {
 -                      printf(" %d", ((SmoothFace *)node->link)->newIndex);
 -              }
 -              printf("}\n");
 -      }
 -
 -      printf("\n--- Edges ---\n");
 -      for(i = 0; i < mesh->num_edges; i++) {
 -              SmoothEdge *edge = &mesh->edges[i];
 -              LinkNode *node;
 -
 -              printf("%4d: indices={%4d, %4d}, verts={%4d, %4d}",
 -                      i,
 -                      edge->oldIndex, edge->newIndex,
 -                      edge->verts[0]->newIndex, edge->verts[1]->newIndex);
 -              if(edge->verts[0] == edge->verts[1]) printf(" <- DUPLICATE VERTEX");
 -              printf(", faces={");
 -              for(node = edge->faces; node != NULL; node = node->next) {
 -                      printf(" %d", ((SmoothFace *)node->link)->newIndex);
 -              }
 -              printf("}\n");
 -      }
 -
 -      printf("\n--- Faces ---\n");
 -      for(i = 0; i < mesh->num_faces; i++) {
 -              SmoothFace *face = &mesh->faces[i];
 -
 -              printf("%4d: indices={%4d, %4d}, edges={", i,
 -                      face->oldIndex, face->newIndex);
 -              for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
 -                      if(face->flip[j])
 -                              printf(" -%-2d", face->edges[j]->newIndex);
 -                      else
 -                              printf("  %-2d", face->edges[j]->newIndex);
 -              }
 -              printf("}, verts={");
 -              for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
 -                      printf(" %d", face->edges[j]->verts[face->flip[j]]->newIndex);
 -              }
 -              printf("}\n");
 -      }
 -}
 -#endif
 -
 -static SmoothMesh *smoothmesh_from_derivedmesh(DerivedMesh *dm)
 -{
 -      SmoothMesh *mesh;
 -      EdgeHash *edges = BLI_edgehash_new();
 -      int i;
 -      int totvert, totedge, totface;
 -
 -      totvert = dm->getNumVerts(dm);
 -      totedge = dm->getNumEdges(dm);
 -      totface = dm->getNumFaces(dm);
 -
 -      mesh = smoothmesh_new(totvert, totedge, totface,
 -                      totvert, totedge, totface);
 -
 -      mesh->dm = dm;
 -
 -      for(i = 0; i < totvert; i++) {
 -              SmoothVert *vert = &mesh->verts[i];
 -
 -              vert->oldIndex = vert->newIndex = i;
 -      }
 -
 -      for(i = 0; i < totedge; i++) {
 -              SmoothEdge *edge = &mesh->edges[i];
 -              MEdge med;
 -
 -              dm->getEdge(dm, i, &med);
 -              edge->verts[0] = &mesh->verts[med.v1];
 -              edge->verts[1] = &mesh->verts[med.v2];
 -              edge->oldIndex = edge->newIndex = i;
 -              edge->flag = med.flag;
 -
 -              BLI_edgehash_insert(edges, med.v1, med.v2, edge);
 -      }
 -
 -      for(i = 0; i < totface; i++) {
 -              SmoothFace *face = &mesh->faces[i];
 -              MFace mf;
 -              MVert v1, v2, v3;
 -              int j;
 -
 -              dm->getFace(dm, i, &mf);
 -
 -              dm->getVert(dm, mf.v1, &v1);
 -              dm->getVert(dm, mf.v2, &v2);
 -              dm->getVert(dm, mf.v3, &v3);
 -              face->edges[0] = BLI_edgehash_lookup(edges, mf.v1, mf.v2);
 -              if(face->edges[0]->verts[1]->oldIndex == mf.v1) face->flip[0] = 1;
 -              face->edges[1] = BLI_edgehash_lookup(edges, mf.v2, mf.v3);
 -              if(face->edges[1]->verts[1]->oldIndex == mf.v2) face->flip[1] = 1;
 -              if(mf.v4) {
 -                      MVert v4;
 -                      dm->getVert(dm, mf.v4, &v4);
 -                      face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v4);
 -                      if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1;
 -                      face->edges[3] = BLI_edgehash_lookup(edges, mf.v4, mf.v1);
 -                      if(face->edges[3]->verts[1]->oldIndex == mf.v4) face->flip[3] = 1;
 -                      normal_quad_v3( face->normal,v1.co, v2.co, v3.co, v4.co);
 -              } else {
 -                      face->edges[2] = BLI_edgehash_lookup(edges, mf.v3, mf.v1);
 -                      if(face->edges[2]->verts[1]->oldIndex == mf.v3) face->flip[2] = 1;
 -                      face->edges[3] = NULL;
 -                      normal_tri_v3( face->normal,v1.co, v2.co, v3.co);
 -              }
 -
 -              for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
 -                      SmoothEdge *edge = face->edges[j];
 -                      BLI_linklist_prepend(&edge->faces, face);
 -                      BLI_linklist_prepend(&edge->verts[face->flip[j]]->faces, face);
 -              }
 -
 -              face->oldIndex = face->newIndex = i;
 -      }
 -
 -      BLI_edgehash_free(edges, NULL);
 -
 -      return mesh;
 -}
 -
 -static DerivedMesh *CDDM_from_smoothmesh(SmoothMesh *mesh)
 -{
 -      DerivedMesh *result = CDDM_from_template(mesh->dm,
 -                      mesh->num_verts,
 -                      mesh->num_edges,
 -                      mesh->num_faces);
 -      MVert *new_verts = CDDM_get_verts(result);
 -      MEdge *new_edges = CDDM_get_edges(result);
 -      MFace *new_faces = CDDM_get_faces(result);
 -      int i;
 -
 -      for(i = 0; i < mesh->num_verts; ++i) {
 -              SmoothVert *vert = &mesh->verts[i];
 -              MVert *newMV = &new_verts[vert->newIndex];
 -
 -              DM_copy_vert_data(mesh->dm, result,
 -                              vert->oldIndex, vert->newIndex, 1);
 -              mesh->dm->getVert(mesh->dm, vert->oldIndex, newMV);
 -      }
 -
 -      for(i = 0; i < mesh->num_edges; ++i) {
 -              SmoothEdge *edge = &mesh->edges[i];
 -              MEdge *newME = &new_edges[edge->newIndex];
 -
 -              DM_copy_edge_data(mesh->dm, result,
 -                              edge->oldIndex, edge->newIndex, 1);
 -              mesh->dm->getEdge(mesh->dm, edge->oldIndex, newME);
 -              newME->v1 = edge->verts[0]->newIndex;
 -              newME->v2 = edge->verts[1]->newIndex;
 -      }
 -
 -      for(i = 0; i < mesh->num_faces; ++i) {
 -              SmoothFace *face = &mesh->faces[i];
 -              MFace *newMF = &new_faces[face->newIndex];
 -
 -              DM_copy_face_data(mesh->dm, result,
 -                              face->oldIndex, face->newIndex, 1);
 -              mesh->dm->getFace(mesh->dm, face->oldIndex, newMF);
 -
 -              newMF->v1 = face->edges[0]->verts[face->flip[0]]->newIndex;
 -              newMF->v2 = face->edges[1]->verts[face->flip[1]]->newIndex;
 -              newMF->v3 = face->edges[2]->verts[face->flip[2]]->newIndex;
 -
 -              if(face->edges[3]) {
 -                      newMF->v4 = face->edges[3]->verts[face->flip[3]]->newIndex;
 -              } else {
 -                      newMF->v4 = 0;
 -              }
 -      }
 -
 -      return result;
 -}
 -
 -/* returns the other vert in the given edge
 - */
 -static SmoothVert *other_vert(SmoothEdge *edge, SmoothVert *vert)
 -{
 -      if(edge->verts[0] == vert) return edge->verts[1];
 -      else return edge->verts[0];
 -}
 -
 -/* returns the other edge in the given face that uses the given vert
 - * returns NULL if no other edge in the given face uses the given vert
 - * (this should never happen)
 - */
 -static SmoothEdge *other_edge(SmoothFace *face, SmoothVert *vert,
 -                                SmoothEdge *edge)
 -{
 -      int i,j;
 -      for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) {
 -              SmoothEdge *tmp_edge = face->edges[i];
 -              if(tmp_edge == edge) continue;
 -
 -              for(j = 0; j < SMOOTHEDGE_NUM_VERTS; j++)
 -                      if(tmp_edge->verts[j] == vert) return tmp_edge;
 -      }
 -
 -      /* if we get to here, something's wrong (there should always be 2 edges
 -      * which use the same vert in a face)
 -      */
 -      return NULL;
 -}
 -
 -/* returns a face attached to the given edge which is not the given face.
 - * returns NULL if no other faces use this edge.
 - */
 -static SmoothFace *other_face(SmoothEdge *edge, SmoothFace *face)
 -{
 -      LinkNode *node;
 -
 -      for(node = edge->faces; node != NULL; node = node->next)
 -              if(node->link != face) return node->link;
 -
 -      return NULL;
 -}
 -
 -#if 0
 -/* copies source list to target, overwriting target (target is not freed)
 - * nodes in the copy will be in the same order as in source
 - */
 -static void linklist_copy(LinkNode **target, LinkNode *source)
 -{
 -      LinkNode *node = NULL;
 -      *target = NULL;
 -
 -      for(; source; source = source->next) {
 -              if(node) {
 -                      node->next = MEM_mallocN(sizeof(*node->next), "nlink_copy");
 -                      node = node->next;
 -              } else {
 -                      node = *target = MEM_mallocN(sizeof(**target), "nlink_copy");
 -              }
 -              node->link = source->link;
 -              node->next = NULL;
 -      }
 -}
 -#endif
 -
 -/* appends source to target if it's not already in target */
 -static void linklist_append_unique(LinkNode **target, void *source)
 -{
 -      LinkNode *node;
 -      LinkNode *prev = NULL;
 -
 -      /* check if source value is already in the list */
 -      for(node = *target; node; prev = node, node = node->next)
 -              if(node->link == source) return;
 -
 -      node = MEM_mallocN(sizeof(*node), "nlink");
 -      node->next = NULL;
 -      node->link = source;
 -
 -      if(prev) prev->next = node;
 -      else *target = node;
 -}
 -
 -/* appends elements of source which aren't already in target to target */
 -static void linklist_append_list_unique(LinkNode **target, LinkNode *source)
 -{
 -      for(; source; source = source->next)
 -              linklist_append_unique(target, source->link);
 -}
 -
 -#if 0 /* this is no longer used, it should possibly be removed */
 -/* prepends prepend to list - doesn't copy nodes, just joins the lists */
 -static void linklist_prepend_linklist(LinkNode **list, LinkNode *prepend)
 -{
 -      if(prepend) {
 -              LinkNode *node = prepend;
 -              while(node->next) node = node->next;
 -
 -              node->next = *list;
 -              *list = prepend;
 -      }
 -}
 -#endif
 -
 -/* returns 1 if the linked list contains the given pointer, 0 otherwise
 - */
 -static int linklist_contains(LinkNode *list, void *ptr)
 -{
 -      LinkNode *node;
 -
 -      for(node = list; node; node = node->next)
 -              if(node->link == ptr) return 1;
 -
 -      return 0;
 -}
 -
 -/* returns 1 if the first linked list is a subset of the second (comparing
 - * pointer values), 0 if not
 - */
 -static int linklist_subset(LinkNode *list1, LinkNode *list2)
 -{
 -      for(; list1; list1 = list1->next)
 -              if(!linklist_contains(list2, list1->link))
 -                      return 0;
 -
 -      return 1;
 -}
 -
 -#if 0
 -/* empties the linked list
 - * frees pointers with freefunc if freefunc is not NULL
 - */
 -static void linklist_empty(LinkNode **list, LinkNodeFreeFP freefunc)
 -{
 -      BLI_linklist_free(*list, freefunc);
 -      *list = NULL;
 -}
 -#endif
 -
 -/* removes the first instance of value from the linked list
 - * frees the pointer with freefunc if freefunc is not NULL
 - */
 -static void linklist_remove_first(LinkNode **list, void *value,
 -                                LinkNodeFreeFP freefunc)
 -{
 -      LinkNode *node = *list;
 -      LinkNode *prev = NULL;
 -
 -      while(node && node->link != value) {
 -              prev = node;
 -              node = node->next;
 -      }
 -
 -      if(node) {
 -              if(prev)
 -                      prev->next = node->next;
 -              else
 -                      *list = node->next;
 -
 -              if(freefunc)
 -                      freefunc(node->link);
 -
 -              MEM_freeN(node);
 -      }
 -}
 -
 -/* removes all elements in source from target */
 -static void linklist_remove_list(LinkNode **target, LinkNode *source,
 -                               LinkNodeFreeFP freefunc)
 -{
 -      for(; source; source = source->next)
 -              linklist_remove_first(target, source->link, freefunc);
 -}
 -
 -#ifdef EDGESPLIT_DEBUG_0
 -static void print_ptr(void *ptr)
 -{
 -      printf("%p\n", ptr);
 -}
 -
 -static void print_edge(void *ptr)
 -{
 -      SmoothEdge *edge = ptr;
 -      printf(" %4d", edge->newIndex);
 -}
 -
 -static void print_face(void *ptr)
 -{
 -      SmoothFace *face = ptr;
 -      printf(" %4d", face->newIndex);
 -}
 -#endif
 -
 -typedef struct ReplaceData {
 -      void *find;
 -      void *replace;
 -} ReplaceData;
 -
 -static void edge_replace_vert(void *ptr, void *userdata)
 -{
 -      SmoothEdge *edge = ptr;
 -      SmoothVert *find = ((ReplaceData *)userdata)->find;
 -      SmoothVert *replace = ((ReplaceData *)userdata)->replace;
 -      int i;
 -
 -#ifdef EDGESPLIT_DEBUG_3
 -      printf("replacing vert %4d with %4d in edge %4d",
 -              find->newIndex, replace->newIndex, edge->newIndex);
 -      printf(": {%4d, %4d}", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
 -#endif
 -
 -      for(i = 0; i < SMOOTHEDGE_NUM_VERTS; i++) {
 -              if(edge->verts[i] == find) {
 -                      linklist_append_list_unique(&replace->faces, edge->faces);
 -                      linklist_remove_list(&find->faces, edge->faces, NULL);
 -
 -                      edge->verts[i] = replace;
 -              }
 -      }
 -
 -#ifdef EDGESPLIT_DEBUG_3
 -      printf(" -> {%4d, %4d}\n", edge->verts[0]->newIndex, edge->verts[1]->newIndex);
 -#endif
 -}
 -
 -static void face_replace_vert(void *ptr, void *userdata)
 -{
 -      SmoothFace *face = ptr;
 -      int i;
 -
 -      for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++)
 -              edge_replace_vert(face->edges[i], userdata);
 -}
 -
 -static void face_replace_edge(void *ptr, void *userdata)
 -{
 -      SmoothFace *face = ptr;
 -      SmoothEdge *find = ((ReplaceData *)userdata)->find;
 -      SmoothEdge *replace = ((ReplaceData *)userdata)->replace;
 -      int i;
 -
 -#ifdef EDGESPLIT_DEBUG_3
 -      printf("replacing edge %4d with %4d in face %4d",
 -              find->newIndex, replace->newIndex, face->newIndex);
 -      if(face->edges[3])
 -              printf(": {%2d %2d %2d %2d}",
 -                      face->edges[0]->newIndex, face->edges[1]->newIndex,
 -                      face->edges[2]->newIndex, face->edges[3]->newIndex);
 -      else
 -              printf(": {%2d %2d %2d}",
 -                      face->edges[0]->newIndex, face->edges[1]->newIndex,
 -                      face->edges[2]->newIndex);
 -#endif
 -
 -      for(i = 0; i < SMOOTHFACE_MAX_EDGES && face->edges[i]; i++) {
 -              if(face->edges[i] == find) {
 -                      linklist_remove_first(&face->edges[i]->faces, face, NULL);
 -                      BLI_linklist_prepend(&replace->faces, face);
 -                      face->edges[i] = replace;
 -              }
 -      }
 -
 -#ifdef EDGESPLIT_DEBUG_3
 -      if(face->edges[3])
 -              printf(" -> {%2d %2d %2d %2d}\n",
 -                      face->edges[0]->newIndex, face->edges[1]->newIndex,
 -                      face->edges[2]->newIndex, face->edges[3]->newIndex);
 -      else
 -              printf(" -> {%2d %2d %2d}\n",
 -                      face->edges[0]->newIndex, face->edges[1]->newIndex,
 -                      face->edges[2]->newIndex);
 -#endif
 -}
 -
 -static int edge_is_loose(SmoothEdge *edge)
 -{
 -      return !(edge->faces && edge->faces->next);
 -}
 -
 -static int edge_is_sharp(SmoothEdge *edge)
 -{
 -#ifdef EDGESPLIT_DEBUG_1
 -      printf("edge %d: ", edge->newIndex);
 -#endif
 -      if(edge->flag & ME_SHARP) {
 -              /* edge can only be sharp if it has at least 2 faces */
 -              if(!edge_is_loose(edge)) {
 -#ifdef EDGESPLIT_DEBUG_1
 -                      printf("sharp\n");
 -#endif
 -                      return 1;
 -              } else {
 -                      /* edge is loose, so it can't be sharp */
 -                      edge->flag &= ~ME_SHARP;
 -              }
 -      }
 -
 -#ifdef EDGESPLIT_DEBUG_1
 -      printf("not sharp\n");
 -#endif
 -      return 0;
 -}
 -
 -/* finds another sharp edge which uses vert, by traversing faces around the
 - * vert until it does one of the following:
 - * - hits a loose edge (the edge is returned)
 - * - hits a sharp edge (the edge is returned)
 - * - returns to the start edge (NULL is returned)
 - */
 -static SmoothEdge *find_other_sharp_edge(SmoothVert *vert, SmoothEdge *edge, LinkNode **visited_faces)
 -{
 -      SmoothFace *face = NULL;
 -      SmoothEdge *edge2 = NULL;
 -      /* holds the edges we've seen so we can avoid looping indefinitely */
 -      LinkNode *visited_edges = NULL;
 -#ifdef EDGESPLIT_DEBUG_1
 -      printf("=== START === find_other_sharp_edge(edge = %4d, vert = %4d)\n",
 -              edge->newIndex, vert->newIndex);
 -#endif
 -
 -      /* get a face on which to start */
 -      if(edge->faces) face = edge->faces->link;
 -      else return NULL;
 -
 -      /* record this edge as visited */
 -      BLI_linklist_prepend(&visited_edges, edge);
 -
 -      /* get the next edge */
 -      edge2 = other_edge(face, vert, edge);
 -
 -      /* record this face as visited */
 -      if(visited_faces)
 -              BLI_linklist_prepend(visited_faces, face);
 -
 -      /* search until we hit a loose edge or a sharp edge or an edge we've
 -      * seen before
 -      */
 -      while(face && !edge_is_sharp(edge2)
 -                       && !linklist_contains(visited_edges, edge2)) {
 -#ifdef EDGESPLIT_DEBUG_3
 -              printf("current face %4d; current edge %4d\n", face->newIndex,
 -                      edge2->newIndex);
 -#endif
 -              /* get the next face */
 -              face = other_face(edge2, face);
 -
 -              /* if face == NULL, edge2 is a loose edge */
 -              if(face) {
 -                      /* record this face as visited */
 -                      if(visited_faces)
 -                              BLI_linklist_prepend(visited_faces, face);
 -
 -                      /* record this edge as visited */
 -                      BLI_linklist_prepend(&visited_edges, edge2);
 -
 -                      /* get the next edge */
 -                      edge2 = other_edge(face, vert, edge2);
 -#ifdef EDGESPLIT_DEBUG_3
 -                      printf("next face %4d; next edge %4d\n",
 -                              face->newIndex, edge2->newIndex);
 -              } else {
 -                      printf("loose edge: %4d\n", edge2->newIndex);
 -#endif
 -              }
 -      }
 -
 -      /* either we came back to the start edge or we found a sharp/loose edge */
 -      if(linklist_contains(visited_edges, edge2))
 -              /* we came back to the start edge */
 -              edge2 = NULL;
 -
 -      BLI_linklist_free(visited_edges, NULL);
 -
 -#ifdef EDGESPLIT_DEBUG_1
 -      printf("=== END === find_other_sharp_edge(edge = %4d, vert = %4d), "
 -              "returning edge %d\n",
 -              edge->newIndex, vert->newIndex, edge2 ? edge2->newIndex : -1);
 -#endif
 -      return edge2;
 -}
 -
 -static void split_single_vert(SmoothVert *vert, SmoothFace *face,
 -                                SmoothMesh *mesh)
 -{
 -      SmoothVert *copy_vert;
 -      ReplaceData repdata;
 -
 -      copy_vert = smoothvert_copy(vert, mesh);
 -
 -      if(copy_vert == NULL) {
 -              /* bug [#26316], this prevents a segfault
 -               * but this still needs fixing */
 -              return;
 -      }
 -
 -      repdata.find = vert;
 -      repdata.replace = copy_vert;
 -      face_replace_vert(face, &repdata);
 -}
 -
 -typedef struct PropagateEdge {
 -      struct PropagateEdge *next, *prev;
 -      SmoothEdge *edge;
 -      SmoothVert *vert;
 -} PropagateEdge;
 -
 -static void push_propagate_stack(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh)
 -{
 -      PropagateEdge *pedge = mesh->reusestack.first;
 -
 -      if(pedge) {
 -              BLI_remlink(&mesh->reusestack, pedge);
 -      }
 -      else {
 -              if(!mesh->arena) {
 -                      mesh->arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "edgesplit arena");
 -                      BLI_memarena_use_calloc(mesh->arena);
 -              }
 -
 -              pedge = BLI_memarena_alloc(mesh->arena, sizeof(PropagateEdge));
 -      }
 -
 -      pedge->edge = edge;
 -      pedge->vert = vert;
 -      BLI_addhead(&mesh->propagatestack, pedge);
 -}
 -
 -static void pop_propagate_stack(SmoothEdge **edge, SmoothVert **vert, SmoothMesh *mesh)
 -{
 -      PropagateEdge *pedge = mesh->propagatestack.first;
 -
 -      if(pedge) {
 -              *edge = pedge->edge;
 -              *vert = pedge->vert;
 -              BLI_remlink(&mesh->propagatestack, pedge);
 -              BLI_addhead(&mesh->reusestack, pedge);
 -      }
 -      else {
 -              *edge = NULL;
 -              *vert = NULL;
 -      }
 -}
 -
 -static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh);
 -
 -static void propagate_split(SmoothEdge *edge, SmoothVert *vert,
 -                              SmoothMesh *mesh)
 -{
 -      SmoothEdge *edge2;
 -      LinkNode *visited_faces = NULL;
 -#ifdef EDGESPLIT_DEBUG_1
 -      printf("=== START === propagate_split(edge = %4d, vert = %4d)\n",
 -              edge->newIndex, vert->newIndex);
 -#endif
 -
 -      edge2 = find_other_sharp_edge(vert, edge, &visited_faces);
 -
 -      if(!edge2) {
 -              /* didn't find a sharp or loose edge, so we've hit a dead end */
 -      } else if(!edge_is_loose(edge2)) {
 -              /* edge2 is not loose, so it must be sharp */
 -              if(edge_is_loose(edge)) {
 -                      /* edge is loose, so we can split edge2 at this vert */
 -                      split_edge(edge2, vert, mesh);
 -              } else if(edge_is_sharp(edge)) {
 -                      /* both edges are sharp, so we can split the pair at vert */
 -                      split_edge(edge, vert, mesh);
 -              } else {
 -                      /* edge is not sharp, so try to split edge2 at its other vert */
 -                      split_edge(edge2, other_vert(edge2, vert), mesh);
 -              }
 -      } else { /* edge2 is loose */
 -              if(edge_is_loose(edge)) {
 -                      SmoothVert *vert2;
 -                      ReplaceData repdata;
 -
 -                      /* can't split edge, what should we do with vert? */
 -                      if(linklist_subset(vert->faces, visited_faces)) {
 -                              /* vert has only one fan of faces attached; don't split it */
 -                      } else {
 -                              /* vert has more than one fan of faces attached; split it */
 -                              vert2 = smoothvert_copy(vert, mesh);
 +      if (!CDDM_Check(dm)) {
 +              cddm = CDDM_copy(dm, 0);
 +      } else cddm = dm;
 +      
 +      em = CDDM_To_BMesh(ob, dm, NULL);
 +      bm = em->bm;
  
 -                              /* fails in rare cases, see [#26993] */
 -                              if(vert2) {
 -                                      /* replace vert with its copy in visited_faces */
 -                                      repdata.find = vert;
 -                                      repdata.replace = vert2;
 -                                      BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
 +      BM_Compute_Normals(bm); 
 +      BMO_push(bm, NULL);
 +      
 +      if (emd->flags & MOD_EDGESPLIT_FROMANGLE) {
 +              BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +                      BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
 +                              float edge_angle_cos;
 +                              
 +                              if (l->radial_next == l)
 +                                      continue;
 +                              
 +                              edge_angle_cos = INPR(f->no, l->radial_next->f->no);
 +                              if (edge_angle_cos < threshold) {
 +                                      BMO_SetFlag(bm, l->e, EDGE_MARK);
                                }
                        }
 -              } else {
 -                      /* edge is not loose, so it must be sharp; split it */
 -                      split_edge(edge, vert, mesh);
                }
        }
 -
 -      BLI_linklist_free(visited_faces, NULL);
 -#ifdef EDGESPLIT_DEBUG_1
 -      printf("=== END === propagate_split(edge = %4d, vert = %4d)\n",
 -              edge->newIndex, vert->newIndex);
 -#endif
 -}
 -
 -static void split_edge(SmoothEdge *edge, SmoothVert *vert, SmoothMesh *mesh)
 -{
 -      SmoothEdge *edge2;
 -      SmoothVert *vert2;
 -      ReplaceData repdata;
 -      /* the list of faces traversed while looking for a sharp edge */
 -      LinkNode *visited_faces = NULL;
 -#ifdef EDGESPLIT_DEBUG_1
 -      printf("=== START === split_edge(edge = %4d, vert = %4d)\n",
 -              edge->newIndex, vert->newIndex);
 -#endif
 -
 -      edge2 = find_other_sharp_edge(vert, edge, &visited_faces);
 -
 -      if(!edge2) {
 -              /* didn't find a sharp or loose edge, so try the other vert */
 -              vert2 = other_vert(edge, vert);
 -              push_propagate_stack(edge, vert2, mesh);
 -      } else if(!edge_is_loose(edge2)) {
 -              /* edge2 is not loose, so it must be sharp */
 -              SmoothEdge *copy_edge = smoothedge_copy(edge, mesh);
 -              SmoothEdge *copy_edge2 = smoothedge_copy(edge2, mesh);
 -              SmoothVert *vert2;
 -
 -              /* replace edge with its copy in visited_faces */
 -              repdata.find = edge;
 -              repdata.replace = copy_edge;
 -              BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
 -
 -              /* replace edge2 with its copy in visited_faces */
 -              repdata.find = edge2;
 -              repdata.replace = copy_edge2;
 -              BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
 -
 -              vert2 = smoothvert_copy(vert, mesh);
 -
 -              /* replace vert with its copy in visited_faces (must be done after
 -              * edge replacement so edges have correct vertices)
 -              */
 -              repdata.find = vert;
 -              repdata.replace = vert2;
 -              BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
 -
 -              /* all copying and replacing is done; the mesh should be consistent.
 -              * now propagate the split to the vertices at either end
 -              */
 -              push_propagate_stack(copy_edge, other_vert(copy_edge, vert2), mesh);
 -              push_propagate_stack(copy_edge2, other_vert(copy_edge2, vert2), mesh);
 -
 -              if(smoothedge_has_vert(edge, vert))
 -                      push_propagate_stack(edge, vert, mesh);
 -      } else {
 -              /* edge2 is loose */
 -              SmoothEdge *copy_edge = smoothedge_copy(edge, mesh);
 -              SmoothVert *vert2;
 -
 -              /* replace edge with its copy in visited_faces */
 -              repdata.find = edge;
 -              repdata.replace = copy_edge;
 -              BLI_linklist_apply(visited_faces, face_replace_edge, &repdata);
 -
 -              vert2 = smoothvert_copy(vert, mesh);
 -
 -              /* replace vert with its copy in visited_faces (must be done after
 -              * edge replacement so edges have correct vertices)
 -              */
 -              repdata.find = vert;
 -              repdata.replace = vert2;
 -              BLI_linklist_apply(visited_faces, face_replace_vert, &repdata);
 -
 -              /* copying and replacing is done; the mesh should be consistent.
 -              * now propagate the split to the vertex at the other end
 -              */
 -              push_propagate_stack(copy_edge, other_vert(copy_edge, vert2), mesh);
 -
 -              if(smoothedge_has_vert(edge, vert))
 -                      push_propagate_stack(edge, vert, mesh);
 -      }
 -
 -      BLI_linklist_free(visited_faces, NULL);
 -#ifdef EDGESPLIT_DEBUG_1
 -      printf("=== END === split_edge(edge = %4d, vert = %4d)\n",
 -              edge->newIndex, vert->newIndex);
 -#endif
 -}
 -
 -static void tag_and_count_extra_edges(SmoothMesh *mesh, float split_angle,
 -                                        int flags, int *extra_edges)
 -{
 -      /* if normal1 dot normal2 < threshold, angle is greater, so split */
 -      /* FIXME not sure if this always works */
 -      /* 0.00001 added for floating-point rounding */
 -      float threshold = cos((split_angle + 0.00001f) * (float)M_PI / 180.0f);
 -      int i;
 -
 -      *extra_edges = 0;
 -
 -      /* loop through edges, counting potential new ones */
 -      for(i = 0; i < mesh->num_edges; i++) {
 -              SmoothEdge *edge = &mesh->edges[i];
 -              int sharp = 0;
 -
 -              /* treat all non-manifold edges (3 or more faces) as sharp */
 -              if(edge->faces && edge->faces->next && edge->faces->next->next) {
 -                      LinkNode *node;
 -
 -                      /* this edge is sharp */
 -                      sharp = 1;
 -
 -                      /* add an extra edge for every face beyond the first */
 -                      *extra_edges += 2;
 -                      for(node = edge->faces->next->next->next; node; node = node->next)
 -                              (*extra_edges)++;
 -              } else if((flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG))
 -                                       && !edge_is_loose(edge)) {
 -                      /* (the edge can only be sharp if we're checking angle or flag,
 -                      * and it has at least 2 faces) */
 -
 -                      /* if we're checking the sharp flag and it's set, good */
 -                      if((flags & MOD_EDGESPLIT_FROMFLAG) && (edge->flag & ME_SHARP)) {
 -                              /* this edge is sharp */
 -                              sharp = 1;
 -
 -                              (*extra_edges)++;
 -                      } else if(flags & MOD_EDGESPLIT_FROMANGLE) {
 -                              /* we know the edge has 2 faces, so check the angle */
 -                              SmoothFace *face1 = edge->faces->link;
 -                              SmoothFace *face2 = edge->faces->next->link;
 -                              float edge_angle_cos = dot_v3v3(face1->normal,
 -                              face2->normal);
 -
 -                              if(edge_angle_cos < threshold) {
 -                                      /* this edge is sharp */
 -                                      sharp = 1;
 -
 -                                      (*extra_edges)++;
 -                              }
 -                      }
 +      
 +      if (emd->flags & MOD_EDGESPLIT_FROMFLAG) {
 +              BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +                      if (BM_TestHFlag(e, BM_SHARP))
 +                              BMO_SetFlag(bm, e, EDGE_MARK);
                }
 -
 -              /* set/clear sharp flag appropriately */
 -              if(sharp) edge->flag |= ME_SHARP;
 -              else edge->flag &= ~ME_SHARP;
        }
 -}
 -
 -static void split_sharp_edges(SmoothMesh *mesh, float split_angle, int flags)
 -{
 -      SmoothVert *vert;
 -      int i;
 -      /* if normal1 dot normal2 < threshold, angle is greater, so split */
 -      /* FIXME not sure if this always works */
 -      /* 0.00001 added for floating-point rounding */
 -      mesh->threshold = cosf((split_angle + 0.00001f) * (float)M_PI / 180.0f);
 -      mesh->flags = flags;
 -
 -      /* loop through edges, splitting sharp ones */
 -      /* can't use an iterator here, because we'll be adding edges */
 -      for(i = 0; i < mesh->num_edges; i++) {
 -              SmoothEdge *edge = &mesh->edges[i];
 -
 -              if(edge_is_sharp(edge)) {
 -                      split_edge(edge, edge->verts[0], mesh);
 -
 -                      do {
 -                              pop_propagate_stack(&edge, &vert, mesh);
 -                              if(edge && smoothedge_has_vert(edge, vert))
 -                                      propagate_split(edge, vert, mesh);
 -                      } while(edge);
 -              }
 +      
 +      BMO_CallOpf(bm, "edgesplit edges=%fe", EDGE_MARK);
 +      
 +      BMO_pop(bm);
 +      BMEdit_RecalcTesselation(em);
 +      
 +      if (cddm != dm) {
 +              cddm->needsFree = 1;
 +              cddm->release(cddm);
        }
 +      
 +      cddm = CDDM_from_BMEditMesh(em, NULL, 1);
 +      BMEdit_Free(em);
 +      MEM_freeN(em);
 +      
 +      return cddm;
  }
  
 -static int count_bridge_verts(SmoothMesh *mesh)
 +static void initData(ModifierData *md)
  {
 -      int i, j, count = 0;
 -
 -      for(i = 0; i < mesh->num_faces; i++) {
 -              SmoothFace *face = &mesh->faces[i];
 -
 -              for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
 -                      SmoothEdge *edge = face->edges[j];
 -                      SmoothEdge *next_edge;
 -                      SmoothVert *vert = edge->verts[1 - face->flip[j]];
 -                      int next = (j + 1) % SMOOTHFACE_MAX_EDGES;
 -
 -                      /* wrap next around if at last edge */
 -                      if(!face->edges[next]) next = 0;
 -
 -                      next_edge = face->edges[next];
 -
 -                      /* if there are other faces sharing this vertex but not
 -                      * these edges, the vertex will be split, so count it
 -                      */
 -                      /* vert has to have at least one face (this one), so faces != 0 */
 -                      if(!edge->faces->next && !next_edge->faces->next
 -                                               && vert->faces->next) {
 -                              count++;
 -                                               }
 -              }
 -      }
 +      EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
  
 -      /* each bridge vert will be counted once per face that uses it,
 -      * so count is too high, but it's ok for now
 +      /* default to 30-degree split angle, sharpness from both angle & flag
        */
 -      return count;
 +      emd->split_angle = 30;
 +      emd->flags = MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG;
  }
  
 -static void split_bridge_verts(SmoothMesh *mesh)
 +static void copyData(ModifierData *md, ModifierData *target)
  {
 -      int i,j;
 -
 -      for(i = 0; i < mesh->num_faces; i++) {
 -              SmoothFace *face = &mesh->faces[i];
 -
 -              for(j = 0; j < SMOOTHFACE_MAX_EDGES && face->edges[j]; j++) {
 -                      SmoothEdge *edge = face->edges[j];
 -                      SmoothEdge *next_edge;
 -                      SmoothVert *vert = edge->verts[1 - face->flip[j]];
 -                      int next = (j + 1) % SMOOTHFACE_MAX_EDGES;
 -
 -                      /* wrap next around if at last edge */
 -                      if(!face->edges[next]) next = 0;
 -
 -                      next_edge = face->edges[next];
 +      EdgeSplitModifierData *emd = (EdgeSplitModifierData*) md;
 +      EdgeSplitModifierData *temd = (EdgeSplitModifierData*) target;
  
 -                      /* if there are other faces sharing this vertex but not
 -                      * these edges, split the vertex
 -                      */
 -                      /* vert has to have at least one face (this one), so faces != 0 */
 -                      if(!edge->faces->next && !next_edge->faces->next
 -                                               && vert->faces->next)
 -                              /* FIXME this needs to find all faces that share edges with
 -                              * this one and split off together
 -                              */
 -                              split_single_vert(vert, face, mesh);
 -              }
 -      }
 +      temd->split_angle = emd->split_angle;
 +      temd->flags = emd->flags;
  }
  
 -static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd, DerivedMesh *dm)
 +static DerivedMesh *edgesplitModifier_do(EdgeSplitModifierData *emd,
 +                                       Object *ob, DerivedMesh *dm)
  {
 -      SmoothMesh *mesh;
 -      DerivedMesh *result;
 -      int max_verts, max_edges;
 -
        if(!(emd->flags & (MOD_EDGESPLIT_FROMANGLE | MOD_EDGESPLIT_FROMFLAG)))
                return dm;
  
Simple merge
Simple merge