svn merge ^/trunk/blender -r40872:40890
authorCampbell Barton <ideasman42@gmail.com>
Thu, 13 Oct 2011 22:50:01 +0000 (22:50 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 13 Oct 2011 22:50:01 +0000 (22:50 +0000)
15 files changed:
1  2 
release/scripts/startup/bl_ui/properties_data_modifier.py
source/blender/blenkernel/BKE_mesh.h
source/blender/blenkernel/CMakeLists.txt
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/editderivedbmesh.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/view3d_select.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/makesrna/intern/rna_modifier.c
source/blender/makesrna/intern/rna_object.c
source/blender/modifiers/CMakeLists.txt
source/blender/modifiers/intern/MOD_util.c

index 7d4d970b2389957247a6ceb114ca3de999196bb6,62261af729f81be0807ac8738a301574c5c5eddd..146855bb806ebe5cc4823d116c18a3a9659dd029
@@@ -46,11 -46,7 +46,11 @@@ class DATA_PT_modifiers(ModifierButtons
      # the mt.type enum is (ab)used for a lookup on function names
      # ...to avoid lengthy if statements
      # so each type must have a function here.
 -
 +      
 +    def NGONINTERP(self, layout, ob, md):
 +        split = layout.split()
 +        split.prop(md, "resolution")
 +        
      def ARMATURE(self, layout, ob, md):
          split = layout.split()
  
          col.label(text="Mirror Object:")
          col.prop(md, "mirror_object", text="")
  
-     def NAVMESH(self, layout, ob, md):
-         layout.operator("mesh.assign_navpolygon")
-         layout.operator("mesh.assign_new_navpolygon")
      def MULTIRES(self, layout, ob, md):
          layout.row().prop(md, "subdivision_type", expand=True)
  
index df22fdcc78af4555166ff19a40f5d8f4ed47b11f,052e18a98ea92c239ee9ead9c5c50e8544a9307c..b414bcef474a4114f6bf3883c81d1022e3974aa5
  struct BoundBox;
  struct DispList;
  struct ListBase;
 -struct EditMesh;
 -struct MDeformVert;
 +struct BMEditMesh;
 +struct BMesh;
  struct Mesh;
 +struct MPoly;
 +struct MLoop;
  struct MFace;
  struct MEdge;
  struct MVert;
 +struct MDeformVert;
  struct MCol;
  struct Object;
  struct MTFace;
@@@ -61,35 -58,14 +61,35 @@@ struct Scene
  extern "C" {
  #endif
  
 -struct EditMesh *BKE_mesh_get_editmesh(struct Mesh *me);
 -void BKE_mesh_end_editmesh(struct Mesh *me, struct EditMesh *em);
 +struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob);
 +
 +/*
 +  this function recreates a tesselation.
 +  returns number of tesselation faces.
 +
 +  use_poly_origindex sets whether or not the tesselation faces' origindex
 +  layer should point to original poly indices or real poly indices.
 +
 +  use_face_origindex sets the tesselation faces' origindex layer
 +  to point to the tesselation faces themselves, not the polys.
 +
 +  if both of the above are 0, it'll use the indices of the mpolys of the MPoly
 +  data in pdata, and ignore the origindex layer altogether.
 + */
 +int mesh_recalcTesselation(struct CustomData *fdata, struct CustomData *ldata, 
 +      struct CustomData *pdata, struct MVert *mvert, int totface, 
 +      int totloop, int totpoly, int use_poly_origindex, int use_face_origindex);
 +
 +/*calculates a face normal.*/
 +void mesh_calc_poly_normal(struct MPoly *mpoly, struct MLoop *loopstart, 
 +                           struct MVert *mvarray, float *no);
  
  void unlink_mesh(struct Mesh *me);
 -void free_mesh(struct Mesh *me);
 +void free_mesh(struct Mesh *me, int unlink);
  struct Mesh *add_mesh(const char *name);
  struct Mesh *copy_mesh(struct Mesh *me);
  void mesh_update_customdata_pointers(struct Mesh *me);
 +
  void make_local_mesh(struct Mesh *me);
  void boundbox_mesh(struct Mesh *me, float *loc, float *size);
  void tex_space_mesh(struct Mesh *me);
@@@ -99,26 -75,17 +99,26 @@@ int test_index_face(struct MFace *mface
  struct Mesh *get_mesh(struct Object *ob);
  void set_mesh(struct Object *ob, struct Mesh *me);
  void mball_to_mesh(struct ListBase *lb, struct Mesh *me);
 -int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *_totvert,
 -      struct MEdge **alledge, int *_totedge, struct MFace **allface, int *_totface);
 -int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase,
 -      struct MVert **allvert, int *_totvert, struct MEdge **alledge, int *_totedge,
 -      struct MFace **allface, int *_totface);
 +int nurbs_to_mdata(struct Object *ob, struct MVert **allvert, int *totvert,
 +      struct MEdge **alledge, int *totedge, struct MFace **allface, struct MLoop **allloop, struct MPoly **allpoly, 
 +      int *totface, int *totloop, int *totpoly);
 +int nurbs_to_mdata_customdb(struct Object *ob, struct ListBase *dispbase, struct MVert **allvert, int *_totvert,
 +      struct MEdge **alledge, int *_totedge, struct MFace **allface, struct MLoop **allloop, struct MPoly **allpoly, 
 +      int *_totface, int *_totloop, int *_totpoly);
  void nurbs_to_mesh(struct Object *ob);
  void mesh_to_curve(struct Scene *scene, struct Object *ob);
  void free_dverts(struct MDeformVert *dvert, int totvert);
  void copy_dverts(struct MDeformVert *dst, struct MDeformVert *src, int totvert); /* __NLA */
  void mesh_delete_material_index(struct Mesh *me, short index);
  void mesh_set_smooth_flag(struct Object *meshOb, int enableSmooth);
 +void convert_mfaces_to_mpolys(struct Mesh *mesh);
 +void mesh_calc_tessface_normals(struct MVert *mverts, int numVerts,struct  MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
 +
 +/*used for unit testing; compares two meshes, checking only
 +  differences we care about.  should be usable with leaf's
 +  testing framework I get RNA work done, will use hackish
 +  testing code for now.*/
 +const char *mesh_cmp(struct Mesh *me1, struct Mesh *me2, float thresh);
  
  struct BoundBox *mesh_get_bb(struct Object *ob);
  void mesh_get_texspace(struct Mesh *me, float *loc_r, float *rot_r, float *size_r);
@@@ -132,9 -99,7 +132,9 @@@ void mesh_strip_loose_edges(struct Mes
        /* Calculate vertex and face normals, face normals are returned in *faceNors_r if non-NULL
         * and vertex normals are stored in actual mverts.
         */
 -void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MFace *mfaces, int numFaces, float (*faceNors_r)[3]);
 +void mesh_calc_normals(struct MVert *mverts, int numVerts, struct MLoop *mloop, 
 +      struct MPoly *mpolys, int numLoops, int numPolys, float (*polyNors_r)[3], 
 +      struct MFace *mfaces, int numFaces, int *origIndexFace, float (*faceNors_r)[3]);
  
        /* Return a newly MEM_malloc'd array of all the mesh vertex locations
         * (_numVerts_r_ may be NULL) */
@@@ -196,11 -161,8 +196,13 @@@ int BKE_mesh_validate_dm(struct Derived
  
  void BKE_mesh_calc_edges(struct Mesh *mesh, int update);
  
+ void BKE_mesh_ensure_navmesh(struct Mesh *me);
 +/*convert a triangle of loop facedata to mface facedata*/
 +void mesh_loops_to_tri_corners(struct CustomData *fdata, struct CustomData *ldata, 
 +                         struct CustomData *pdata, int lindex[3], int findex, 
 +                         int polyindex);
 +
  #ifdef __cplusplus
  }
  #endif
index 2a8d0fb0fb9d4d035faab6625b5240058683618b,bfadff064006c64ac9c7e7554df43a3308d3a52c..35116a7e2f41ae784853b80fa71102fa3935864f
@@@ -40,7 -40,6 +40,7 @@@ set(IN
        ../imbuf
        ../makesdna
        ../makesrna
 +      ../bmesh
        ../modifiers
        ../nodes
        ../render/extern/include
@@@ -96,7 -95,6 +96,7 @@@ set(SR
        intern/depsgraph.c
        intern/displist.c
        intern/effect.c
 +      intern/editderivedbmesh.c
        intern/fcurve.c
        intern/fluidsim.c
        intern/fmodifier.c
        intern/mesh.c
        intern/mesh_validate.c
        intern/modifier.c
 +      intern/modifiers_bmesh.c
        intern/multires.c
        intern/nla.c
        intern/node.c
        BKE_speaker.h
        BKE_subsurf.h
        BKE_suggestions.h
 +      BKE_tessmesh.h
        BKE_text.h
        BKE_texture.h
        BKE_unit.h
@@@ -357,12 -353,14 +357,14 @@@ endif(
  
  if(WITH_GAMEENGINE)
        list(APPEND INC_SYS
-       ../../../extern/recastnavigation
+               ../../../extern/recastnavigation
        )
        list(APPEND SRC
                intern/navmesh_conversion.c
                BKE_navmesh_conversion.h
        )
+       add_definitions(-DWITH_GAMEENGINE)
  endif()
  
  ## Warnings as errors, this is too strict!
index 5e0ccac360fc8787ebba92c2e3c3eda5842f0510,e46ea1bbe38cc2f56236f05435cf1b543aff0a11..1578eebb4fe7099031d6892957e51549674571cc
@@@ -33,7 -33,7 +33,7 @@@
  
  
  #include <string.h>
 -
 +#include "limits.h"
  
  #include "MEM_guardedalloc.h"
  
@@@ -48,7 -48,6 +48,7 @@@
  #include "BLI_editVert.h"
  #include "BLI_math.h"
  #include "BLI_memarena.h"
 +#include "BLI_array.h"
  #include "BLI_pbvh.h"
  #include "BLI_utildefines.h"
  
  #include "BKE_texture.h"
  #include "BKE_multires.h"
  #include "BKE_armature.h"
 +#include "BKE_particle.h"
 +#include "BKE_tessmesh.h"
 +#include "BKE_bvhutils.h"
  
+ #ifdef WITH_GAMEENGINE
+ #include "BKE_navmesh_conversion.h"
+ #endif
  #include "BLO_sys_types.h" // for intptr_t support
  
  #include "GL/glew.h"
  
  extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
  
-               ///////////////////////////////////
 +static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *ob);
 +static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid);
 +
+ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
+ ///////////////////////////////////
  ///////////////////////////////////
  
  static MVert *dm_getVertArray(DerivedMesh *dm)
@@@ -117,42 -116,14 +123,42 @@@ static MFace *dm_getFaceArray(DerivedMe
  
        if (!mface) {
                mface = CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL,
 -                      dm->getNumFaces(dm));
 +                      dm->getNumTessFaces(dm));
                CustomData_set_layer_flag(&dm->faceData, CD_MFACE, CD_FLAG_TEMPORARY);
 -              dm->copyFaceArray(dm, mface);
 +              dm->copyTessFaceArray(dm, mface);
        }
  
        return mface;
  }
  
 +static MLoop *dm_getLoopArray(DerivedMesh *dm)
 +{
 +      MLoop *mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
 +
 +      if (!mloop) {
 +              mloop = CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL,
 +                      dm->numLoopData);
 +              CustomData_set_layer_flag(&dm->loopData, CD_MLOOP, CD_FLAG_TEMPORARY);
 +              dm->copyLoopArray(dm, mloop);
 +      }
 +
 +      return mloop;
 +}
 +
 +static MPoly *dm_getPolyArray(DerivedMesh *dm)
 +{
 +      MPoly *mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
 +
 +      if (!mpoly) {
 +              mpoly = CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL,
 +                      dm->getNumFaces(dm));
 +              CustomData_set_layer_flag(&dm->polyData, CD_MPOLY, CD_FLAG_TEMPORARY);
 +              dm->copyPolyArray(dm, mpoly);
 +      }
 +
 +      return mpoly;
 +}
 +
  static MVert *dm_dupVertArray(DerivedMesh *dm)
  {
        MVert *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumVerts(dm),
@@@ -175,98 -146,41 +181,98 @@@ static MEdge *dm_dupEdgeArray(DerivedMe
  
  static MFace *dm_dupFaceArray(DerivedMesh *dm)
  {
 -      MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumFaces(dm),
 +      MFace *tmp = MEM_callocN(sizeof(*tmp) * dm->getNumTessFaces(dm),
                                                         "dm_dupFaceArray tmp");
  
 -      if(tmp) dm->copyFaceArray(dm, tmp);
 +      if(tmp) dm->copyTessFaceArray(dm, tmp);
 +
 +      return tmp;
 +}
 +
 +static MLoop *dm_dupLoopArray(DerivedMesh *dm)
 +{
 +      MLoop *tmp = MEM_callocN(sizeof(*tmp) * dm->numLoopData,
 +                                                       "dm_dupLoopArray tmp");
 +
 +      if(tmp) dm->copyLoopArray(dm, tmp);
  
        return tmp;
  }
  
 +static MPoly *dm_dupPolyArray(DerivedMesh *dm)
 +{
 +      MPoly *tmp = MEM_callocN(sizeof(*tmp) * dm->numFaceData,
 +                                                       "dm_dupPolyArray tmp");
 +
 +      if(tmp) dm->copyPolyArray(dm, tmp);
 +
 +      return tmp;
 +}
 +
 +static CustomData *dm_getVertCData(DerivedMesh *dm)
 +{
 +      return &dm->vertData;
 +}
 +
 +static CustomData *dm_getEdgeCData(DerivedMesh *dm)
 +{
 +      return &dm->edgeData;
 +}
 +
 +static CustomData *dm_getFaceCData(DerivedMesh *dm)
 +{
 +      return &dm->faceData;
 +}
 +
 +static CustomData *dm_getLoopCData(DerivedMesh *dm)
 +{
 +      return &dm->loopData;
 +}
 +
 +static CustomData *dm_getPolyCData(DerivedMesh *dm)
 +{
 +      return &dm->polyData;
 +}
 +
  void DM_init_funcs(DerivedMesh *dm)
  {
        /* default function implementations */
        dm->getVertArray = dm_getVertArray;
        dm->getEdgeArray = dm_getEdgeArray;
 -      dm->getFaceArray = dm_getFaceArray;
 +      dm->getTessFaceArray = dm_getFaceArray;
 +      dm->getLoopArray = dm_getLoopArray;
 +      dm->getPolyArray = dm_getPolyArray;
        dm->dupVertArray = dm_dupVertArray;
        dm->dupEdgeArray = dm_dupEdgeArray;
 -      dm->dupFaceArray = dm_dupFaceArray;
 +      dm->dupTessFaceArray = dm_dupFaceArray;
 +      dm->dupLoopArray = dm_dupLoopArray;
 +      dm->dupPolyArray = dm_dupPolyArray;
 +
 +      dm->getVertDataLayout = dm_getVertCData;
 +      dm->getEdgeDataLayout = dm_getEdgeCData;
 +      dm->getTessFaceDataLayout = dm_getFaceCData;
 +      dm->getLoopDataLayout = dm_getLoopCData;
 +      dm->getFaceDataLayout = dm_getPolyCData;
  
        dm->getVertData = DM_get_vert_data;
        dm->getEdgeData = DM_get_edge_data;
 -      dm->getFaceData = DM_get_face_data;
 +      dm->getTessFaceData = DM_get_face_data;
        dm->getVertDataArray = DM_get_vert_data_layer;
        dm->getEdgeDataArray = DM_get_edge_data_layer;
 -      dm->getFaceDataArray = DM_get_face_data_layer;
 +      dm->getTessFaceDataArray = DM_get_tessface_data_layer;
  
        bvhcache_init(&dm->bvhCache);
  }
  
 -void DM_init(DerivedMesh *dm, DerivedMeshType type,
 -                       int numVerts, int numEdges, int numFaces)
 +void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
 +           int numFaces, int numLoops, int numPoly)
  {
        dm->type = type;
        dm->numVertData = numVerts;
        dm->numEdgeData = numEdges;
        dm->numFaceData = numFaces;
 +      dm->numLoopData = numLoops;
 +      dm->numPolyData = numPoly;
  
        DM_init_funcs(dm);
        
  }
  
  void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
 -                                        int numVerts, int numEdges, int numFaces)
 +                      int numVerts, int numEdges, int numFaces,
 +                    int numLoops, int numPolys)
  {
        CustomData_copy(&source->vertData, &dm->vertData, CD_MASK_DERIVEDMESH,
                                        CD_CALLOC, numVerts);
                                        CD_CALLOC, numEdges);
        CustomData_copy(&source->faceData, &dm->faceData, CD_MASK_DERIVEDMESH,
                                        CD_CALLOC, numFaces);
 +      CustomData_copy(&source->loopData, &dm->loopData, CD_MASK_DERIVEDMESH,
 +                      CD_CALLOC, numLoops);
 +      CustomData_copy(&source->polyData, &dm->polyData, CD_MASK_DERIVEDMESH,
 +                      CD_CALLOC, numPolys);
  
        dm->type = type;
        dm->numVertData = numVerts;
        dm->numEdgeData = numEdges;
        dm->numFaceData = numFaces;
 +      dm->numLoopData = numLoops;
 +      dm->numPolyData = numPolys;
  
        DM_init_funcs(dm);
  
@@@ -308,8 -215,6 +314,8 @@@ int DM_release(DerivedMesh *dm
                CustomData_free(&dm->vertData, dm->numVertData);
                CustomData_free(&dm->edgeData, dm->numEdgeData);
                CustomData_free(&dm->faceData, dm->numFaceData);
 +              CustomData_free(&dm->loopData, dm->numLoopData);
 +              CustomData_free(&dm->polyData, dm->numPolyData);
  
                return 1;
        }
                CustomData_free_temporary(&dm->vertData, dm->numVertData);
                CustomData_free_temporary(&dm->edgeData, dm->numEdgeData);
                CustomData_free_temporary(&dm->faceData, dm->numFaceData);
 +              CustomData_free_temporary(&dm->loopData, dm->numLoopData);
 +              CustomData_free_temporary(&dm->polyData, dm->numPolyData);
  
                return 0;
        }
  }
  
 -void DM_to_mesh(DerivedMesh *dm, Mesh *me)
 +void DM_DupPolys(DerivedMesh *source, DerivedMesh *target)
 +{
 +      CustomData_copy(&source->loopData, &target->loopData, CD_MASK_DERIVEDMESH, CD_CALLOC, source->numLoopData);
 +      CustomData_copy(&source->polyData, &target->polyData, CD_MASK_DERIVEDMESH, CD_CALLOC, source->numPolyData);
 +
 +      target->numLoopData = source->numLoopData;
 +      target->numPolyData = source->numPolyData;
 +
 +      if (!CustomData_has_layer(&target->polyData, CD_MPOLY)) {
 +              MPoly *mpoly;
 +              MLoop *mloop;
 +
 +              mloop = source->dupLoopArray(source);
 +              mpoly = source->dupPolyArray(source);
 +              CustomData_add_layer(&target->loopData, CD_MLOOP, CD_ASSIGN, mloop, source->numLoopData);
 +              CustomData_add_layer(&target->polyData, CD_MPOLY, CD_ASSIGN, mpoly, source->numPolyData);
 +      }
 +}
 +
 +void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
  {
        /* dm might depend on me, so we need to do everything with a local copy */
        Mesh tmp = *me;
 -      int totvert, totedge, totface;
 -
 +      int totvert, totedge, totface, totloop, totpoly;
 +      int did_shapekeys=0;
 +      
        memset(&tmp.vdata, 0, sizeof(tmp.vdata));
        memset(&tmp.edata, 0, sizeof(tmp.edata));
        memset(&tmp.fdata, 0, sizeof(tmp.fdata));
 +      memset(&tmp.ldata, 0, sizeof(tmp.ldata));
 +      memset(&tmp.pdata, 0, sizeof(tmp.pdata));
  
        totvert = tmp.totvert = dm->getNumVerts(dm);
        totedge = tmp.totedge = dm->getNumEdges(dm);
 -      totface = tmp.totface = dm->getNumFaces(dm);
 +      totface = tmp.totface = dm->getNumTessFaces(dm);
 +      totpoly = tmp.totpoly = dm->getNumFaces(dm);
 +      totloop = tmp.totloop = dm->numLoopData;
  
        CustomData_copy(&dm->vertData, &tmp.vdata, CD_MASK_MESH, CD_DUPLICATE, totvert);
        CustomData_copy(&dm->edgeData, &tmp.edata, CD_MASK_MESH, CD_DUPLICATE, totedge);
        CustomData_copy(&dm->faceData, &tmp.fdata, CD_MASK_MESH, CD_DUPLICATE, totface);
 +      CustomData_copy(&dm->loopData, &tmp.ldata, CD_MASK_MESH, CD_DUPLICATE, totloop);
 +      CustomData_copy(&dm->polyData, &tmp.pdata, CD_MASK_MESH, CD_DUPLICATE, totpoly);
  
 +      if (CustomData_has_layer(&dm->vertData, CD_SHAPEKEY)) {
 +              KeyBlock *kb;
 +              int i=0;
 +              
 +              if (ob) {
 +                      for (kb=me->key->block.first; kb; kb=kb->next, i++) {
 +                              if (i == ob->shapenr-1) {
 +                                      i = kb->uid;
 +                                      break;
 +                              }
 +                      }
 +                      
 +                      if (!kb) {
 +                              printf("error in DM_to_mesh: could not find active shapekey! eek!!\n");
 +                              i = INT_MAX;
 +                      }
 +              } else {
 +                      /*if no object, set to INT_MAX so we don't mess up any shapekey layers*/
 +                      i = INT_MAX;
 +              }
 +              
 +              shapekey_layers_to_keyblocks(dm, me, i);
 +              did_shapekeys = 1;
 +      }
 +      
        /* not all DerivedMeshes store their verts/edges/faces in CustomData, so
           we set them here in case they are missing */
        if(!CustomData_has_layer(&tmp.vdata, CD_MVERT))
        if(!CustomData_has_layer(&tmp.edata, CD_MEDGE))
                CustomData_add_layer(&tmp.edata, CD_MEDGE, CD_ASSIGN, dm->dupEdgeArray(dm), totedge);
        if(!CustomData_has_layer(&tmp.fdata, CD_MFACE))
 -              CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupFaceArray(dm), totface);
 +              CustomData_add_layer(&tmp.fdata, CD_MFACE, CD_ASSIGN, dm->dupTessFaceArray(dm), totface);
 +      if(!CustomData_has_layer(&tmp.pdata, CD_MPOLY)) {
 +              tmp.mloop = dm->dupLoopArray(dm);
 +              tmp.mpoly = dm->dupPolyArray(dm);
 +
 +              CustomData_add_layer(&tmp.ldata, CD_MLOOP, CD_ASSIGN, tmp.mloop, tmp.totloop);
 +              CustomData_add_layer(&tmp.pdata, CD_MPOLY, CD_ASSIGN, tmp.mpoly, tmp.totpoly);
 +      }
  
        /* object had got displacement layer, should copy this layer to save sculpted data */
        /* NOTE: maybe some other layers should be copied? nazgul */
 -      if(CustomData_has_layer(&me->fdata, CD_MDISPS)) {
 -              if (totface == me->totface) {
 -                      MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
 -                      CustomData_add_layer(&tmp.fdata, CD_MDISPS, CD_DUPLICATE, mdisps, totface);
 +      if(CustomData_has_layer(&me->ldata, CD_MDISPS)) {
 +              if (totloop == me->totloop) {
 +                      MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS);
 +                      CustomData_add_layer(&tmp.ldata, CD_MDISPS, CD_DUPLICATE, mdisps, totloop);
                }
        }
  
        CustomData_free(&me->vdata, me->totvert);
        CustomData_free(&me->edata, me->totedge);
        CustomData_free(&me->fdata, me->totface);
 -
 -      /* if the number of verts has changed, remove invalid data */
 -      if(tmp.totvert != me->totvert) {
 +      CustomData_free(&me->ldata, me->totloop);
 +      CustomData_free(&me->pdata, me->totpoly);
 +
 +      /*  ok, this should now use new CD shapekey data,
 +          which shouuld be fed through the modifier 
 +              stack*/
 +      if(tmp.totvert != me->totvert && !did_shapekeys && me->key) {
 +              printf("YEEK! this should be recoded! Shape key loss!!!\n");
                if(tmp.key) tmp.key->id.us--;
                tmp.key = NULL;
        }
@@@ -475,207 -315,1189 +481,207 @@@ void DM_add_edge_layer(DerivedMesh *dm
        CustomData_add_layer(&dm->edgeData, type, alloctype, layer, dm->numEdgeData);
  }
  
 -void DM_add_face_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
 +void DM_add_tessface_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
  {
        CustomData_add_layer(&dm->faceData, type, alloctype, layer, dm->numFaceData);
  }
  
 -void *DM_get_vert_data(DerivedMesh *dm, int index, int type)
 -{
 -      return CustomData_get(&dm->vertData, index, type);
 -}
 -
 -void *DM_get_edge_data(DerivedMesh *dm, int index, int type)
 -{
 -      return CustomData_get(&dm->edgeData, index, type);
 -}
 -
 -void *DM_get_face_data(DerivedMesh *dm, int index, int type)
 -{
 -      return CustomData_get(&dm->faceData, index, type);
 -}
 -
 -void *DM_get_vert_data_layer(DerivedMesh *dm, int type)
 -{
 -      if(type == CD_MVERT)
 -              return dm->getVertArray(dm);
 -
 -      return CustomData_get_layer(&dm->vertData, type);
 -}
 -
 -void *DM_get_edge_data_layer(DerivedMesh *dm, int type)
 -{
 -      if(type == CD_MEDGE)
 -              return dm->getEdgeArray(dm);
 -
 -      return CustomData_get_layer(&dm->edgeData, type);
 -}
 -
 -void *DM_get_face_data_layer(DerivedMesh *dm, int type)
 -{
 -      if(type == CD_MFACE)
 -              return dm->getFaceArray(dm);
 -
 -      return CustomData_get_layer(&dm->faceData, type);
 -}
 -
 -void DM_set_vert_data(DerivedMesh *dm, int index, int type, void *data)
 -{
 -      CustomData_set(&dm->vertData, index, type, data);
 -}
 -
 -void DM_set_edge_data(DerivedMesh *dm, int index, int type, void *data)
 -{
 -      CustomData_set(&dm->edgeData, index, type, data);
 -}
 -
 -void DM_set_face_data(DerivedMesh *dm, int index, int type, void *data)
 -{
 -      CustomData_set(&dm->faceData, index, type, data);
 -}
 -
 -void DM_copy_vert_data(DerivedMesh *source, DerivedMesh *dest,
 -                                         int source_index, int dest_index, int count)
 -{
 -      CustomData_copy_data(&source->vertData, &dest->vertData,
 -                                               source_index, dest_index, count);
 -}
 -
 -void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest,
 -                                         int source_index, int dest_index, int count)
 -{
 -      CustomData_copy_data(&source->edgeData, &dest->edgeData,
 -                                               source_index, dest_index, count);
 -}
 -
 -void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest,
 -                                         int source_index, int dest_index, int count)
 -{
 -      CustomData_copy_data(&source->faceData, &dest->faceData,
 -                                               source_index, dest_index, count);
 -}
 -
 -void DM_free_vert_data(struct DerivedMesh *dm, int index, int count)
 -{
 -      CustomData_free_elem(&dm->vertData, index, count);
 -}
 -
 -void DM_free_edge_data(struct DerivedMesh *dm, int index, int count)
 -{
 -      CustomData_free_elem(&dm->edgeData, index, count);
 -}
 -
 -void DM_free_face_data(struct DerivedMesh *dm, int index, int count)
 -{
 -      CustomData_free_elem(&dm->faceData, index, count);
 -}
 -
 -void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest,
 -                                               int *src_indices, float *weights,
 -                                               int count, int dest_index)
 -{
 -      CustomData_interp(&source->vertData, &dest->vertData, src_indices,
 -                                        weights, NULL, count, dest_index);
 -}
 -
 -void DM_interp_edge_data(DerivedMesh *source, DerivedMesh *dest,
 -                                               int *src_indices,
 -                                               float *weights, EdgeVertWeight *vert_weights,
 -                                               int count, int dest_index)
 -{
 -      CustomData_interp(&source->edgeData, &dest->edgeData, src_indices,
 -                                        weights, (float*)vert_weights, count, dest_index);
 -}
 -
 -void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
 -                                               int *src_indices,
 -                                               float *weights, FaceVertWeight *vert_weights,
 -                                               int count, int dest_index)
 -{
 -      CustomData_interp(&source->faceData, &dest->faceData, src_indices,
 -                                        weights, (float*)vert_weights, count, dest_index);
 -}
 -
 -void DM_swap_face_data(DerivedMesh *dm, int index, const int *corner_indices)
 -{
 -      CustomData_swap(&dm->faceData, index, corner_indices);
 -}
 -
 -///
 -
 -DerivedMesh *mesh_create_derived(Mesh *me, Object *ob, float (*vertCos)[3])
 -{
 -      DerivedMesh *dm = CDDM_from_mesh(me, ob);
 -      
 -      if(!dm)
 -              return NULL;
 -      
 -      if (vertCos)
 -              CDDM_apply_vert_coords(dm, vertCos);
 -
 -      CDDM_calc_normals(dm);
 -
 -      return dm;
 -}
 -
 -///
 -
 -typedef struct {
 -      DerivedMesh dm;
 -
 -      EditMesh *em;
 -      float (*vertexCos)[3];
 -      float (*vertexNos)[3];
 -      float (*faceNos)[3];
 -} EditMeshDerivedMesh;
 -
 -static void emDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
 -{
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditVert *eve;
 -      int i;
 -
 -      for (i=0,eve= emdm->em->verts.first; eve; i++,eve=eve->next) {
 -              if (emdm->vertexCos) {
 -                      func(userData, i, emdm->vertexCos[i], emdm->vertexNos[i], NULL);
 -              } else {
 -                      func(userData, i, eve->co, eve->no, NULL);
 -              }
 -      }
 -}
 -static void emDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
 -{
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditEdge *eed;
 -      int i;
 -
 -      if (emdm->vertexCos) {
 -              EditVert *eve;
 -
 -              for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
 -                      eve->tmp.l = (intptr_t) i++;
 -              for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next)
 -                      func(userData, i, emdm->vertexCos[(int) eed->v1->tmp.l], emdm->vertexCos[(int) eed->v2->tmp.l]);
 -      } else {
 -              for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next)
 -                      func(userData, i, eed->v1->co, eed->v2->co);
 -      }
 -}
 -static void emDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) 
 -{
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditEdge *eed;
 -      int i;
 -
 -      if (emdm->vertexCos) {
 -              EditVert *eve;
 -
 -              for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
 -                      eve->tmp.l = (intptr_t) i++;
 -
 -              glBegin(GL_LINES);
 -              for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
 -                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 -                              glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]);
 -                              glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]);
 -                      }
 -              }
 -              glEnd();
 -      } else {
 -              glBegin(GL_LINES);
 -              for(i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
 -                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 -                              glVertex3fv(eed->v1->co);
 -                              glVertex3fv(eed->v2->co);
 -                      }
 -              }
 -              glEnd();
 -      }
 -}
 -static void emDM_drawEdges(DerivedMesh *dm, int UNUSED(drawLooseEdges), int UNUSED(drawAllEdges))
 -{
 -      emDM_drawMappedEdges(dm, NULL, NULL);
 -}
 -static void emDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) 
 -{
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditEdge *eed;
 -      int i;
 -
 -      if (emdm->vertexCos) {
 -              EditVert *eve;
 -
 -              for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
 -                      eve->tmp.l = (intptr_t) i++;
 -
 -              glBegin(GL_LINES);
 -              for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
 -                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 -                              setDrawInterpOptions(userData, i, 0.0);
 -                              glVertex3fv(emdm->vertexCos[(int) eed->v1->tmp.l]);
 -                              setDrawInterpOptions(userData, i, 1.0);
 -                              glVertex3fv(emdm->vertexCos[(int) eed->v2->tmp.l]);
 -                      }
 -              }
 -              glEnd();
 -      } else {
 -              glBegin(GL_LINES);
 -              for (i=0,eed= emdm->em->edges.first; eed; i++,eed= eed->next) {
 -                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 -                              setDrawInterpOptions(userData, i, 0.0);
 -                              glVertex3fv(eed->v1->co);
 -                              setDrawInterpOptions(userData, i, 1.0);
 -                              glVertex3fv(eed->v2->co);
 -                      }
 -              }
 -              glEnd();
 -      }
 -}
 -
 -static void emDM_drawUVEdges(DerivedMesh *dm)
 -{
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditFace *efa;
 -      MTFace *tf;
 -
 -      glBegin(GL_LINES);
 -      for(efa= emdm->em->faces.first; efa; efa= efa->next) {
 -              tf = CustomData_em_get(&emdm->em->fdata, efa->data, CD_MTFACE);
 -
 -              if(tf && !(efa->h)) {
 -                      glVertex2fv(tf->uv[0]);
 -                      glVertex2fv(tf->uv[1]);
 -
 -                      glVertex2fv(tf->uv[1]);
 -                      glVertex2fv(tf->uv[2]);
 -
 -                      if (!efa->v4) {
 -                              glVertex2fv(tf->uv[2]);
 -                              glVertex2fv(tf->uv[0]);
 -                      } else {
 -                              glVertex2fv(tf->uv[2]);
 -                              glVertex2fv(tf->uv[3]);
 -                              glVertex2fv(tf->uv[3]);
 -                              glVertex2fv(tf->uv[0]);
 -                      }
 -              }
 -      }
 -      glEnd();
 -}
 -
 -static void emDM__calcFaceCent(EditFace *efa, float cent[3], float (*vertexCos)[3])
 -{
 -      if (vertexCos) {
 -              VECCOPY(cent, vertexCos[(int) efa->v1->tmp.l]);
 -              add_v3_v3(cent, vertexCos[(int) efa->v2->tmp.l]);
 -              add_v3_v3(cent, vertexCos[(int) efa->v3->tmp.l]);
 -              if (efa->v4) add_v3_v3(cent, vertexCos[(int) efa->v4->tmp.l]);
 -      } else {
 -              VECCOPY(cent, efa->v1->co);
 -              add_v3_v3(cent, efa->v2->co);
 -              add_v3_v3(cent, efa->v3->co);
 -              if (efa->v4) add_v3_v3(cent, efa->v4->co);
 -      }
 -
 -      if (efa->v4) {
 -              mul_v3_fl(cent, 0.25f);
 -      } else {
 -              mul_v3_fl(cent, 0.33333333333f);
 -      }
 -}
 -static void emDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
 -{
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditVert *eve;
 -      EditFace *efa;
 -      float cent[3];
 -      int i;
 -
 -      if (emdm->vertexCos) {
 -              for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
 -                      eve->tmp.l = (intptr_t) i++;
 -      }
 -
 -      for(i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
 -              emDM__calcFaceCent(efa, cent, emdm->vertexCos);
 -              func(userData, i, cent, emdm->vertexCos?emdm->faceNos[i]:efa->n);
 -      }
 -}
 -
 -/* note, material function is ignored for now. */
 -static void emDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int UNUSED(useColors), int (*setMaterial)(int, void *attribs),
 -                      int (*compareDrawOptions)(void *userData, int cur_index, int next_index))
 -{
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditFace *efa;
 -      int i, draw;
 -      const int skip_normals= !glIsEnabled(GL_LIGHTING); /* could be passed as an arg */
 -
 -      /* GL_ZERO is used to detect if drawing has started or not */
 -      GLenum poly_prev= GL_ZERO;
 -      GLenum shade_prev= GL_ZERO;
 -
 -      (void)setMaterial; /* unused */
 -
 -      /* currently unused -- each original face is handled separately */
 -      (void)compareDrawOptions;
 -
 -      if (emdm->vertexCos) {
 -              /* add direct access */
 -              float (*vertexCos)[3]= emdm->vertexCos;
 -              float (*vertexNos)[3]= emdm->vertexNos;
 -              float (*faceNos)[3]=   emdm->faceNos;
 -              EditVert *eve;
 -
 -              for (i=0,eve=emdm->em->verts.first; eve; eve= eve->next)
 -                      eve->tmp.l = (intptr_t) i++;
 -
 -              for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
 -                      int drawSmooth = (efa->flag & ME_SMOOTH);
 -                      draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
 -                      if(draw) {
 -                              const GLenum poly_type= efa->v4 ? GL_QUADS:GL_TRIANGLES;
 -                              if (draw==2) { /* enabled with stipple */
 -
 -                                      if(poly_prev != GL_ZERO) glEnd();
 -                                      poly_prev= GL_ZERO; /* force glBegin */
 -
 -                                      glEnable(GL_POLYGON_STIPPLE);
 -                                      glPolygonStipple(stipple_quarttone);
 -                              }
 -                              
 -                              if(skip_normals) {
 -                                      if(poly_type != poly_prev) {
 -                                              if(poly_prev != GL_ZERO) glEnd();
 -                                              glBegin((poly_prev= poly_type));
 -                                      }
 -                                      glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 -                                      glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 -                                      glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 -                                      if(poly_type == GL_QUADS) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 -                              }
 -                              else {
 -                                      const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
 -                                      if (shade_type != shade_prev) {
 -                                              if(poly_prev != GL_ZERO) glEnd();
 -                                              glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
 -                                              glBegin((poly_prev= poly_type));
 -                                      }
 -                                      else if(poly_type != poly_prev) {
 -                                              if(poly_prev != GL_ZERO) glEnd();
 -                                              glBegin((poly_prev= poly_type));
 -                                      }
 -
 -                                      if (!drawSmooth) {
 -                                              glNormal3fv(faceNos[i]);
 -                                              glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 -                                              glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 -                                              glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 -                                              if(poly_type == GL_QUADS) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 -                                      } else {
 -                                              glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
 -                                              glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 -                                              glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
 -                                              glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 -                                              glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
 -                                              glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 -                                              if(poly_type == GL_QUADS) {
 -                                                      glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
 -                                                      glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 -                                              }
 -                                      }
 -                              }
 -
 -                              
 -                              if (draw==2) {
 -                                      glEnd();
 -                                      poly_prev= GL_ZERO; /* force glBegin */
 -
 -                                      glDisable(GL_POLYGON_STIPPLE);
 -                              }
 -                      }
 -              }
 -      }
 -      else {
 -              for (i=0,efa= emdm->em->faces.first; efa; i++,efa= efa->next) {
 -                      int drawSmooth = (efa->flag & ME_SMOOTH);
 -                      draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, i, &drawSmooth);
 -                      if(draw) {
 -                              const GLenum poly_type= efa->v4 ? GL_QUADS:GL_TRIANGLES;
 -                              if (draw==2) { /* enabled with stipple */
 -
 -                                      if(poly_prev != GL_ZERO) glEnd();
 -                                      poly_prev= GL_ZERO; /* force glBegin */
 -
 -                                      glEnable(GL_POLYGON_STIPPLE);
 -                                      glPolygonStipple(stipple_quarttone);
 -                              }
 -
 -                              if(skip_normals) {
 -                                      if(poly_type != poly_prev) {
 -                                              if(poly_prev != GL_ZERO) glEnd();
 -                                              glBegin((poly_prev= poly_type));
 -                                      }
 -                                      glVertex3fv(efa->v1->co);
 -                                      glVertex3fv(efa->v2->co);
 -                                      glVertex3fv(efa->v3->co);
 -                                      if(poly_type == GL_QUADS) glVertex3fv(efa->v4->co);
 -                              }
 -                              else {
 -                                      const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
 -                                      if (shade_type != shade_prev) {
 -                                              if(poly_prev != GL_ZERO) glEnd();
 -                                              glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
 -                                              glBegin((poly_prev= poly_type));
 -                                      }
 -                                      else if(poly_type != poly_prev) {
 -                                              if(poly_prev != GL_ZERO) glEnd();
 -                                              glBegin((poly_prev= poly_type));
 -                                      }
 -
 -                                      if (!drawSmooth) {
 -                                              glNormal3fv(efa->n);
 -                                              glVertex3fv(efa->v1->co);
 -                                              glVertex3fv(efa->v2->co);
 -                                              glVertex3fv(efa->v3->co);
 -                                              if(poly_type == GL_QUADS) glVertex3fv(efa->v4->co);
 -                                      } else {
 -                                              glNormal3fv(efa->v1->no);
 -                                              glVertex3fv(efa->v1->co);
 -                                              glNormal3fv(efa->v2->no);
 -                                              glVertex3fv(efa->v2->co);
 -                                              glNormal3fv(efa->v3->no);
 -                                              glVertex3fv(efa->v3->co);
 -                                              if(poly_type == GL_QUADS) {
 -                                                      glNormal3fv(efa->v4->no);
 -                                                      glVertex3fv(efa->v4->co);
 -                                              }
 -                                      }
 -                              }
 -
 -                              
 -                              if (draw==2) {
 -                                      glEnd();
 -                                      poly_prev= GL_ZERO;
 -
 -                                      glDisable(GL_POLYGON_STIPPLE);
 -                              }
 -                      }
 -              }
 -      }
 -
 -      /* if non zero we know a face was rendered */
 -      if(poly_prev != GL_ZERO) glEnd();
 -}
 -
 -static void emDM_drawFacesTex_common(DerivedMesh *dm,
 -                         int (*drawParams)(MTFace *tface, int has_mcol, int matnr),
 -                         int (*drawParamsMapped)(void *userData, int index),
 -                         void *userData) 
 +static void DM_add_loop_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditMesh *em= emdm->em;
 -      float (*vertexCos)[3]= emdm->vertexCos;
 -      float (*vertexNos)[3]= emdm->vertexNos;
 -      EditFace *efa;
 -      int i;
 -
 -      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 -      glShadeModel(GL_SMOOTH);
 -      
 -      if (vertexCos) {
 -              EditVert *eve;
 -
 -              for (i=0,eve=em->verts.first; eve; eve= eve->next)
 -                      eve->tmp.l = (intptr_t) i++;
 -
 -              for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
 -                      MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -                      MCol *mcol= CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
 -                      unsigned char *cp= NULL;
 -                      int drawSmooth= (efa->flag & ME_SMOOTH);
 -                      int flag;
 -
 -                      if(drawParams)
 -                              flag= drawParams(tf, (mcol != NULL), efa->mat_nr);
 -                      else if(drawParamsMapped)
 -                              flag= drawParamsMapped(userData, i);
 -                      else
 -                              flag= 1;
 -
 -                      if(flag != 0) { /* flag 0 == the face is hidden or invisible */
 -                              
 -                              /* we always want smooth here since otherwise vertex colors dont interpolate */
 -                              if (mcol) {
 -                                      if (flag==1) {
 -                                              cp= (unsigned char*)mcol;
 -                                      }
 -                              } else {
 -                                      glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 -                              } 
 -                              
 -                              glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 -                              if (!drawSmooth) {
 -                                      glNormal3fv(emdm->faceNos[i]);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[0]);
 -                                      if(cp) glColor3ub(cp[3], cp[2], cp[1]);
 -                                      glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[1]);
 -                                      if(cp) glColor3ub(cp[7], cp[6], cp[5]);
 -                                      glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[2]);
 -                                      if(cp) glColor3ub(cp[11], cp[10], cp[9]);
 -                                      glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 -
 -                                      if(efa->v4) {
 -                                              if(tf) glTexCoord2fv(tf->uv[3]);
 -                                              if(cp) glColor3ub(cp[15], cp[14], cp[13]);
 -                                              glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 -                                      }
 -                              } else {
 -                                      if(tf) glTexCoord2fv(tf->uv[0]);
 -                                      if(cp) glColor3ub(cp[3], cp[2], cp[1]);
 -                                      glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
 -                                      glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[1]);
 -                                      if(cp) glColor3ub(cp[7], cp[6], cp[5]);
 -                                      glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
 -                                      glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[2]);
 -                                      if(cp) glColor3ub(cp[11], cp[10], cp[9]);
 -                                      glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
 -                                      glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 -
 -                                      if(efa->v4) {
 -                                              if(tf) glTexCoord2fv(tf->uv[3]);
 -                                              if(cp) glColor3ub(cp[15], cp[14], cp[13]);
 -                                              glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
 -                                              glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 -                                      }
 -                              }
 -                              glEnd();
 -                      }
 -              }
 -      } else {
 -              for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
 -                      MTFace *tf= CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -                      MCol *mcol= CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
 -                      unsigned char *cp= NULL;
 -                      int drawSmooth= (efa->flag & ME_SMOOTH);
 -                      int flag;
 -
 -                      if(drawParams)
 -                              flag= drawParams(tf, (mcol != NULL), efa->mat_nr);
 -                      else if(drawParamsMapped)
 -                              flag= drawParamsMapped(userData, i);
 -                      else
 -                              flag= 1;
 -
 -                      if(flag != 0) { /* flag 0 == the face is hidden or invisible */
 -                              /* we always want smooth here since otherwise vertex colors dont interpolate */
 -                              if (mcol) {
 -                                      if (flag==1) {
 -                                              cp= (unsigned char*)mcol;
 -                                      }
 -                              } else {
 -                                      glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 -                              } 
 -
 -                              glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 -                              if (!drawSmooth) {
 -                                      glNormal3fv(efa->n);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[0]);
 -                                      if(cp) glColor3ub(cp[3], cp[2], cp[1]);
 -                                      glVertex3fv(efa->v1->co);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[1]);
 -                                      if(cp) glColor3ub(cp[7], cp[6], cp[5]);
 -                                      glVertex3fv(efa->v2->co);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[2]);
 -                                      if(cp) glColor3ub(cp[11], cp[10], cp[9]);
 -                                      glVertex3fv(efa->v3->co);
 -
 -                                      if(efa->v4) {
 -                                              if(tf) glTexCoord2fv(tf->uv[3]);
 -                                              if(cp) glColor3ub(cp[15], cp[14], cp[13]);
 -                                              glVertex3fv(efa->v4->co);
 -                                      }
 -                              } else {
 -                                      if(tf) glTexCoord2fv(tf->uv[0]);
 -                                      if(cp) glColor3ub(cp[3], cp[2], cp[1]);
 -                                      glNormal3fv(efa->v1->no);
 -                                      glVertex3fv(efa->v1->co);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[1]);
 -                                      if(cp) glColor3ub(cp[7], cp[6], cp[5]);
 -                                      glNormal3fv(efa->v2->no);
 -                                      glVertex3fv(efa->v2->co);
 -
 -                                      if(tf) glTexCoord2fv(tf->uv[2]);
 -                                      if(cp) glColor3ub(cp[11], cp[10], cp[9]);
 -                                      glNormal3fv(efa->v3->no);
 -                                      glVertex3fv(efa->v3->co);
 -
 -                                      if(efa->v4) {
 -                                              if(tf) glTexCoord2fv(tf->uv[3]);
 -                                              if(cp) glColor3ub(cp[15], cp[14], cp[13]);
 -                                              glNormal3fv(efa->v4->no);
 -                                              glVertex3fv(efa->v4->co);
 -                                      }
 -                              }
 -                              glEnd();
 -                      }
 -              }
 -      }
 +      CustomData_add_layer(&dm->loopData, type, alloctype, layer, dm->numLoopData);
  }
  
 -static void emDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_mcol, int matnr))
 +void DM_add_face_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
  {
 -      emDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
 +      CustomData_add_layer(&dm->polyData, type, alloctype, layer, dm->numPolyData);
  }
  
 -static void emDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
 +void *DM_get_vert_data(DerivedMesh *dm, int index, int type)
  {
 -      emDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 +      return CustomData_get(&dm->vertData, index, type);
  }
  
 -static void emDM_drawMappedFacesGLSL(DerivedMesh *dm,
 -                         int (*setMaterial)(int, void *attribs),
 -                         int (*setDrawOptions)(void *userData, int index), void *userData) 
 +void *DM_get_edge_data(DerivedMesh *dm, int index, int type)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditMesh *em= emdm->em;
 -      float (*vertexCos)[3]= emdm->vertexCos;
 -      float (*vertexNos)[3]= emdm->vertexNos;
 -      EditVert *eve;
 -      EditFace *efa;
 -      DMVertexAttribs attribs= {{{0}}};
 -      GPUVertexAttribs gattribs;
 -      /* int tfoffset; */ /* UNUSED */
 -      int i, b, matnr, new_matnr, dodraw /* , layer */ /* UNUSED */;
 -
 -      dodraw = 0;
 -      matnr = -1;
 -
 -      /* layer = CustomData_get_layer_index(&em->fdata, CD_MTFACE); */ /* UNUSED */
 -      /* tfoffset = (layer == -1)? -1: em->fdata.layers[layer].offset; */ /* UNUSED */
 -
 -      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 -      glShadeModel(GL_SMOOTH);
 -
 -      for (i=0,eve=em->verts.first; eve; eve= eve->next)
 -              eve->tmp.l = (intptr_t) i++;
 -
 -#define PASSATTRIB(efa, eve, vert) {                                                                                  \
 -      if(attribs.totorco) {                                                                                                           \
 -              float *orco = attribs.orco.array[eve->tmp.l];                                                   \
 -              glVertexAttrib3fvARB(attribs.orco.glIndex, orco);                                               \
 -      }                                                                                                                                                       \
 -      for(b = 0; b < attribs.tottface; b++) {                                                                         \
 -              MTFace *_tf = (MTFace*)((char*)efa->data + attribs.tface[b].emOffset);  \
 -              glVertexAttrib2fvARB(attribs.tface[b].glIndex, _tf->uv[vert]);                  \
 -      }                                                                                                                                                       \
 -      for(b = 0; b < attribs.totmcol; b++) {                                                                          \
 -              MCol *cp = (MCol*)((char*)efa->data + attribs.mcol[b].emOffset);                \
 -              GLubyte col[4];                                                                                                                 \
 -              col[0]= cp->b; col[1]= cp->g; col[2]= cp->r; col[3]= cp->a;                             \
 -              glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, col);                                    \
 -      }                                                                                                                                                       \
 -      if(attribs.tottang) {                                                                                                           \
 -              float *tang = attribs.tang.array[i*4 + vert];                                                   \
 -              glVertexAttrib4fvARB(attribs.tang.glIndex, tang);                                               \
 -      }                                                                                                                                                       \
 -}
 -
 -      for (i=0,efa= em->faces.first; efa; i++,efa= efa->next) {
 -              int drawSmooth= (efa->flag & ME_SMOOTH);
 -
 -              if(setDrawOptions && !setDrawOptions(userData, i))
 -                      continue;
 -
 -              new_matnr = efa->mat_nr + 1;
 -              if(new_matnr != matnr) {
 -                      dodraw = setMaterial(matnr = new_matnr, &gattribs);
 -                      if(dodraw)
 -                              DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
 -              }
 -
 -              if(dodraw) {
 -                      glBegin(efa->v4?GL_QUADS:GL_TRIANGLES);
 -                      if (!drawSmooth) {
 -                              if(vertexCos) glNormal3fv(emdm->faceNos[i]);
 -                              else glNormal3fv(efa->n);
 -
 -                              PASSATTRIB(efa, efa->v1, 0);
 -                              if(vertexCos) glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 -                              else glVertex3fv(efa->v1->co);
 -
 -                              PASSATTRIB(efa, efa->v2, 1);
 -                              if(vertexCos) glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 -                              else glVertex3fv(efa->v2->co);
 -
 -                              PASSATTRIB(efa, efa->v3, 2);
 -                              if(vertexCos) glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 -                              else glVertex3fv(efa->v3->co);
 -
 -                              if(efa->v4) {
 -                                      PASSATTRIB(efa, efa->v4, 3);
 -                                      if(vertexCos) glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 -                                      else glVertex3fv(efa->v4->co);
 -                              }
 -                      } else {
 -                              PASSATTRIB(efa, efa->v1, 0);
 -                              if(vertexCos) {
 -                                      glNormal3fv(vertexNos[(int) efa->v1->tmp.l]);
 -                                      glVertex3fv(vertexCos[(int) efa->v1->tmp.l]);
 -                              }
 -                              else {
 -                                      glNormal3fv(efa->v1->no);
 -                                      glVertex3fv(efa->v1->co);
 -                              }
 -
 -                              PASSATTRIB(efa, efa->v2, 1);
 -                              if(vertexCos) {
 -                                      glNormal3fv(vertexNos[(int) efa->v2->tmp.l]);
 -                                      glVertex3fv(vertexCos[(int) efa->v2->tmp.l]);
 -                              }
 -                              else {
 -                                      glNormal3fv(efa->v2->no);
 -                                      glVertex3fv(efa->v2->co);
 -                              }
 -
 -                              PASSATTRIB(efa, efa->v3, 2);
 -                              if(vertexCos) {
 -                                      glNormal3fv(vertexNos[(int) efa->v3->tmp.l]);
 -                                      glVertex3fv(vertexCos[(int) efa->v3->tmp.l]);
 -                              }
 -                              else {
 -                                      glNormal3fv(efa->v3->no);
 -                                      glVertex3fv(efa->v3->co);
 -                              }
 -
 -                              if(efa->v4) {
 -                                      PASSATTRIB(efa, efa->v4, 3);
 -                                      if(vertexCos) {
 -                                              glNormal3fv(vertexNos[(int) efa->v4->tmp.l]);
 -                                              glVertex3fv(vertexCos[(int) efa->v4->tmp.l]);
 -                                      }
 -                                      else {
 -                                              glNormal3fv(efa->v4->no);
 -                                              glVertex3fv(efa->v4->co);
 -                                      }
 -                              }
 -                      }
 -                      glEnd();
 -              }
 -      }
 -#undef PASSATTRIB
 +      return CustomData_get(&dm->edgeData, index, type);
  }
  
 -static void emDM_drawFacesGLSL(DerivedMesh *dm,
 -                         int (*setMaterial)(int, void *attribs))
 +void *DM_get_face_data(DerivedMesh *dm, int index, int type)
  {
 -      dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
 +      return CustomData_get(&dm->faceData, index, type);
  }
  
 -static void emDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
 +void *DM_get_vert_data_layer(DerivedMesh *dm, int type)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditVert *eve;
 -      int i;
 +      if(type == CD_MVERT)
 +              return dm->getVertArray(dm);
  
 -      if (emdm->em->verts.first) {
 -              for (i=0,eve= emdm->em->verts.first; eve; i++,eve= eve->next) {
 -                      if (emdm->vertexCos) {
 -                              DO_MINMAX(emdm->vertexCos[i], min_r, max_r);
 -                      } else {
 -                              DO_MINMAX(eve->co, min_r, max_r);
 -                      }
 -              }
 -      } else {
 -              min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
 -      }
 +      return CustomData_get_layer(&dm->vertData, type);
  }
 -static int emDM_getNumVerts(DerivedMesh *dm)
 +
 +void *DM_get_edge_data_layer(DerivedMesh *dm, int type)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 +      if(type == CD_MEDGE)
 +              return dm->getEdgeArray(dm);
  
 -      return BLI_countlist(&emdm->em->verts);
 +      return CustomData_get_layer(&dm->edgeData, type);
  }
  
 -static int emDM_getNumEdges(DerivedMesh *dm)
 +void *DM_get_tessface_data_layer(DerivedMesh *dm, int type)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 +      if(type == CD_MFACE)
 +              return dm->getTessFaceArray(dm);
  
 -      return BLI_countlist(&emdm->em->edges);
 +      return CustomData_get_layer(&dm->faceData, type);
  }
  
 -static int emDM_getNumFaces(DerivedMesh *dm)
 +void *DM_get_face_data_layer(DerivedMesh *dm, int type)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -
 -      return BLI_countlist(&emdm->em->faces);
 +      return CustomData_get_layer(&dm->polyData, type);
  }
  
 -static void emDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
 +void DM_set_vert_data(DerivedMesh *dm, int index, int type, void *data)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditVert *eve;
 -      int i;
 -
 -      for (i=0,eve= emdm->em->verts.first; eve; i++,eve=eve->next) {
 -              if (emdm->vertexCos) {
 -                      copy_v3_v3(cos_r[i], emdm->vertexCos[i]);
 -              } else {
 -                      copy_v3_v3(cos_r[i], eve->co);
 -              }
 -      }
 +      CustomData_set(&dm->vertData, index, type, data);
  }
  
 -static void emDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
 +void DM_set_edge_data(DerivedMesh *dm, int index, int type, void *data)
  {
 -      EditVert *ev = ((EditMeshDerivedMesh *)dm)->em->verts.first;
 -      int i;
 -
 -      for(i = 0; i < index; ++i) ev = ev->next;
 -
 -      VECCOPY(vert_r->co, ev->co);
 -
 -      normal_float_to_short_v3(vert_r->no, ev->no);
 -
 -      /* TODO what to do with vert_r->flag? */
 -      vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
 +      CustomData_set(&dm->edgeData, index, type, data);
  }
  
 -static void emDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
 +void DM_set_face_data(DerivedMesh *dm, int index, int type, void *data)
  {
 -      EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
 -      EditEdge *ee = em->edges.first;
 -      EditVert *ev, *v1, *v2;
 -      int i;
 -
 -      for(i = 0; i < index; ++i) ee = ee->next;
 -
 -      edge_r->crease = (unsigned char) (ee->crease*255.0f);
 -      edge_r->bweight = (unsigned char) (ee->bweight*255.0f);
 -      /* TODO what to do with edge_r->flag? */
 -      edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
 -      if (ee->seam) edge_r->flag |= ME_SEAM;
 -      if (ee->sharp) edge_r->flag |= ME_SHARP;
 -#if 0
 -      /* this needs setup of f2 field */
 -      if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
 -#endif
 -
 -      /* goddamn, we have to search all verts to find indices */
 -      v1 = ee->v1;
 -      v2 = ee->v2;
 -      for(i = 0, ev = em->verts.first; v1 || v2; i++, ev = ev->next) {
 -              if(ev == v1) {
 -                      edge_r->v1 = i;
 -                      v1 = NULL;
 -              }
 -              if(ev == v2) {
 -                      edge_r->v2 = i;
 -                      v2 = NULL;
 -              }
 -      }
 +      CustomData_set(&dm->faceData, index, type, data);
  }
  
 -static void emDM_getFace(DerivedMesh *dm, int index, MFace *face_r)
 +void DM_copy_vert_data(DerivedMesh *source, DerivedMesh *dest,
 +                                         int source_index, int dest_index, int count)
  {
 -      EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
 -      EditFace *ef = em->faces.first;
 -      EditVert *ev, *v1, *v2, *v3, *v4;
 -      int i;
 -
 -      for(i = 0; i < index; ++i) ef = ef->next;
 -
 -      face_r->mat_nr = ef->mat_nr;
 -      face_r->flag = ef->flag;
 -
 -      /* goddamn, we have to search all verts to find indices */
 -      v1 = ef->v1;
 -      v2 = ef->v2;
 -      v3 = ef->v3;
 -      v4 = ef->v4;
 -      if(!v4) face_r->v4 = 0;
 -
 -      for(i = 0, ev = em->verts.first; v1 || v2 || v3 || v4;
 -              i++, ev = ev->next) {
 -              if(ev == v1) {
 -                      face_r->v1 = i;
 -                      v1 = NULL;
 -              }
 -              if(ev == v2) {
 -                      face_r->v2 = i;
 -                      v2 = NULL;
 -              }
 -              if(ev == v3) {
 -                      face_r->v3 = i;
 -                      v3 = NULL;
 -              }
 -              if(ev == v4) {
 -                      face_r->v4 = i;
 -                      v4 = NULL;
 -              }
 -      }
 -
 -      test_index_face(face_r, NULL, 0, ef->v4?4:3);
 +      CustomData_copy_data(&source->vertData, &dest->vertData,
 +                                               source_index, dest_index, count);
  }
  
 -static void emDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
 +void DM_copy_edge_data(DerivedMesh *source, DerivedMesh *dest,
 +                                         int source_index, int dest_index, int count)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditVert *ev = emdm->em->verts.first;
 -      int i;
 -
 -      for(i=0; ev; ev = ev->next, ++vert_r, ++i) {
 -              if(emdm->vertexCos)
 -                      copy_v3_v3(vert_r->co, emdm->vertexCos[i]);
 -              else
 -                      copy_v3_v3(vert_r->co, ev->co);
 -
 -              normal_float_to_short_v3(vert_r->no, ev->no);
 -
 -              /* TODO what to do with vert_r->flag? */
 -              vert_r->flag = 0;
 -              vert_r->bweight = (unsigned char) (ev->bweight*255.0f);
 -      }
 +      CustomData_copy_data(&source->edgeData, &dest->edgeData,
 +                                               source_index, dest_index, count);
  }
  
 -static void emDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
 +void DM_copy_tessface_data(DerivedMesh *source, DerivedMesh *dest,
 +                                         int source_index, int dest_index, int count)
  {
 -      EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
 -      EditEdge *ee = em->edges.first;
 -      EditVert *ev;
 -      int i;
 -
 -      /* store vertex indices in tmp union */
 -      for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
 -              ev->tmp.l = (intptr_t) i;
 -
 -      for( ; ee; ee = ee->next, ++edge_r) {
 -              edge_r->crease = (unsigned char) (ee->crease*255.0f);
 -              edge_r->bweight = (unsigned char) (ee->bweight*255.0f);
 -              /* TODO what to do with edge_r->flag? */
 -              edge_r->flag = ME_EDGEDRAW|ME_EDGERENDER;
 -              if (ee->seam) edge_r->flag |= ME_SEAM;
 -              if (ee->sharp) edge_r->flag |= ME_SHARP;
 -#if 0
 -              /* this needs setup of f2 field */
 -              if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
 -#endif
 -
 -              edge_r->v1 = (int)ee->v1->tmp.l;
 -              edge_r->v2 = (int)ee->v2->tmp.l;
 -      }
 +      CustomData_copy_data(&source->faceData, &dest->faceData,
 +                                               source_index, dest_index, count);
  }
  
 -static void emDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
 +void DM_copy_loop_data(DerivedMesh *source, DerivedMesh *dest,
 +                       int source_index, int dest_index, int count)
  {
 -      EditMesh *em = ((EditMeshDerivedMesh *)dm)->em;
 -      EditFace *ef = em->faces.first;
 -      EditVert *ev;
 -      int i;
 -
 -      /* store vertexes indices in tmp union */
 -      for(ev = em->verts.first, i = 0; ev; ev = ev->next, ++i)
 -              ev->tmp.l = (intptr_t) i;
 -
 -      for( ; ef; ef = ef->next, ++face_r) {
 -              face_r->mat_nr = ef->mat_nr;
 -              face_r->flag = ef->flag;
 -
 -              face_r->v1 = (int)ef->v1->tmp.l;
 -              face_r->v2 = (int)ef->v2->tmp.l;
 -              face_r->v3 = (int)ef->v3->tmp.l;
 -              if(ef->v4) face_r->v4 = (int)ef->v4->tmp.l;
 -              else face_r->v4 = 0;
 -
 -              test_index_face(face_r, NULL, 0, ef->v4?4:3);
 -      }
 +      CustomData_copy_data(&source->loopData, &dest->loopData,
 +                           source_index, dest_index, count);
  }
  
 -static void *emDM_getFaceDataArray(DerivedMesh *dm, int type)
 +void DM_copy_face_data(DerivedMesh *source, DerivedMesh *dest,
 +                       int source_index, int dest_index, int count)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 -      EditMesh *em= emdm->em;
 -      EditFace *efa;
 -      char *data, *emdata;
 -      void *datalayer;
 -      int index, size;
 -
 -      datalayer = DM_get_face_data_layer(dm, type);
 -      if(datalayer)
 -              return datalayer;
 -
 -      /* layers are store per face for editmesh, we convert to a temporary
 -       * data layer array in the derivedmesh when these are requested */
 -      if(type == CD_MTFACE || type == CD_MCOL) {
 -              index = CustomData_get_layer_index(&em->fdata, type);
 -
 -              if(index != -1) {
 -                      /* int offset = em->fdata.layers[index].offset; */ /* UNUSED */
 -                      size = CustomData_sizeof(type);
 -
 -                      DM_add_face_layer(dm, type, CD_CALLOC, NULL);
 -                      index = CustomData_get_layer_index(&dm->faceData, type);
 -                      dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
 -
 -                      data = datalayer = DM_get_face_data_layer(dm, type);
 -                      for(efa=em->faces.first; efa; efa=efa->next, data+=size) {
 -                              emdata = CustomData_em_get(&em->fdata, efa->data, type);
 -                              memcpy(data, emdata, size);
 -                      }
 -              }
 -      }
 -
 -      return datalayer;
 +      CustomData_copy_data(&source->polyData, &dest->polyData,
 +                           source_index, dest_index, count);
  }
  
 -static void emDM_release(DerivedMesh *dm)
 +void DM_free_vert_data(struct DerivedMesh *dm, int index, int count)
  {
 -      EditMeshDerivedMesh *emdm= (EditMeshDerivedMesh*) dm;
 +      CustomData_free_elem(&dm->vertData, index, count);
 +}
  
 -      if (DM_release(dm)) {
 -              if (emdm->vertexCos) {
 -                      MEM_freeN(emdm->vertexCos);
 -                      MEM_freeN(emdm->vertexNos);
 -                      MEM_freeN(emdm->faceNos);
 -              }
 +void DM_free_edge_data(struct DerivedMesh *dm, int index, int count)
 +{
 +      CustomData_free_elem(&dm->edgeData, index, count);
 +}
  
 -              MEM_freeN(emdm);
 -      }
 +void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count)
 +{
 +      CustomData_free_elem(&dm->faceData, index, count);
  }
  
 -DerivedMesh *editmesh_get_derived(EditMesh *em, float (*vertexCos)[3])
 +void DM_free_loop_data(struct DerivedMesh *dm, int index, int count)
  {
 -      EditMeshDerivedMesh *emdm = MEM_callocN(sizeof(*emdm), "emdm");
 +      CustomData_free_elem(&dm->loopData, index, count);
 +}
  
 -      DM_init(&emdm->dm, DM_TYPE_EDITMESH, BLI_countlist(&em->verts),
 -                                       BLI_countlist(&em->edges), BLI_countlist(&em->faces));
 +void DM_free_face_data(struct DerivedMesh *dm, int index, int count)
 +{
 +      CustomData_free_elem(&dm->polyData, index, count);
 +}
  
 -      emdm->dm.getMinMax = emDM_getMinMax;
 +void DM_interp_vert_data(DerivedMesh *source, DerivedMesh *dest,
 +                                               int *src_indices, float *weights,
 +                                               int count, int dest_index)
 +{
 +      CustomData_interp(&source->vertData, &dest->vertData, src_indices,
 +                                        weights, NULL, count, dest_index);
 +}
  
 -      emdm->dm.getNumVerts = emDM_getNumVerts;
 -      emdm->dm.getNumEdges = emDM_getNumEdges;
 -      emdm->dm.getNumFaces = emDM_getNumFaces;
 +void DM_interp_edge_data(DerivedMesh *source, DerivedMesh *dest,
 +                                               int *src_indices,
 +                                               float *weights, EdgeVertWeight *vert_weights,
 +                                               int count, int dest_index)
 +{
 +      CustomData_interp(&source->edgeData, &dest->edgeData, src_indices,
 +                                        weights, (float*)vert_weights, count, dest_index);
 +}
  
 -      emdm->dm.getVertCos = emDM_getVertCos;
 +void DM_interp_tessface_data(DerivedMesh *source, DerivedMesh *dest,
 +                                               int *src_indices,
 +                                               float *weights, FaceVertWeight *vert_weights,
 +                                               int count, int dest_index)
 +{
 +      CustomData_interp(&source->faceData, &dest->faceData, src_indices,
 +                                        weights, (float*)vert_weights, count, dest_index);
 +}
  
 -      emdm->dm.getVert = emDM_getVert;
 -      emdm->dm.getEdge = emDM_getEdge;
 -      emdm->dm.getFace = emDM_getFace;
 -      emdm->dm.copyVertArray = emDM_copyVertArray;
 -      emdm->dm.copyEdgeArray = emDM_copyEdgeArray;
 -      emdm->dm.copyFaceArray = emDM_copyFaceArray;
 -      emdm->dm.getFaceDataArray = emDM_getFaceDataArray;
 +void DM_swap_tessface_data(DerivedMesh *dm, int index, const int *corner_indices)
 +{
 +      CustomData_swap(&dm->faceData, index, corner_indices);
 +}
  
 -      emdm->dm.foreachMappedVert = emDM_foreachMappedVert;
 -      emdm->dm.foreachMappedEdge = emDM_foreachMappedEdge;
 -      emdm->dm.foreachMappedFaceCenter = emDM_foreachMappedFaceCenter;
 +void DM_interp_loop_data(DerivedMesh *source, DerivedMesh *dest,
 +                         int *src_indices,
 +                         float *weights, int count, int dest_index)
 +{
 +      CustomData_interp(&source->loopData, &dest->loopData, src_indices,
 +                        weights, NULL, count, dest_index);
 +}
  
 -      emdm->dm.drawEdges = emDM_drawEdges;
 -      emdm->dm.drawMappedEdges = emDM_drawMappedEdges;
 -      emdm->dm.drawMappedEdgesInterp = emDM_drawMappedEdgesInterp;
 -      emdm->dm.drawMappedFaces = emDM_drawMappedFaces;
 -      emdm->dm.drawMappedFacesTex = emDM_drawMappedFacesTex;
 -      emdm->dm.drawMappedFacesGLSL = emDM_drawMappedFacesGLSL;
 -      emdm->dm.drawFacesTex = emDM_drawFacesTex;
 -      emdm->dm.drawFacesGLSL = emDM_drawFacesGLSL;
 -      emdm->dm.drawUVEdges = emDM_drawUVEdges;
 +void DM_interp_face_data(DerivedMesh *source, DerivedMesh *dest,
 +                         int *src_indices,
 +                         float *weights, int count, int dest_index)
 +{
 +      CustomData_interp(&source->polyData, &dest->polyData, src_indices,
 +                        weights, NULL, count, dest_index);
 +}
  
 -      emdm->dm.release = emDM_release;
 +///
 +DerivedMesh *mesh_create_derived(Mesh *me, Object *ob, float (*vertCos)[3])
 +{
 +      DerivedMesh *dm = CDDM_from_mesh(me, ob);
        
 -      emdm->em = em;
 -      emdm->vertexCos = vertexCos;
 -
 -      if(CustomData_has_layer(&em->vdata, CD_MDEFORMVERT)) {
 -              EditVert *eve;
 -              int i;
 -
 -              DM_add_vert_layer(&emdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
 -
 -              for(eve = em->verts.first, i = 0; eve; eve = eve->next, ++i)
 -                      DM_set_vert_data(&emdm->dm, i, CD_MDEFORMVERT,
 -                                                       CustomData_em_get(&em->vdata, eve->data, CD_MDEFORMVERT));
 -      }
 -
 -      if(vertexCos) {
 -              EditVert *eve;
 -              EditFace *efa;
 -              int totface = BLI_countlist(&em->faces);
 -              int i;
 -
 -              for (i=0,eve=em->verts.first; eve; eve= eve->next)
 -                      eve->tmp.l = (intptr_t) i++;
 -
 -              emdm->vertexNos = MEM_callocN(sizeof(*emdm->vertexNos)*i, "emdm_vno");
 -              emdm->faceNos = MEM_mallocN(sizeof(*emdm->faceNos)*totface, "emdm_vno");
 -
 -              for(i=0, efa= em->faces.first; efa; i++, efa=efa->next) {
 -                      float *v1 = vertexCos[(int) efa->v1->tmp.l];
 -                      float *v2 = vertexCos[(int) efa->v2->tmp.l];
 -                      float *v3 = vertexCos[(int) efa->v3->tmp.l];
 -                      float *no = emdm->faceNos[i];
 -                      
 -                      if(efa->v4) {
 -                              float *v4 = vertexCos[(int) efa->v4->tmp.l];
 -
 -                              normal_quad_v3( no,v1, v2, v3, v4);
 -                              add_v3_v3(emdm->vertexNos[(int) efa->v4->tmp.l], no);
 -                      }
 -                      else {
 -                              normal_tri_v3( no,v1, v2, v3);
 -                      }
 -
 -                      add_v3_v3(emdm->vertexNos[(int) efa->v1->tmp.l], no);
 -                      add_v3_v3(emdm->vertexNos[(int) efa->v2->tmp.l], no);
 -                      add_v3_v3(emdm->vertexNos[(int) efa->v3->tmp.l], no);
 -              }
 +      if(!dm)
 +              return NULL;
 +      
 +      if (vertCos)
 +              CDDM_apply_vert_coords(dm, vertCos);
  
 -              for(i=0, eve= em->verts.first; eve; i++, eve=eve->next) {
 -                      float *no = emdm->vertexNos[i];
 -                      /* following Mesh convention; we use vertex coordinate itself
 -                       * for normal in this case */
 -                      if (normalize_v3(no) == 0.0f) {
 -                              normalize_v3_v3(no, vertexCos[i]);
 -                      }
 -              }
 -      }
 +      CDDM_calc_normals(dm);
  
 -      return (DerivedMesh*) emdm;
 +      return dm;
  }
  
  /***/
  
 -DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, ModifierData *md)
 +DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob, 
 +      ModifierData *md, int build_shapekey_layers)
  {
        Mesh *me = ob->data;
        ModifierTypeInfo *mti = modifierType_getInfo(md->type);
        
        if (!(md->mode&eModifierMode_Realtime)) return NULL;
        if (mti->isDisabled && mti->isDisabled(md, 0)) return NULL;
 -
 +      
 +      if (build_shapekey_layers && me->key && ob->shapenr <= BLI_countlist(&me->key->block)) {
 +              key_to_mesh(BLI_findlink(&me->key->block, ob->shapenr-1), me);
 +      }
 +      
        if (mti->type==eModifierTypeType_OnlyDeform) {
                int numVerts;
                float (*deformedVerts)[3] = mesh_getVertexCos(me, &numVerts);
                mti->deformVerts(md, ob, NULL, deformedVerts, numVerts, 0, 0);
                dm = mesh_create_derived(me, ob, deformedVerts);
  
 +              if (build_shapekey_layers)
 +                      add_shapekey_layers(dm, me, ob);
 +              
                MEM_freeN(deformedVerts);
        } else {
                DerivedMesh *tdm = mesh_create_derived(me, ob, NULL);
 +
 +              if (build_shapekey_layers)
 +                      add_shapekey_layers(tdm, me, ob);
 +              
                dm = mti->applyModifier(md, ob, tdm, 0, 0);
  
                if(tdm != dm) tdm->release(tdm);
        return dm;
  }
  
 -static float *get_editmesh_orco_verts(EditMesh *em)
 +static float *get_editbmesh_orco_verts(BMEditMesh *em)
  {
 -      EditVert *eve;
 +      BMIter iter;
 +      BMVert *eve;
        float *orco;
        int a, totvert;
  
        /* these may not really be the orco's, but it's only for preview.
         * could be solver better once, but isn't simple */
  
 -      totvert= 0;
 -      for(eve=em->verts.first; eve; eve=eve->next)
 -              totvert++;
 +      totvert= em->bm->totvert;
        
        orco = MEM_mallocN(sizeof(float)*3*totvert, "EditMesh Orco");
  
 -      for(a=0, eve=em->verts.first; eve; eve=eve->next, a+=3)
 +      eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
 +      for (a=0; eve; eve=BMIter_Step(&iter), a+=3)
                VECCOPY(orco+a, eve->co);
        
        return orco;
  }
  
  /* orco custom data layer */
 -
 -static void *get_orco_coords_dm(Object *ob, EditMesh *em, int layer, int *free)
 +static void *get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free)
  {
        *free= 0;
  
                *free= 1;
  
                if(em)
 -                      return (float(*)[3])get_editmesh_orco_verts(em);
 +                      return (float(*)[3])get_editbmesh_orco_verts(em);
                else
                        return (float(*)[3])get_mesh_orco_verts(ob);
        }
                   by a more flexible customdata system, but not simple */
                if(!em) {
                        ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
 -                      KeyBlock *kb= key_get_keyblock(ob_get_key(ob), clmd->sim_parms->shapekey_rest);
 -
 -                      if(kb->data)
 -                              return kb->data;
 +                      if (clmd) {
 +                              KeyBlock *kb= key_get_keyblock(ob_get_key(ob), clmd->sim_parms->shapekey_rest);
 +      
 +                              if(kb->data)
 +                                      return kb->data;
 +                      }
                }
  
                return NULL;
        return NULL;
  }
  
 -static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, EditMesh *em, int layer)
 +static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em, int layer)
  {
        DerivedMesh *dm;
        float (*orco)[3];
        int free;
  
 -      if(em) dm= CDDM_from_editmesh(em, me);
 +      if(em) dm= CDDM_from_BMEditMesh(em, me, 0);
        else dm= CDDM_from_mesh(me, ob);
  
        orco= get_orco_coords_dm(ob, em, layer, &free);
        return dm;
  }
  
 -static void add_orco_dm(Object *ob, EditMesh *em, DerivedMesh *dm, DerivedMesh *orcodm, int layer)
 +static void add_orco_dm(Object *ob, BMEditMesh *em, DerivedMesh *dm,
 +                                              DerivedMesh *orcodm, int layer)
  {
        float (*orco)[3], (*layerorco)[3];
        int totvert, free;
@@@ -938,28 -1747,21 +944,28 @@@ void vDM_ColorBand_store(ColorBand *cob
  
  static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm, int const draw_flag)
  {
 -      Mesh *me = ob->data;
 -      MFace *mf = me->mface;
 +      // Mesh *me = ob->data; // UNUSED
 +      MFace *mf = dm->getTessFaceArray(dm);
 +      MLoop *mloop = dm->getLoopArray(dm), *ml;
 +      MPoly *mp = dm->getPolyArray(dm);
        ColorBand *coba= stored_cb;     /* warning, not a local var */
        unsigned char *wtcol;
 -      int i;
 -      
 +      unsigned char(*wlcol)[4] = NULL;
 +      BLI_array_declare(wlcol);
 +      int i, j, totface=dm->getNumTessFaces(dm), totloop;
 +      int *origIndex = dm->getVertDataArray(dm, CD_ORIGINDEX);
 +
        int defbase_len = BLI_countlist(&ob->defbase);
        char *defbase_sel = MEM_mallocN(defbase_len * sizeof(char), __func__);
        int selected = get_selected_defgroups(ob, defbase_sel, defbase_len);
        int unselected = defbase_len - selected;
  
 -      wtcol = MEM_callocN (sizeof (unsigned char) * me->totface*4*4, "weightmap");
 +      wtcol = MEM_callocN (sizeof (unsigned char) * totface*4*4, "weightmap");
        
 -      memset(wtcol, 0x55, sizeof (unsigned char) * me->totface*4*4);
 -      for (i=0; i<me->totface; i++, mf++) {
 +      /*first add colors to the tesselation faces*/
 +      memset(wtcol, 0x55, sizeof (unsigned char) * totface*4*4);
 +      for (i=0; i<totface; i++, mf++) {
 +              /*origindex being NULL means we're operating on original mesh data*/
                calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4], defbase_sel, selected, unselected, draw_flag);
                calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4], defbase_sel, selected, unselected, draw_flag);
                calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4], defbase_sel, selected, unselected, draw_flag);
                        calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4], defbase_sel, selected, unselected, draw_flag);
        }
        
 +      CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, totface);
 +
 +      /*now add to loops, so the data can be passed through the modifier stack*/
 +      totloop = 0;
 +      for (i=0; i<dm->numPolyData; i++, mp++) {
 +              ml = mloop + mp->loopstart;
 +
 +              for (j=0; j<mp->totloop; j++, ml++, totloop++) {
 +                      BLI_array_growone(wlcol);
 +
 +                      calc_weightpaint_vert_color(ob, coba, origIndex ? origIndex[ml->v] : ml->v,
 +                                                                              (unsigned char *)&wlcol[totloop], defbase_sel, selected, unselected, draw_flag);
 +              }
 +      }
 +
        MEM_freeN(defbase_sel);
  
 -      CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, dm->numFaceData);
 +      CustomData_add_layer(&dm->loopData, CD_WEIGHT_MLOOPCOL, CD_ASSIGN, wlcol, totloop);
 +}
 +
 +
 +static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape_uid)
 +{
 +      KeyBlock *kb;
 +      int i, j, tot;
 +      
 +      if (!me->key)
 +              return; 
 +      
 +      tot = CustomData_number_of_layers(&dm->vertData, CD_SHAPEKEY);
 +      for (i=0; i<tot; i++) {
 +              CustomDataLayer *layer = &dm->vertData.layers[CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, i)];
 +              float (*cos)[3], (*kbcos)[3];
 +              
 +              for (kb=me->key->block.first; kb; kb=kb->next) {
 +                      if (kb->uid == layer->uid)
 +                              break;
 +              }
 +              
 +              if (!kb) {
 +                      kb = add_keyblock(me->key, layer->name);
 +                      kb->uid = layer->uid;
 +              }
 +              
 +              if (kb->data)
 +                      MEM_freeN(kb->data);
 +              
 +              cos = CustomData_get_layer_n(&dm->vertData, CD_SHAPEKEY, i);
 +              kb->totelem = dm->numVertData;
 +
 +              kb->data = kbcos = MEM_mallocN(sizeof(float)*3*kb->totelem, "kbcos DerivedMesh.c");
 +              if (kb->uid == actshape_uid) {
 +                      MVert *mvert = dm->getVertArray(dm);
 +                      
 +                      for (j=0; j<dm->numVertData; j++, kbcos++, mvert++) {
 +                              copy_v3_v3(*kbcos, mvert->co);
 +                      }
 +              } else {
 +                      for (j=0; j<kb->totelem; j++, cos++, kbcos++) {
 +                              copy_v3_v3(*kbcos, *cos);
 +                      }
 +              }
 +      }
 +      
 +      for (kb=me->key->block.first; kb; kb=kb->next) {
 +              if (kb->totelem != dm->numVertData) {
 +                      if (kb->data)
 +                              MEM_freeN(kb->data);
 +                      
 +                      kb->totelem = dm->numVertData;
 +                      kb->data = MEM_callocN(sizeof(float)*3*kb->totelem, "kb->data derivedmesh.c");
 +                      fprintf(stderr, "%s: lost a shapekey layer! (bmesh internal error)\n", __func__);
 +              }
 +      }
 +}
 +
 +static void add_shapekey_layers(DerivedMesh *dm, Mesh *me, Object *UNUSED(ob))
 +{
 +      KeyBlock *kb;
 +      Key *key = me->key;
 +      int a, b;
 +      
 +      if (!me->key)
 +              return;
 +      
 +      if (dm->numVertData != me->totvert) {
 +              printf("error in add_shapekey_layers: dm isn't the same size as me\n");
 +              return;
 +      }
 +              
 +      for (a=0, kb=key->block.first; kb; kb=kb->next, a++) {
 +              float (*cos)[3] = CustomData_add_layer_named(&dm->vertData, CD_SHAPEKEY, CD_CALLOC, NULL, dm->numVertData, kb->name);
 +              int ci = CustomData_get_layer_index_n(&dm->vertData, CD_SHAPEKEY, a);
 +              
 +              dm->vertData.layers[ci].uid = kb->uid;
 +              if (kb->totelem != dm->numVertData) {
 +                      printf("error in add_shapekey_layers: totelem and totvert don't match");
 +                      continue;
 +              }
 +              
 +              for (b=0; b<kb->totelem; b++, cos++) {
 +                      copy_v3_v3((float *)cos, ((float*)kb->data)+b*3);
 +              }
 +      }
  }
  
  /* new value for useDeform -1  (hack for the gameengine):
  static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos)[3],
                                                                DerivedMesh **deform_r, DerivedMesh **final_r,
                                                                int useRenderParams, int useDeform,
 -                                                              int needMapping, CustomDataMask dataMask, int index, int useCache)
 +                                                              int needMapping, CustomDataMask dataMask, 
 +                                                              int index, int useCache, int build_shapekey_layers)
  {
        Mesh *me = ob->data;
        ModifierData *firstmd, *md;
        LinkNode *datamasks, *curr;
        CustomDataMask mask, nextmask;
        float (*deformedVerts)[3] = NULL;
 -      DerivedMesh *dm, *orcodm, *clothorcodm, *finaldm;
 +      DerivedMesh *dm=NULL, *orcodm, *clothorcodm, *finaldm;
        int numVerts = me->totvert;
        int required_mode;
        int isPrevDeform= FALSE;
                 */
                if (deform_r) {
                        *deform_r = CDDM_from_mesh(me, ob);
 -
 +                      
 +                      if (build_shapekey_layers)
 +                              add_shapekey_layers(dm, me, ob);
 +                      
                        if(deformedVerts) {
                                CDDM_apply_vert_coords(*deform_r, deformedVerts);
                                CDDM_calc_normals(*deform_r);
  
                        /* if this is not the last modifier in the stack then recalculate the normals
                         * to avoid giving bogus normals to the next modifier see: [#23673] */
 -                      if(isPrevDeform &&  mti->dependsOnNormals && mti->dependsOnNormals(md)) {
 +                      if(dm && isPrevDeform &&  mti->dependsOnNormals && mti->dependsOnNormals(md)) {
                                /* XXX, this covers bug #23673, but we may need normal calc for other types */
                                if(dm && dm->type == DM_TYPE_CDDM) {
                                        CDDM_apply_vert_coords(dm, deformedVerts);
                        /* apply vertex coordinates or build a DerivedMesh as necessary */
                        if(dm) {
                                if(deformedVerts) {
 -                                      DerivedMesh *tdm = CDDM_copy(dm);
 +                                      DerivedMesh *tdm = CDDM_copy(dm, 0);
                                        dm->release(dm);
                                        dm = tdm;
  
                        } else {
                                dm = CDDM_from_mesh(me, ob);
  
 +                              if (build_shapekey_layers)
 +                                      add_shapekey_layers(dm, me, ob);
 +
                                if(deformedVerts) {
                                        CDDM_apply_vert_coords(dm, deformedVerts);
                                        CDDM_calc_normals(dm);
                                }
  
 -                              if((dataMask & CD_MASK_WEIGHT_MCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT))
 -                                      add_weight_mcol_dm(ob, dm, draw_flag); 
 -
                                /* Constructive modifiers need to have an origindex
                                 * otherwise they wont have anywhere to copy the data from.
                                 *
  
                                        range_vni(DM_get_vert_data_layer(dm, CD_ORIGINDEX), dm->numVertData, 0);
                                        range_vni(DM_get_edge_data_layer(dm, CD_ORIGINDEX), dm->numEdgeData, 0);
 -                                      range_vni(DM_get_face_data_layer(dm, CD_ORIGINDEX), dm->numFaceData, 0);
 +                                      range_vni(DM_get_face_data_layer(dm, CD_ORIGINDEX), dm->numPolyData, 0);
                                }
 +
 +                              if((dataMask & CD_MASK_WEIGHT_MCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT))
 +                                      add_weight_mcol_dm(ob, dm, draw_flag);
 +
                        }
  
                        
                        /* add an origspace layer if needed */
                        if(((CustomDataMask)GET_INT_FROM_POINTER(curr->link)) & CD_MASK_ORIGSPACE)
                                if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE))
 -                                      DM_add_face_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
 +                                      DM_add_tessface_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
  
                        ndm = mti->applyModifier(md, ob, dm, useRenderParams, useCache);
  
         * DerivedMesh then we need to build one.
         */
        if(dm && deformedVerts) {
 -              finaldm = CDDM_copy(dm);
 +              finaldm = CDDM_copy(dm, 0);
  
                dm->release(dm);
  
        } else if(dm) {
                finaldm = dm;
        } else {
 -              finaldm = CDDM_from_mesh(me, ob);
 +              int recalc_normals= 0;
  
 +              finaldm = CDDM_from_mesh(me, ob);
 +              
 +              if(build_shapekey_layers) {
 +                      add_shapekey_layers(finaldm, me, ob);
 +                      recalc_normals= 1;
 +              }
 +              
                if(deformedVerts) {
                        CDDM_apply_vert_coords(finaldm, deformedVerts);
 -                      CDDM_calc_normals(finaldm);
 +                      recalc_normals= 1;
                }
  
 +              if(recalc_normals)
 +                      CDDM_calc_normals(finaldm);
 +              
                if((dataMask & CD_MASK_WEIGHT_MCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT))
                        add_weight_mcol_dm(ob, finaldm, draw_flag);
        }
                        add_orco_dm(ob, NULL, *deform_r, NULL, CD_ORCO);
        }
  
+ #ifdef WITH_GAMEENGINE
+       /* NavMesh - this is a hack but saves having a NavMesh modifier */
+       if ((ob->gameflag & OB_NAVMESH) && (finaldm->type == DM_TYPE_CDDM)) {
+               DerivedMesh *tdm;
+               tdm= navmesh_dm_createNavMeshForVisualization(finaldm);
+               if (finaldm != tdm) {
+                       finaldm->release(finaldm);
+                       finaldm= tdm;
+               }
+       }
+ #endif /* WITH_GAMEENGINE */
        *final_r = finaldm;
  
        if(orcodm)
        BLI_linklist_free(datamasks, NULL);
  }
  
 -float (*editmesh_get_vertex_cos(EditMesh *em, int *numVerts_r))[3]
 +float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *numVerts_r))[3]
  {
 -      int i, numVerts = *numVerts_r = BLI_countlist(&em->verts);
 +      int i, numVerts = *numVerts_r = em->bm->totvert;
        float (*cos)[3];
 -      EditVert *eve;
 +      BMIter iter;
 +      BMVert *eve;
 +
 +      cos = MEM_mallocN(sizeof(float)*3*numVerts, "vertexcos");
  
 -      cos = MEM_mallocN(sizeof(*cos)*numVerts, "vertexcos");
 -      for (i=0,eve=em->verts.first; i<numVerts; i++,eve=eve->next) {
 +      eve = BMIter_New(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; eve; eve=BMIter_Step(&iter), i++) {
                VECCOPY(cos[i], eve->co);
        }
  
        return cos;
  }
  
 -int editmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
 +int editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *dm)
  {
        ModifierTypeInfo *mti = modifierType_getInfo(md->type);
        int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
        return 1;
  }
  
 -static void editmesh_calc_modifiers(Scene *scene, Object *ob, EditMesh *em, DerivedMesh **cage_r,
 +static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, DerivedMesh **cage_r,
                                                                        DerivedMesh **final_r,
                                                                        CustomDataMask dataMask)
  {
        modifiers_clearErrors(ob);
  
        if(cage_r && cageIndex == -1) {
 -              *cage_r = editmesh_get_derived(em, NULL);
 +              *cage_r = getEditDerivedBMesh(em, ob, NULL);
        }
  
        dm = NULL;
  
                md->scene= scene;
                
 -              if(!editmesh_modifier_is_enabled(scene, md, dm))
 +              if(!editbmesh_modifier_is_enabled(scene, md, dm))
                        continue;
  
                /* add an orco layer if needed by this modifier */
                                                MEM_mallocN(sizeof(*deformedVerts) * numVerts, "dfmv");
                                        dm->getVertCos(dm, deformedVerts);
                                } else {
 -                                      deformedVerts = editmesh_get_vertex_cos(em, &numVerts);
 +                                      deformedVerts = editbmesh_get_vertex_cos(em, &numVerts);
                                }
                        }
  
                        /* apply vertex coordinates or build a DerivedMesh as necessary */
                        if(dm) {
                                if(deformedVerts) {
 -                                      DerivedMesh *tdm = CDDM_copy(dm);
 +                                      DerivedMesh *tdm = CDDM_copy(dm, 0);
                                        if(!(cage_r && dm == *cage_r)) dm->release(dm);
                                        dm = tdm;
  
                                } else if(cage_r && dm == *cage_r) {
                                        /* dm may be changed by this modifier, so we need to copy it
                                         */
 -                                      dm = CDDM_copy(dm);
 +                                      dm = CDDM_copy(dm, 0);
                                }
  
                        } else {
 -                              dm = CDDM_from_editmesh(em, ob->data);
 +                              dm = CDDM_from_BMEditMesh(em, ob->data, 0);
  
                                if(deformedVerts) {
                                        CDDM_apply_vert_coords(dm, deformedVerts);
  
                        if(mask & CD_MASK_ORIGSPACE)
                                if(!CustomData_has_layer(&dm->faceData, CD_ORIGSPACE))
 -                                      DM_add_face_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
 +                                      DM_add_tessface_layer(dm, CD_ORIGSPACE, CD_DEFAULT, NULL);
                        
                        if (mti->applyModifierEM)
                                ndm = mti->applyModifierEM(md, ob, em, dm);
  
                if(cage_r && i == cageIndex) {
                        if(dm && deformedVerts) {
 -                              *cage_r = CDDM_copy(dm);
 +                              *cage_r = CDDM_copy(dm, 0);
                                CDDM_apply_vert_coords(*cage_r, deformedVerts);
                        } else if(dm) {
                                *cage_r = dm;
                        } else {
                                *cage_r =
 -                                      editmesh_get_derived(em,
 +                                      getEditDerivedBMesh(em, ob,
                                                deformedVerts ? MEM_dupallocN(deformedVerts) : NULL);
                        }
                }
         * then we need to build one.
         */
        if(dm && deformedVerts) {
 -              *final_r = CDDM_copy(dm);
 +              *final_r = CDDM_copy(dm, 0);
  
                if(!(cage_r && dm == *cage_r)) dm->release(dm);
  
        } else if (!deformedVerts && cage_r && *cage_r) {
                *final_r = *cage_r;
        } else {
 -              *final_r = editmesh_get_derived(em, deformedVerts);
 +              *final_r = getEditDerivedBMesh(em, ob, deformedVerts);
                deformedVerts = NULL;
        }
  
@@@ -1694,11 -2386,10 +1712,11 @@@ static void clear_mesh_caches(Object *o
        }
  }
  
 -static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask)
 +static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
 +      int build_shapekey_layers)
  {
        Object *obact = scene->basact?scene->basact->object:NULL;
 -      int editing = paint_facesel_test(ob) || paint_vertsel_test(ob);/* paint_vertsel_test */
 +      int editing = paint_facesel_test(ob);
        /* weight paint and face select need original indices because of selection buffer drawing */
        int needMapping = (ob==obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT|OB_MODE_VERTEX_PAINT)));
  
  
        mesh_calc_modifiers(scene, ob, NULL, &ob->derivedDeform,
                                                &ob->derivedFinal, 0, 1,
 -                                              needMapping, dataMask, -1, 1);
 +                                              needMapping, dataMask, -1, 1, build_shapekey_layers);
  
        DM_set_object_boundbox (ob, ob->derivedFinal);
  
        ob->lastDataMask = dataMask;
  }
  
 -static void editmesh_build_data(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask)
 +static void editbmesh_build_data(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
  {
        clear_mesh_caches(obedit);
  
                em->derivedCage = NULL;
        }
  
 -      editmesh_calc_modifiers(scene, obedit, em, &em->derivedCage, &em->derivedFinal, dataMask);
 +      editbmesh_calc_modifiers(scene, obedit, em, &em->derivedCage, &em->derivedFinal, dataMask);
        DM_set_object_boundbox (obedit, em->derivedFinal);
  
        em->lastDataMask = dataMask;
        em->derivedCage->needsFree = 0;
  }
  
 -void makeDerivedMesh(Scene *scene, Object *ob, EditMesh *em, CustomDataMask dataMask)
 +void makeDerivedMesh(Scene *scene, Object *ob, BMEditMesh *em,
 +      CustomDataMask dataMask, int build_shapekey_layers)
  {
        if (em) {
 -              editmesh_build_data(scene, ob, em, dataMask);
 +              editbmesh_build_data(scene, ob, em, dataMask);
        } else {
 -              mesh_build_data(scene, ob, dataMask);
 +              mesh_build_data(scene, ob, dataMask, build_shapekey_layers);
        }
  }
  
@@@ -1758,7 -2448,7 +1776,7 @@@ DerivedMesh *mesh_get_derived_final(Sce
         * the data we need, rebuild the derived mesh
         */
        if(!ob->derivedFinal || (dataMask & ob->lastDataMask) != dataMask)
 -              mesh_build_data(scene, ob, dataMask);
 +              mesh_build_data(scene, ob, dataMask, 0);
  
        return ob->derivedFinal;
  }
@@@ -1769,7 -2459,7 +1787,7 @@@ DerivedMesh *mesh_get_derived_deform(Sc
         * the data we need, rebuild the derived mesh
         */
        if(!ob->derivedDeform || (dataMask & ob->lastDataMask) != dataMask)
 -              mesh_build_data(scene, ob, dataMask);
 +              mesh_build_data(scene, ob, dataMask, 0);
  
        return ob->derivedDeform;
  }
@@@ -1778,7 -2468,7 +1796,7 @@@ DerivedMesh *mesh_create_derived_render
  {
        DerivedMesh *final;
        
 -      mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, -1, 0);
 +      mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, -1, 0, 0);
  
        return final;
  }
@@@ -1787,7 -2477,7 +1805,7 @@@ DerivedMesh *mesh_create_derived_index_
  {
        DerivedMesh *final;
        
 -      mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, index, 0);
 +      mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 1, 1, 0, dataMask, index, 0, 0);
  
        return final;
  }
@@@ -1796,7 -2486,7 +1814,7 @@@ DerivedMesh *mesh_create_derived_view(S
  {
        DerivedMesh *final;
  
 -      mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 0, 1, 0, dataMask, -1, 0);
 +      mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 0, 1, 0, dataMask, -1, 0, 0);
  
        return final;
  }
@@@ -1806,7 -2496,7 +1824,7 @@@ DerivedMesh *mesh_create_derived_no_def
  {
        DerivedMesh *final;
        
 -      mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, 0, 0, dataMask, -1, 0);
 +      mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, 0, 0, dataMask, -1, 0, 0);
  
        return final;
  }
@@@ -1816,7 -2506,7 +1834,7 @@@ DerivedMesh *mesh_create_derived_no_vir
  {
        DerivedMesh *final;
        
 -      mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 0, dataMask, -1, 0);
 +      mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 0, dataMask, -1, 0, 0);
  
        return final;
  }
@@@ -1826,7 -2516,7 +1844,7 @@@ DerivedMesh *mesh_create_derived_physic
  {
        DerivedMesh *final;
        
 -      mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 1, dataMask, -1, 0);
 +      mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 0, -1, 1, dataMask, -1, 0, 0);
  
        return final;
  }
@@@ -1837,14 -2527,14 +1855,14 @@@ DerivedMesh *mesh_create_derived_no_def
  {
        DerivedMesh *final;
  
 -      mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 1, 0, 0, dataMask, -1, 0);
 +      mesh_calc_modifiers(scene, ob, vertCos, NULL, &final, 1, 0, 0, dataMask, -1, 0, 0);
  
        return final;
  }
  
  /***/
  
 -DerivedMesh *editmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, EditMesh *em, DerivedMesh **final_r,
 +DerivedMesh *editbmesh_get_derived_cage_and_final(Scene *scene, Object *obedit, BMEditMesh *em, DerivedMesh **final_r,
                                                                                                 CustomDataMask dataMask)
  {
        /* if there's no derived mesh or the last data mask used doesn't include
         */
        if(!em->derivedCage ||
           (em->lastDataMask & dataMask) != dataMask)
 -              editmesh_build_data(scene, obedit, em, dataMask);
 +              editbmesh_build_data(scene, obedit, em, dataMask);
  
        *final_r = em->derivedFinal;
        return em->derivedCage;
  }
  
 -DerivedMesh *editmesh_get_derived_cage(Scene *scene, Object *obedit, EditMesh *em, CustomDataMask dataMask)
 +DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh *em, CustomDataMask dataMask)
  {
        /* if there's no derived mesh or the last data mask used doesn't include
         * the data we need, rebuild the derived mesh
         */
        if(!em->derivedCage ||
           (em->lastDataMask & dataMask) != dataMask)
 -              editmesh_build_data(scene, obedit, em, dataMask);
 +              editbmesh_build_data(scene, obedit, em, dataMask);
  
        return em->derivedCage;
  }
  
 -DerivedMesh *editmesh_get_derived_base(Object *UNUSED(obedit), EditMesh *em)
 +DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em)
  {
 -      return editmesh_get_derived(em, NULL);
 +      return getEditDerivedBMesh(em, obedit, NULL);
  }
  
  
@@@ -1912,7 -2602,7 +1930,7 @@@ float *mesh_get_mapped_verts_nors(Scen
        if(ob->type!=OB_MESH || me->totvert==0)
                return NULL;
        
 -      dm= mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH);
 +      dm= mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH|CD_MASK_ORIGINDEX);
        vertexcosnos= MEM_callocN(6*sizeof(float)*me->totvert, "vertexcosnos map");
        
        if(dm->foreachMappedVert) {
@@@ -2041,15 -2731,15 +2059,15 @@@ void DM_add_tangent_layer(DerivedMesh *
        if(CustomData_get_layer_index(&dm->faceData, CD_TANGENT) != -1)
                return;
  
 -      nors = dm->getFaceDataArray(dm, CD_NORMAL);
 +      nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
  
        /* check we have all the needed layers */
        totvert= dm->getNumVerts(dm);
 -      totface= dm->getNumFaces(dm);
 +      totface= dm->getNumTessFaces(dm);
  
        mvert= dm->getVertArray(dm);
 -      mface= dm->getFaceArray(dm);
 -      mtface= dm->getFaceDataArray(dm, CD_MTFACE);
 +      mface= dm->getTessFaceArray(dm);
 +      mtface= dm->getTessFaceDataArray(dm, CD_MTFACE);
  
        if(!mtface) {
                orco= dm->getVertDataArray(dm, CD_ORCO);
        }
        
        /* create tangent layer */
 -      DM_add_face_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
 -      tangent= DM_get_face_data_layer(dm, CD_TANGENT);
 +      DM_add_tessface_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
 +      tangent= DM_get_tessface_data_layer(dm, CD_TANGENT);
        
        /* allocate some space */
        arena= BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "tangent layer arena");
@@@ -2180,8 -2870,15 +2198,8 @@@ void DM_vertex_attributes_from_gpu(Deri
        memset(attribs, 0, sizeof(DMVertexAttribs));
  
        vdata = &dm->vertData;
 -      fdata = &dm->faceData;
 -
 -      /* ugly hack, editmesh derivedmesh doesn't copy face data, this way we
 -       * can use offsets instead */
 -      if(dm->release == emDM_release)
 -              tfdata = &((EditMeshDerivedMesh*)dm)->em->fdata;
 -      else
 -              tfdata = fdata;
 -
 +      fdata = tfdata = dm->getTessFaceDataLayout(dm);
 +      
        /* add a tangent layer if necessary */
        for(b = 0; b < gattribs->totlayer; b++)
                if(gattribs->layer[b].type == CD_TANGENT)
                                attribs->tface[a].array = tfdata->layers[layer].data;
                                attribs->tface[a].emOffset = tfdata->layers[layer].offset;
                                attribs->tface[a].glIndex = gattribs->layer[b].glindex;
 -                              attribs->tface[a].glTexco = gattribs->layer[b].gltexco;
 -                      }
 +                      } /*else {
 +                              int player;
 +                              CustomData *pdata = dm->getFaceDataLayout(dm);
 +                              
 +                              if(gattribs->layer[b].name[0])
 +                                      player = CustomData_get_named_layer_index(pdata, CD_MTEXPOLY,
 +                                              gattribs->layer[b].name);
 +                              else
 +                                      player = CustomData_get_active_layer_index(pdata, CD_MTEXPOLY);
 +                              
 +                              if (player != -1) {
 +                                      a = attribs->tottface++;
 +      
 +                                      attribs->tface[a].array = NULL;
 +                                      attribs->tface[a].emOffset = pdata->layers[layer].offset;
 +                                      attribs->tface[a].glIndex = gattribs->layer[b].glindex;
 +                                      attribs->tface[a].glTexco = gattribs->layer[b].gltexco;
 +                                      
 +                              }
 +                      }*/
                }
                else if(gattribs->layer[b].type == CD_MCOL) {
                        /* vertex colors */
@@@ -2282,3 -2961,167 +2300,167 @@@ void DM_set_object_boundbox(Object *ob
  
        boundbox_set_from_min_max(ob->bb, min, max);
  }
+ /* --- NAVMESH (begin) --- */
+ #ifdef WITH_GAMEENGINE
+ BM_INLINE int navmesh_bit(int a, int b)
+ {
+       return (a & (1 << b)) >> b;
+ }
+ static void navmesh_intToCol(int i, float* col)
+ {
+       int     r = navmesh_bit(i, 0) + navmesh_bit(i, 3) * 2 + 1;
+       int     g = navmesh_bit(i, 1) + navmesh_bit(i, 4) * 2 + 1;
+       int     b = navmesh_bit(i, 2) + navmesh_bit(i, 5) * 2 + 1;
+       col[0] = 1 - r*63.0f/255.0f;
+       col[1] = 1 - g*63.0f/255.0f;
+       col[2] = 1 - b*63.0f/255.0f;
+ }
+ static void navmesh_drawColored(DerivedMesh *dm)
+ {
+       int a, glmode;
+       MVert *mvert = (MVert *)CustomData_get_layer(&dm->vertData, CD_MVERT);
+       MFace *mface = (MFace *)CustomData_get_layer(&dm->faceData, CD_MFACE);
+       int* polygonIdx = (int*)CustomData_get_layer(&dm->faceData, CD_RECAST);
+       const float BLACK_COLOR[3] = {0.f, 0.f, 0.f};
+       float col[3];
+       if (!polygonIdx)
+               return;
+       /*
+       //UI_ThemeColor(TH_WIRE);
+       glDisable(GL_LIGHTING);
+       glLineWidth(2.0);
+       dm->drawEdges(dm, 0, 1);
+       glLineWidth(1.0);
+       glEnable(GL_LIGHTING);*/
+       glDisable(GL_LIGHTING);
+       if(GPU_buffer_legacy(dm) ) {
+               DEBUG_VBO( "Using legacy code. drawNavMeshColored\n" );
+               //glShadeModel(GL_SMOOTH);
+               glBegin(glmode = GL_QUADS);
+               for(a = 0; a < dm->numFaceData; a++, mface++) {
+                       int new_glmode = mface->v4?GL_QUADS:GL_TRIANGLES;
+                       int polygonIdx = *(int*)CustomData_get(&dm->faceData, a, CD_RECAST);
+                       if (polygonIdx<=0)
+                               memcpy(col, BLACK_COLOR, 3*sizeof(float));
+                       else
+                               navmesh_intToCol(polygonIdx, col);
+                       if(new_glmode != glmode) {
+                               glEnd();
+                               glBegin(glmode = new_glmode);
+                       }
+                       glColor3fv(col);
+                       glVertex3fv(mvert[mface->v1].co);
+                       glVertex3fv(mvert[mface->v2].co);
+                       glVertex3fv(mvert[mface->v3].co);
+                       if(mface->v4) {
+                               glVertex3fv(mvert[mface->v4].co);
+                       }
+               }
+               glEnd();
+       }
+       glEnable(GL_LIGHTING);
+ }
+ static void navmesh_DM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_mcol, int matnr))
+ {
+       (void) setDrawOptions;
+       navmesh_drawColored(dm);
+ }
+ static void navmesh_DM_drawFacesSolid(DerivedMesh *dm,
+                                       float (*partial_redraw_planes)[4],
+                                       int UNUSED(fast), int (*setMaterial)(int, void *attribs))
+ {
+       (void) partial_redraw_planes;
+       (void) setMaterial;
+       //drawFacesSolid_original(dm, partial_redraw_planes, fast, setMaterial);
+       navmesh_drawColored(dm);
+ }
+ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
+ {
+       DerivedMesh *result;
+       int maxFaces = dm->getNumFaces(dm);
+       int *recastData;
+       int vertsPerPoly=0, nverts=0, ndtris=0, npolys=0;
+       float* verts=NULL;
+       unsigned short *dtris=NULL, *dmeshes=NULL, *polys=NULL;
+       int *dtrisToPolysMap=NULL, *dtrisToTrisMap=NULL, *trisToFacesMap=NULL;
+       int res;
+       result = CDDM_copy(dm);
+       if (!CustomData_has_layer(&result->faceData, CD_RECAST)) {
+               int *sourceRecastData = (int*)CustomData_get_layer(&dm->faceData, CD_RECAST);
+               CustomData_add_layer_named(&result->faceData, CD_RECAST, CD_DUPLICATE,
+                       sourceRecastData, maxFaces, "recastData");
+       }
+       recastData = (int*)CustomData_get_layer(&result->faceData, CD_RECAST);
+       /* note: This is not good design! - really should not be doing this */
+       result->drawFacesTex =  navmesh_DM_drawFacesTex;
+       result->drawFacesSolid = navmesh_DM_drawFacesSolid;
+       /* process mesh */
+       res  = buildNavMeshDataByDerivedMesh(dm, &vertsPerPoly, &nverts, &verts, &ndtris, &dtris,
+                                            &npolys, &dmeshes, &polys, &dtrisToPolysMap, &dtrisToTrisMap,
+                                            &trisToFacesMap);
+       if (res) {
+               size_t polyIdx;
+               /* invalidate concave polygon */
+               for (polyIdx=0; polyIdx<(size_t)npolys; polyIdx++) {
+                       unsigned short* poly = &polys[polyIdx*2*vertsPerPoly];
+                       if (!polyIsConvex(poly, vertsPerPoly, verts)) {
+                               /* set negative polygon idx to all faces */
+                               unsigned short *dmesh = &dmeshes[4*polyIdx];
+                               unsigned short tbase = dmesh[2];
+                               unsigned short tnum = dmesh[3];
+                               unsigned short ti;
+                               for (ti=0; ti<tnum; ti++) {
+                                       unsigned short triidx = dtrisToTrisMap[tbase+ti];
+                                       unsigned short faceidx = trisToFacesMap[triidx];
+                                       if (recastData[faceidx] > 0) {
+                                               recastData[faceidx] = -recastData[faceidx];
+                                       }
+                               }
+                       }
+               }
+       }
+       else {
+               printf("Error during creation polygon infos\n");
+       }
+       /* clean up */
+       if (verts!=NULL)
+               MEM_freeN(verts);
+       if (dtris!=NULL)
+               MEM_freeN(dtris);
+       if (dmeshes!=NULL)
+               MEM_freeN(dmeshes);
+       if (polys!=NULL)
+               MEM_freeN(polys);
+       if (dtrisToPolysMap!=NULL)
+               MEM_freeN(dtrisToPolysMap);
+       if (dtrisToTrisMap!=NULL)
+               MEM_freeN(dtrisToTrisMap);
+       if (trisToFacesMap!=NULL)
+               MEM_freeN(trisToFacesMap);
+       return result;
+ }
+ #endif /* WITH_GAMEENGINE */
+ /* --- NAVMESH (end) --- */
index f8dfbd4b7b6c36ed189a1a2025f66dbd1fe18863,0b5fd93958028e0309543aa7bdf58bb37177c359..5fbb87e618c48f5827f04cbef6be78d86a3f3b66
@@@ -1,4 -1,4 +1,4 @@@
 -/*
 + /*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
   
  #include "GL/glew.h"
  
 +#include "BKE_cdderivedmesh.h"
 +#include "BKE_global.h"
 +#include "BKE_mesh.h"
 +#include "BKE_paint.h"
 +#include "BKE_utildefines.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "BLI_editVert.h"
 +#include "BLI_scanfill.h"
 +#include "BLI_math.h"
  #include "BLI_blenlib.h"
  #include "BLI_edgehash.h"
  #include "BLI_editVert.h"
  #include "BLI_math.h"
  #include "BLI_pbvh.h"
 +#include "BLI_array.h"
 +#include "BLI_smallhash.h"
  #include "BLI_utildefines.h"
  
  #include "BKE_cdderivedmesh.h"
@@@ -86,8 -74,6 +86,8 @@@ typedef struct 
        MVert *mvert;
        MEdge *medge;
        MFace *mface;
 +      MLoop *mloop;
 +      MPoly *mpoly;
  
        /* Cached */
        struct PBVH *pbvh;
@@@ -109,16 -95,11 +109,16 @@@ static int cdDM_getNumEdges(DerivedMes
        return dm->numEdgeData;
  }
  
 -static int cdDM_getNumFaces(DerivedMesh *dm)
 +static int cdDM_getNumTessFaces(DerivedMesh *dm)
  {
        return dm->numFaceData;
  }
  
 +static int cdDM_getNumFaces(DerivedMesh *dm)
 +{
 +      return dm->numPolyData;
 +}
 +
  static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
  {
        CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
@@@ -155,18 -136,6 +155,18 @@@ static void cdDM_copyFaceArray(DerivedM
        memcpy(face_r, cddm->mface, sizeof(*face_r) * dm->numFaceData);
  }
  
 +static void cdDM_copyLoopArray(DerivedMesh *dm, MLoop *loop_r)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
 +      memcpy(loop_r, cddm->mloop, sizeof(*loop_r) * dm->numLoopData);
 +}
 +
 +static void cdDM_copyPolyArray(DerivedMesh *dm, MPoly *poly_r)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
 +      memcpy(poly_r, cddm->mpoly, sizeof(*poly_r) * dm->numPolyData);
 +}
 +
  static void cdDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
  {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@@ -236,7 -205,7 +236,7 @@@ static int can_pbvh_draw(Object *ob, De
        if(deformed)
                return 0;
  
 -      return (cddm->mvert == me->mvert) || ob->sculpt->kb;
 +      return cddm->mvert == me->mvert || ob->sculpt->kb;
  }
  
  static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
@@@ -325,7 -294,7 +325,7 @@@ static void cdDM_drawUVEdges(DerivedMes
  {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MFace *mf = cddm->mface;
 -      MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
 +      MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
        int i;
  
        if(mf) {
@@@ -496,7 -465,7 +496,7 @@@ static void cdDM_drawFacesSolid(Derived
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mvert = cddm->mvert;
        MFace *mface = cddm->mface;
 -      float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
 +      float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
        int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
  
  #define PASSVERT(index) {                                             \
@@@ -684,15 -653,15 +684,15 @@@ static void cdDM_drawFacesTex_common(De
  {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mv = cddm->mvert;
 -      MFace *mf = DM_get_face_data_layer(dm, CD_MFACE);
 -      MCol *realcol = dm->getFaceDataArray(dm, CD_TEXTURE_MCOL);
 -      float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
 -      MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
 -      int i, j, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
 +      MFace *mf = DM_get_tessface_data_layer(dm, CD_MFACE);
 +      MCol *realcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL);
 +      float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
 +      MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
 +      int i, j, orig, *index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
        int startFace = 0, lastFlag = 0xdeadbeef;
 -      MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
 +      MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
        if(!mcol)
 -              mcol = dm->getFaceDataArray(dm, CD_MCOL);
 +              mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
  
        cdDM_update_normals_from_pbvh(dm);
  
                        }
                        
                        if( col != 0 ) {*/
 -                              unsigned char *colors = MEM_mallocN(dm->getNumFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
 -                              for( i=0; i < dm->getNumFaces(dm); i++ ) {
 +                              unsigned char *colors = MEM_mallocN(dm->getNumTessFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
 +                              for( i=0; i < dm->getNumTessFaces(dm); i++ ) {
                                        for( j=0; j < 4; j++ ) {
-                                               colors[i*12+j*3] = col[i*4+j].r;
+                                               /* bgr -> rgb is intentional (and stupid), but how its stored internally */
+                                               colors[i*12+j*3] = col[i*4+j].b;
                                                colors[i*12+j*3+1] = col[i*4+j].g;
-                                               colors[i*12+j*3+2] = col[i*4+j].b;
+                                               colors[i*12+j*3+2] = col[i*4+j].r;
                                        }
                                }
                                GPU_color3_upload(dm,colors);
@@@ -878,14 -848,14 +879,14 @@@ static void cdDM_drawMappedFaces(Derive
        MVert *mv = cddm->mvert;
        MFace *mf = cddm->mface;
        MCol *mc;
 -      float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
 -      int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
 +      float *nors= DM_get_tessface_data_layer(dm, CD_NORMAL);
 +      int i, orig, *index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
  
 -      mc = DM_get_face_data_layer(dm, CD_ID_MCOL);
 +      mc = DM_get_tessface_data_layer(dm, CD_ID_MCOL);
        if(!mc)
 -              mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
 +              mc = DM_get_tessface_data_layer(dm, CD_WEIGHT_MCOL);
        if(!mc)
 -              mc = DM_get_face_data_layer(dm, CD_MCOL);
 +              mc = DM_get_tessface_data_layer(dm, CD_MCOL);
  
        cdDM_update_normals_from_pbvh(dm);
  
                                }
  
                                glEnd();
 -                      }
 +                      } /*else {
 +                              printf("eek in cddm draw mapped faces!\n");
 +                      }*/
                        
                        if (nors) nors += 3;
                }
@@@ -1097,10 -1065,10 +1098,10 @@@ static void cdDM_drawMappedFacesGLSL(De
        DMVertexAttribs attribs;
        MVert *mvert = cddm->mvert;
        MFace *mface = cddm->mface;
 -      /* MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
 -      float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
 +      /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
 +      float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
        int a, b, dodraw, matnr, new_matnr;
 -      int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
 +      int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
  
        cdDM_update_normals_from_pbvh(dm);
  
@@@ -1459,13 -1427,10 +1460,13 @@@ static void cdDM_foreachMappedFaceCente
  {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
        MVert *mv = cddm->mvert;
 -      MFace *mf = cddm->mface;
 -      int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
 +      MPoly *mf = cddm->mpoly;
 +      MLoop *ml = cddm->mloop;
 +      int i, j, orig, *index;
  
 -      for(i = 0; i < dm->numFaceData; i++, mf++) {
 +      index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
 +      mf = cddm->mpoly;
 +      for(i = 0; i < dm->numPolyData; i++, mf++) {
                float cent[3];
                float no[3];
  
                }
                else
                        orig = i;
 +              
 +              ml = &cddm->mloop[mf->loopstart];
 +              cent[0] = cent[1] = cent[2] = 0.0f;
 +              for (j=0; j<mf->totloop; j++, ml++) {
 +                      add_v3_v3v3(cent, cent, mv[ml->v].co);
 +              }
 +              mul_v3_fl(cent, 1.0f / (float)j);
  
 -              VECCOPY(cent, mv[mf->v1].co);
 -              add_v3_v3(cent, mv[mf->v2].co);
 -              add_v3_v3(cent, mv[mf->v3].co);
 -
 -              if (mf->v4) {
 -                      normal_quad_v3( no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
 -                      add_v3_v3(cent, mv[mf->v4].co);
 -                      mul_v3_fl(cent, 0.25f);
 +              ml = &cddm->mloop[mf->loopstart];
 +              if (j > 3) {
 +                      normal_quad_v3(no, mv[ml->v].co, mv[(ml+1)->v].co,
 +                                     mv[(ml+2)->v].co, mv[(ml+3)->v].co);
                } else {
 -                      normal_tri_v3( no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
 -                      mul_v3_fl(cent, 0.33333333333f);
 +                      normal_tri_v3(no, mv[ml->v].co, mv[(ml+1)->v].co, mv[(ml+2)->v].co);
                }
  
                func(userData, orig, cent, no);
        }
 +
 +}
 +
 +static void cdDM_recalcTesselation(DerivedMesh *dm)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +
 +      dm->numFaceData = mesh_recalcTesselation(&dm->faceData, &dm->loopData, 
 +              &dm->polyData, cddm->mvert, dm->numFaceData, dm->numLoopData, 
 +              dm->numPolyData, 1, 0);
 +      
 +      cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
 +}
 +
 +/*ignores original poly origindex layer*/
 +static void cdDM_recalcTesselation2(DerivedMesh *dm)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +
 +      dm->numFaceData = mesh_recalcTesselation(&dm->faceData, &dm->loopData, 
 +              &dm->polyData, cddm->mvert, dm->numFaceData, dm->numLoopData, 
 +              dm->numPolyData, 0, 0);
 +      
 +      cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
 +}
 +
 +void CDDM_recalc_tesselation(DerivedMesh *dm, int orig_use_polyorig)
 +{
 +      if (orig_use_polyorig)
 +              cdDM_recalcTesselation(dm);
 +      else
 +              cdDM_recalcTesselation2(dm);
  }
  
  static void cdDM_free_internal(CDDerivedMesh *cddm)
@@@ -1543,11 -1474,6 +1544,11 @@@ static void cdDM_release(DerivedMesh *d
        }
  }
  
 +int CDDM_Check(DerivedMesh *dm)
 +{
 +      return dm && dm->getMinMax == cdDM_getMinMax;
 +}
 +
  /**************** CDDM interface functions ****************/
  static CDDerivedMesh *cdDM_create(const char *desc)
  {
        dm->getMinMax = cdDM_getMinMax;
  
        dm->getNumVerts = cdDM_getNumVerts;
 -      dm->getNumFaces = cdDM_getNumFaces;
        dm->getNumEdges = cdDM_getNumEdges;
 +      dm->getNumTessFaces = cdDM_getNumTessFaces;
 +      dm->getNumFaces = cdDM_getNumFaces;
  
        dm->getVert = cdDM_getVert;
        dm->getEdge = cdDM_getEdge;
 -      dm->getFace = cdDM_getFace;
 +      dm->getTessFace = cdDM_getFace;
        dm->copyVertArray = cdDM_copyVertArray;
        dm->copyEdgeArray = cdDM_copyEdgeArray;
 -      dm->copyFaceArray = cdDM_copyFaceArray;
 +      dm->copyTessFaceArray = cdDM_copyFaceArray;
 +      dm->copyLoopArray = cdDM_copyLoopArray;
 +      dm->copyPolyArray = cdDM_copyPolyArray;
        dm->getVertData = DM_get_vert_data;
        dm->getEdgeData = DM_get_edge_data;
 -      dm->getFaceData = DM_get_face_data;
 +      dm->getTessFaceData = DM_get_face_data;
        dm->getVertDataArray = DM_get_vert_data_layer;
        dm->getEdgeDataArray = DM_get_edge_data_layer;
 -      dm->getFaceDataArray = DM_get_face_data_layer;
 +      dm->getTessFaceDataArray = DM_get_tessface_data_layer;
 +      
 +      //doesn't work yet for all cases
 +      //dm->recalcTesselation = cdDM_recalcTesselation;
  
        dm->getVertCos = cdDM_getVertCos;
        dm->getVertCo = cdDM_getVertCo;
        return cddm;
  }
  
 -DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
 +DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces, int numLoops, int numPolys)
  {
        CDDerivedMesh *cddm = cdDM_create("CDDM_new dm");
        DerivedMesh *dm = &cddm->dm;
  
 -      DM_init(dm, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
 +      DM_init(dm, DM_TYPE_CDDM, numVerts, numEdges, numFaces, numLoops, numPolys);
  
        CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
 +      CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, numPolys);
  
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
 +      CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
 +      CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
  
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
 +      cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
 +      cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
  
        return dm;
  }
@@@ -1649,8 -1564,7 +1650,8 @@@ DerivedMesh *CDDM_from_mesh(Mesh *mesh
  
        /* this does a referenced copy, with an exception for fluidsim */
  
 -      DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, mesh->totface);
 +      DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, mesh->totface,
 +                  mesh->totloop, mesh->totpoly);
  
        dm->deformedOnly = 1;
  
                                         mesh->totvert);
        CustomData_merge(&mesh->edata, &dm->edgeData, mask, alloctype,
                                         mesh->totedge);
 -      CustomData_merge(&mesh->fdata, &dm->faceData, mask, alloctype,
 +      CustomData_merge(&mesh->fdata, &dm->faceData, mask|CD_MASK_ORIGINDEX, alloctype,
                                         mesh->totface);
 +      CustomData_merge(&mesh->ldata, &dm->loopData, mask, alloctype,
 +                       mesh->totloop);
 +      CustomData_merge(&mesh->pdata, &dm->polyData, mask, alloctype,
 +                       mesh->totpoly);
  
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
 +      cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
 +      cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
  
 +      if (!CustomData_has_layer(&cddm->dm.faceData, CD_ORIGINDEX))
 +              CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
 +
        return dm;
  }
  
 -DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
 +static DerivedMesh *disabled__CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
  {
        DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
 -                                                         BLI_countlist(&em->edges),
 -                                                         BLI_countlist(&em->faces));
 +                                 BLI_countlist(&em->edges),
 +                                 BLI_countlist(&em->faces), 0, 0);
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
        EditVert *eve;
        EditEdge *eed;
                                         CD_CALLOC, dm->numEdgeData); */
        CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
                                         CD_CALLOC, dm->numFaceData);
 +      CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
 +                       CD_CALLOC, dm->numFaceData);
  
        /* set eve->hash to vert index */
        for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i)
                /* CustomData_from_em_block(&em->edata, &dm->edgeData, eed->data, i); */
        }
  
 -      index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
 +      index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
        for(i = 0, efa = em->faces.first; i < dm->numFaceData;
                i++, efa = efa->next, index++) {
                MFace *mf = &mface[i];
@@@ -1789,17 -1692,15 +1790,17 @@@ DerivedMesh *CDDM_from_curve_customDB(O
        MVert *allvert;
        MEdge *alledge;
        MFace *allface;
 -      int totvert, totedge, totface;
 +      MLoop *allloop;
 +      MPoly *allpoly;
 +      int totvert, totedge, totface, totloop, totpoly;
  
        if (nurbs_to_mdata_customdb(ob, dispbase, &allvert, &totvert, &alledge,
 -              &totedge, &allface, &totface) != 0) {
 +              &totedge, &allface, &allloop, &allpoly, &totface, &totloop, &totpoly) != 0) {
                /* Error initializing mdata. This often happens when curve is empty */
 -              return CDDM_new(0, 0, 0);
 +              return CDDM_new(0, 0, 0, 0, 0);
        }
  
 -      dm = CDDM_new(totvert, totedge, totface);
 +      dm = CDDM_new(totvert, totedge, totface, totloop, totpoly);
        dm->deformedOnly = 1;
  
        cddm = (CDDerivedMesh*)dm;
        memcpy(cddm->mvert, allvert, totvert*sizeof(MVert));
        memcpy(cddm->medge, alledge, totedge*sizeof(MEdge));
        memcpy(cddm->mface, allface, totface*sizeof(MFace));
 +      memcpy(cddm->mloop, allloop, totloop*sizeof(MLoop));
 +      memcpy(cddm->mpoly, allpoly, totpoly*sizeof(MPoly));
  
        MEM_freeN(allvert);
        MEM_freeN(alledge);
        MEM_freeN(allface);
 +      MEM_freeN(allloop);
 +      MEM_freeN(allpoly);
 +
 +      return dm;
 +}
 +
 +static void loops_to_customdata_corners(BMesh *bm, CustomData *facedata,
 +                                        int cdindex, BMLoop *l3[3],
 +                                        int numCol, int numTex)
 +{
 +      BMLoop *l;
 +      BMFace *f = l3[0]->f;
 +      MTFace *texface;
 +      MTexPoly *texpoly;
 +      MCol *mcol;
 +      MLoopCol *mloopcol;
 +      MLoopUV *mloopuv;
 +      int i, j, hasWCol = CustomData_has_layer(&bm->ldata, CD_WEIGHT_MLOOPCOL);
 +
 +      for(i=0; i < numTex; i++){
 +              texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
 +              texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
 +              
 +              texface->tpage = texpoly->tpage;
 +              texface->flag = texpoly->flag;
 +              texface->transp = texpoly->transp;
 +              texface->mode = texpoly->mode;
 +              texface->tile = texpoly->tile;
 +              texface->unwrap = texpoly->unwrap;
 +      
 +              for (j=0; j<3; j++) {
 +                      l = l3[j];
 +                      mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
 +                      texface->uv[j][0] = mloopuv->uv[0];
 +                      texface->uv[j][1] = mloopuv->uv[1];
 +              }
 +      }
 +
 +      for(i=0; i < numCol; i++){
 +              mcol = CustomData_get_n(facedata, CD_MCOL, cdindex, i);
 +              
 +              for (j=0; j<3; j++) {
 +                      l = l3[j];
 +                      mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
 +                      mcol[j].r = mloopcol->r;
 +                      mcol[j].g = mloopcol->g;
 +                      mcol[j].b = mloopcol->b;
 +                      mcol[j].a = mloopcol->a;
 +              }
 +      }
 +
 +      if (hasWCol) {
 +              mcol = CustomData_get(facedata, cdindex, CD_WEIGHT_MCOL);
 +
 +              for (j=0; j<3; j++) {
 +                      l = l3[j];
 +                      mloopcol = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_WEIGHT_MLOOPCOL);
 +                      mcol[j].r = mloopcol->r;
 +                      mcol[j].g = mloopcol->g;
 +                      mcol[j].b = mloopcol->b;
 +                      mcol[j].a = mloopcol->a;
 +              }
 +      }
 +}
 +
 +DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *UNUSED(me), int use_mdisps)
 +{
 +      DerivedMesh *dm = CDDM_new(em->bm->totvert, em->bm->totedge, 
 +                             em->tottri, em->bm->totloop, em->bm->totface);
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +      BMesh *bm = em->bm;
 +      BMIter iter, liter;
 +      BMVert *eve;
 +      BMEdge *eed;
 +      BMFace *efa;
 +      MVert *mvert = cddm->mvert;
 +      MEdge *medge = cddm->medge;
 +      MFace *mface = cddm->mface;
 +      MLoop *mloop = cddm->mloop;
 +      MPoly *mpoly = cddm->mpoly;
 +      int numCol = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
 +      int numTex = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
 +      int i, j, *index, add_orig;
 +      int has_crease, has_edge_bweight, has_vert_bweight;
 +      int flag;
 +      
 +      has_edge_bweight = CustomData_has_layer(&em->bm->edata, CD_BWEIGHT);
 +      has_vert_bweight = CustomData_has_layer(&em->bm->vdata, CD_BWEIGHT);
 +      has_crease = CustomData_has_layer(&em->bm->edata, CD_CREASE);
 +      
 +      dm->deformedOnly = 1;
 +      
 +      /*don't add origindex layer if one already exists*/
 +      add_orig = !CustomData_has_layer(&em->bm->pdata, CD_ORIGINDEX);
 +
 +      flag = use_mdisps ? CD_MASK_DERIVEDMESH|CD_MASK_MDISPS : CD_MASK_DERIVEDMESH;
 +      
 +      /*don't process shapekeys, we only feed them through the modifier stack as needed,
 +      e.g. for applying modifiers or the like*/
 +      flag &= ~CD_SHAPEKEY;
 +      CustomData_merge(&em->bm->vdata, &dm->vertData, flag,
 +                       CD_CALLOC, dm->numVertData);
 +      CustomData_merge(&em->bm->edata, &dm->edgeData, flag,
 +                       CD_CALLOC, dm->numEdgeData);
 +      CustomData_merge(&em->bm->ldata, &dm->loopData, flag,
 +                       CD_CALLOC, dm->numLoopData);
 +      CustomData_merge(&em->bm->pdata, &dm->polyData, flag,
 +                       CD_CALLOC, dm->numPolyData);
 +      
 +      /*add tesselation mface layers*/
 +      CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em->tottri);
 +
 +      /* set vert index */
 +      eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +              BM_SetIndex(eve, i);
 +
 +      index = dm->getVertDataArray(dm, CD_ORIGINDEX);
 +
 +      eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; eve; eve=BMIter_Step(&iter), i++, index++) {
 +              MVert *mv = &mvert[i];
 +
 +              VECCOPY(mv->co, eve->co);
 +
 +              BM_SetIndex(eve, i);
 +
 +              mv->no[0] = eve->no[0] * 32767.0;
 +              mv->no[1] = eve->no[1] * 32767.0;
 +              mv->no[2] = eve->no[2] * 32767.0;
 +
 +              mv->flag = BMFlags_To_MEFlags(eve);
 +
 +              if (has_vert_bweight)
 +                      mv->bweight = (unsigned char)(BM_GetCDf(&bm->vdata, eve, CD_BWEIGHT)*255.0f);
 +
 +              if (add_orig) *index = i;
 +
 +              CustomData_from_bmesh_block(&bm->vdata, &dm->vertData, eve->head.data, i);
 +      }
 +
 +      index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
 +      eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
 +      for (i=0; eed; eed=BMIter_Step(&iter), i++, index++) {
 +              MEdge *med = &medge[i];
 +
 +              BM_SetIndex(eed, i);
 +
 +              med->v1 = BM_GetIndex(eed->v1);
 +              med->v2 = BM_GetIndex(eed->v2);
 +
 +              if (has_crease)
 +                      med->crease = (unsigned char)(BM_GetCDf(&bm->edata, eed, CD_CREASE)*255.0f);
 +              if (has_edge_bweight)
 +                      med->bweight = (unsigned char)(BM_GetCDf(&bm->edata, eed, CD_BWEIGHT)*255.0f);
 +              
 +              med->flag = BMFlags_To_MEFlags(eed);
 +
 +              CustomData_from_bmesh_block(&bm->edata, &dm->edgeData, eed->head.data, i);
 +              if (add_orig) *index = i;
 +      }
 +
 +      efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
 +      for (i=0; efa; i++, efa=BMIter_Step(&iter)) {
 +              BM_SetIndex(efa, i);
 +      }
 +
 +      index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
 +      for(i = 0; i < dm->numFaceData; i++, index++) {
 +              MFace *mf = &mface[i];
 +              BMLoop **l = em->looptris[i];
 +              efa = l[0]->f;
 +
 +              mf->v1 = BM_GetIndex(l[0]->v);
 +              mf->v2 = BM_GetIndex(l[1]->v);
 +              mf->v3 = BM_GetIndex(l[2]->v);
 +              mf->v4 = 0;
 +              mf->mat_nr = efa->mat_nr;
 +              mf->flag = BMFlags_To_MEFlags(efa);
 +              
 +              *index = add_orig ? BM_GetIndex(efa) : *(int*)CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_ORIGINDEX);
 +
 +              loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex);
 +              test_index_face(mf, &dm->faceData, i, 3);
 +      }
 +      
 +      index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
 +      j = 0;
 +      efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
 +      for (i=0; efa; i++, efa=BMIter_Step(&iter), index++) {
 +              BMLoop *l;
 +              MPoly *mp = &mpoly[i];
 +
 +              mp->totloop = efa->len;
 +              mp->flag = BMFlags_To_MEFlags(efa);
 +              mp->loopstart = j;
 +              mp->mat_nr = efa->mat_nr;
 +              
 +              BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
 +                      mloop->v = BM_GetIndex(l->v);
 +                      mloop->e = BM_GetIndex(l->e);
 +                      CustomData_from_bmesh_block(&bm->ldata, &dm->loopData, l->head.data, j);
 +
 +                      j++;
 +                      mloop++;
 +              }
 +
 +              CustomData_from_bmesh_block(&bm->pdata, &dm->polyData, efa->head.data, i);
 +
 +              if (add_orig) *index = i;
 +      }
  
        return dm;
  }
  
 -DerivedMesh *CDDM_copy(DerivedMesh *source)
 +DerivedMesh *CDDM_copy(DerivedMesh *source, int faces_from_tessfaces)
  {
        CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
        DerivedMesh *dm = &cddm->dm;
        int numVerts = source->numVertData;
        int numEdges = source->numEdgeData;
        int numFaces = source->numFaceData;
 +      int numLoops = source->numLoopData;
 +      int numPolys = source->numPolyData;
  
        /* ensure these are created if they are made on demand */
        source->getVertDataArray(source, CD_ORIGINDEX);
        source->getEdgeDataArray(source, CD_ORIGINDEX);
 -      source->getFaceDataArray(source, CD_ORIGINDEX);
 +      source->getTessFaceDataArray(source, CD_ORIGINDEX);
  
        /* this initializes dm, and copies all non mvert/medge/mface layers */
 -      DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
 +      DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces,
 +              numLoops, numPolys);
        dm->deformedOnly = source->deformedOnly;
  
        CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
        /* now add mvert/medge/mface layers */
        cddm->mvert = source->dupVertArray(source);
        cddm->medge = source->dupEdgeArray(source);
 -      cddm->mface = source->dupFaceArray(source);
 +      cddm->mface = source->dupTessFaceArray(source);
  
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numFaces);
 +      
 +      if (!faces_from_tessfaces)
 +              DM_DupPolys(source, dm);
 +      else
 +              CDDM_tessfaces_to_faces(dm);
  
 +      cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
 +      cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
 +      
 +      cdDM_recalcTesselation((DerivedMesh *)cddm);
 +      
        return dm;
  }
  
  /* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
   * relationship betwen mesh data this needs to be set by the caller. */
  DerivedMesh *CDDM_from_template(DerivedMesh *source,
 -                                                              int numVerts, int numEdges, int numFaces)
 +                                int numVerts, int numEdges, int numFaces,
 +                                                              int numLoops, int numPolys)
  {
        CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
        DerivedMesh *dm = &cddm->dm;
        /* ensure these are created if they are made on demand */
        source->getVertDataArray(source, CD_ORIGINDEX);
        source->getEdgeDataArray(source, CD_ORIGINDEX);
 -      source->getFaceDataArray(source, CD_ORIGINDEX);
 +      source->getTessFaceDataArray(source, CD_ORIGINDEX);
  
        /* this does a copy of all non mvert/medge/mface layers */
 -      DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
 +      DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces, numLoops, numPolys);
  
        /* now add mvert/medge/mface layers */
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
 +      CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
 +      CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
  
        if(!CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))
                CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
 +      cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
 +      cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
  
        return dm;
  }
@@@ -2145,228 -1815,22 +2146,228 @@@ void CDDM_apply_vert_normals(DerivedMes
  void CDDM_calc_normals(DerivedMesh *dm)
  {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 -      float (*face_nors)[3];
 -
 +      float (*face_nors)[3] = NULL;
 +      
        if(dm->numVertData == 0) return;
  
        /* we don't want to overwrite any referenced layers */
        cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
 +      
 +      /*set tesselation origindex values to map to poly indices, rather then poly
 +        poly origindex values*/
 +      cdDM_recalcTesselation2(dm);
 +      
 +      face_nors = MEM_mallocN(sizeof(float)*3*dm->numFaceData, "face_nors");
 +      
 +      /* calculate face normals */
 +      mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm), 
 +                                        dm->numLoopData, dm->numPolyData, NULL, cddm->mface, dm->numFaceData, 
 +                                        CustomData_get_layer(&dm->faceData, CD_ORIGINDEX), face_nors);
 +      
 +      /*restore tesselation origindex indices to poly origindex indices*/
 +      cdDM_recalcTesselation(dm);
  
 -      /* make a face normal layer if not present */
 -      face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
 -      if(!face_nors)
 -              face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC,
 -                                                                               NULL, dm->numFaceData);
 +      CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN, 
 +              face_nors, dm->numFaceData);
 +}
  
 -      /* calculate face normals */
 -      mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_faces(dm), dm->numFaceData, face_nors);
 +#if 1
 +/*merge verts
 + 
 +  vtargetmap is a table that maps vertices to target vertices.  a value of -1
 +  indicates a vertex is a target, and is to be kept.
 +  
 +  this frees dm, and returns a new one.
 +  
 +  this is a really horribly written function.  ger. - joeedh
 +
 + */
 +DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +      CDDerivedMesh *cddm2 = NULL;
 +      MVert *mv, *mvert = NULL;
 +      BLI_array_declare(mvert);
 +      MEdge *me, *medge = NULL;
 +      BLI_array_declare(medge);
 +      MPoly *mp, *mpoly = NULL;
 +      BLI_array_declare(mpoly);
 +      MLoop *ml, *mloop = NULL;
 +      BLI_array_declare(mloop);
 +      EdgeHash *ehash = BLI_edgehash_new();
 +      int *newv = NULL, *newe = NULL, *newl = NULL;
 +      int *oldv = NULL, *olde = NULL, *oldl = NULL, *oldp = NULL;
 +      BLI_array_declare(oldv); BLI_array_declare(olde); BLI_array_declare(oldl); BLI_array_declare(oldp);
 +      int i, j, c, totloop, totpoly;
 +      
 +      totloop = dm->numLoopData;
 +      totpoly = dm->numPolyData;
 +      
 +      newv = MEM_callocN(sizeof(int)*dm->numVertData, "newv vtable CDDM_merge_verts");
 +      newe = MEM_callocN(sizeof(int)*dm->numEdgeData, "newv etable CDDM_merge_verts");
 +      newl = MEM_callocN(sizeof(int)*totloop, "newv ltable CDDM_merge_verts");
 +      
 +      /*fill newl with destination vertex indices*/
 +      mv = cddm->mvert;
 +      c = 0;
 +      for (i=0; i<dm->numVertData; i++, mv++) {
 +              if (vtargetmap[i] == -1) {
 +                      BLI_array_append(oldv, i);
 +                      newv[i] = c++;
 +                      BLI_array_append(mvert, *mv);
 +              }
 +      }
 +      
 +      /*now link target vertices to destination indices*/
 +      for (i=0; i<dm->numVertData; i++) {
 +              if (vtargetmap[i] != -1) {
 +                      newv[i] = newv[vtargetmap[i]];
 +              }
 +      }
 +      
 +      /*find-replace merged vertices with target vertices*/   
 +      ml = cddm->mloop;
 +      c = 0;
 +      for (i=0; i<totloop; i++, ml++) {
 +              if (ml->v == -1)
 +                      continue;
 +              
 +              if (vtargetmap[ml->v] != -1)
 +                      ml->v = vtargetmap[ml->v];
 +      }
 +      
 +      /*now go through and fix edges and faces*/
 +      me = cddm->medge;
 +      c = 0;
 +      for (i=0; i<dm->numEdgeData; i++, me++) {
 +              int v1, v2;
 +              
 +              if (me->v1 == me->v2) {
 +                      newe[i] = -1;
 +                      continue;
 +              }
 +              
 +              if (vtargetmap[me->v1] != -1)
 +                      v1 = vtargetmap[me->v1];
 +              else
 +                      v1 = me->v1;
 +              
 +              if (vtargetmap[me->v2] != -1)
 +                      v2 = vtargetmap[me->v2];
 +              else
 +                      v2 = me->v2;
 +              
 +              if (BLI_edgehash_haskey(ehash, v1, v2)) {
 +                      newe[i] = GET_INT_FROM_POINTER(BLI_edgehash_lookup(ehash, v1, v2));
 +              } else {
 +                      BLI_array_append(olde, i);
 +                      newe[i] = c;
 +                      BLI_array_append(medge, *me);
 +                      BLI_edgehash_insert(ehash, v1, v2, SET_INT_IN_POINTER(c));
 +                      c++;
 +              }
 +      }
 +      
 +      mp = cddm->mpoly;
 +      for (i=0; i<totpoly; i++, mp++) {
 +              MPoly *mp2;
 +              
 +              ml = cddm->mloop + mp->loopstart;
 +              
 +              c = 0;
 +              for (j=0; j<mp->totloop; j++, ml++) {
 +                      if (ml->v == -1)
 +                              continue;
 +                      
 +                      me = cddm->medge + ml->e;
 +                      if (me->v1 != me->v2) {
 +                              BLI_array_append(oldl, j+mp->loopstart);
 +                              BLI_array_append(mloop, *ml);
 +                              newl[j+mp->loopstart] = BLI_array_count(mloop)-1;
 +                              c++;
 +                      }
 +              }
 +              
 +              if (!c)
 +                      continue;
 +              
 +              mp2 = BLI_array_append(mpoly, *mp);
 +              mp2->totloop = c;
 +              mp2->loopstart = BLI_array_count(mloop) - c;
 +              
 +              BLI_array_append(oldp, i);
 +      }
 +      
 +      /*create new cddm*/     
 +      cddm2 = (CDDerivedMesh*) CDDM_from_template((DerivedMesh*)cddm, BLI_array_count(mvert), BLI_array_count(medge), 0, BLI_array_count(mloop), BLI_array_count(mpoly));
 +      
 +      /*update edge indices and copy customdata*/
 +      me = medge;
 +      for (i=0; i<cddm2->dm.numEdgeData; i++, me++) {
 +              if (newv[me->v1] != -1)
 +                      me->v1 = newv[me->v1];
 +              if (newv[me->v2] != -1)
 +                      me->v2 = newv[me->v2];
 +              
 +              CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
 +      }
 +      
 +      /*update loop indices and copy customdata*/
 +      ml = mloop;
 +      for (i=0; i<cddm2->dm.numLoopData; i++, ml++) {
 +              if (newe[ml->e] != -1)
 +                      ml->e = newe[ml->e];
 +              if (newv[ml->v] != -1)
 +                      ml->v = newv[ml->v];
 +                      
 +              CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
 +      }
 +      
 +      /*copy vertex customdata*/      
 +      mv = mvert;
 +      for (i=0; i<cddm2->dm.numVertData; i++, mv++) {
 +              CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1);
 +      }
 +      
 +      /*copy poly customdata*/
 +      mp = mpoly;
 +      for (i=0; i<cddm2->dm.numPolyData; i++, mp++) {
 +              CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1);
 +      }
 +      
 +      /*copy over data.  CustomData_add_layer can do this, need to look it up.*/
 +      memcpy(cddm2->mvert, mvert, sizeof(MVert)*BLI_array_count(mvert));
 +      memcpy(cddm2->medge, medge, sizeof(MEdge)*BLI_array_count(medge));
 +      memcpy(cddm2->mloop, mloop, sizeof(MLoop)*BLI_array_count(mloop));
 +      memcpy(cddm2->mpoly, mpoly, sizeof(MPoly)*BLI_array_count(mpoly));
 +      BLI_array_free(mvert); BLI_array_free(medge); BLI_array_free(mloop); BLI_array_free(mpoly);
 +
 +      CDDM_recalc_tesselation((DerivedMesh*)cddm2, 1);
 +      
 +      if (newv) 
 +              MEM_freeN(newv); 
 +      if (newe)
 +              MEM_freeN(newe); 
 +      if (newl)
 +              MEM_freeN(newl);
 +      if (oldv) 
 +              MEM_freeN(oldv); 
 +      if (olde) 
 +              MEM_freeN(olde); 
 +      if (oldl) 
 +              MEM_freeN(oldl); 
 +      if (oldp) 
 +              MEM_freeN(oldp);
 +      if (ehash)
 +              BLI_edgehash_free(ehash, NULL);
 +
 +      /*free old derivedmesh*/
 +      dm->needsFree = 1;
 +      dm->release(dm);
 +      
 +      return (DerivedMesh*)cddm2;
  }
 +#endif
  
  void CDDM_calc_edges(DerivedMesh *dm)
  {
        BLI_edgehash_free(eh, NULL);
  }
  
 +
 +void CDDM_calc_edges_poly(DerivedMesh *dm)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +      CustomData edgeData;
 +      EdgeHashIterator *ehi;
 +      MPoly *mp = cddm->mpoly;
 +      MLoop *ml;
 +      MEdge *med;
 +      EdgeHash *eh = BLI_edgehash_new();
 +      int v1, v2;
 +      int *eindex;
 +      int i, j, k, *index, numEdges = cddm->dm.numEdgeData, maxFaces = dm->numPolyData;
 +
 +      eindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
 +
 +      med = cddm->medge;
 +      if (med) {
 +              for (i=0; i < numEdges; i++, med++) {
 +                      BLI_edgehash_insert(eh, med->v1, med->v2, SET_INT_IN_POINTER(i+1));
 +              }
 +      }
 +
 +      for (i=0; i < maxFaces; i++, mp++) {
 +              ml = cddm->mloop + mp->loopstart;
 +              for (j=0; j<mp->totloop; j++, ml++) {
 +                      v1 = ml->v;
 +                      v2 = (cddm->mloop + mp->loopstart + ((j+1)%mp->totloop))->v;
 +                      if (!BLI_edgehash_haskey(eh, v1, v2)) {
 +                              BLI_edgehash_insert(eh, v1, v2, NULL);
 +                      }
 +              }
 +      }
 +
 +      k = numEdges;
 +      numEdges = BLI_edgehash_size(eh);
 +
 +      /* write new edges into a temporary CustomData */
 +      memset(&edgeData, 0, sizeof(edgeData));
 +      CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
 +      CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
 +
 +      ehi = BLI_edgehashIterator_new(eh);
 +      med = CustomData_get_layer(&edgeData, CD_MEDGE);
 +      index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
 +      for(i = 0; !BLI_edgehashIterator_isDone(ehi);
 +          BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) {
 +              BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
 +              j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
 +
 +              med->flag = ME_EDGEDRAW|ME_EDGERENDER;
 +              *index = j==0 ? ORIGINDEX_NONE : eindex[j-1];
 +
 +              BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(i));
 +      }
 +      BLI_edgehashIterator_free(ehi);
 +
 +      /* free old CustomData and assign new one */
 +      CustomData_free(&dm->edgeData, dm->numEdgeData);
 +      dm->edgeData = edgeData;
 +      dm->numEdgeData = numEdges;
 +
 +      cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
 +
 +      mp = cddm->mpoly;
 +      for (i=0; i < maxFaces; i++, mp++) {
 +              ml = cddm->mloop + mp->loopstart;
 +              for (j=0; j<mp->totloop; j++, ml++) {
 +                      v1 = ml->v;
 +                      v2 = (cddm->mloop + mp->loopstart + ((j+1)%mp->totloop))->v;
 +                      ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, v1, v2));
 +              }
 +      }
 +
 +      BLI_edgehash_free(eh, NULL);
 +}
 +
  void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts)
  {
        if (numVerts < dm->numVertData)
@@@ -2535,7 -1922,7 +2536,7 @@@ MEdge *CDDM_get_edge(DerivedMesh *dm, i
        return &((CDDerivedMesh*)dm)->medge[index];
  }
  
 -MFace *CDDM_get_face(DerivedMesh *dm, int index)
 +MFace *CDDM_get_tessface(DerivedMesh *dm, int index)
  {
        return &((CDDerivedMesh*)dm)->mface[index];
  }
@@@ -2550,125 -1937,8 +2551,125 @@@ MEdge *CDDM_get_edges(DerivedMesh *dm
        return ((CDDerivedMesh*)dm)->medge;
  }
  
 -MFace *CDDM_get_faces(DerivedMesh *dm)
 +MFace *CDDM_get_tessfaces(DerivedMesh *dm)
  {
        return ((CDDerivedMesh*)dm)->mface;
  }
  
 +MLoop *CDDM_get_loops(DerivedMesh *dm)
 +{
 +      return ((CDDerivedMesh*)dm)->mloop;
 +}
 +
 +MPoly *CDDM_get_polys(DerivedMesh *dm)
 +{
 +      return ((CDDerivedMesh*)dm)->mpoly;
 +}
 +
 +void CDDM_tessfaces_to_faces(DerivedMesh *dm)
 +{
 +      /*converts mfaces to mpolys/mloops*/
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +      MFace *mf;
 +      MEdge *me;
 +      MLoop *ml;
 +      MPoly *mp;
 +      EdgeHash *eh = BLI_edgehash_new();
 +      int i, l, totloop, *index1, *index2;
 +      
 +      /*ensure we have all the edges we need*/
 +      CDDM_calc_edges(dm);
 +
 +      /*build edge hash*/
 +      me = cddm->medge;
 +      for (i=0; i<cddm->dm.numEdgeData; i++, me++) {
 +              BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
 +      }
 +
 +      mf = cddm->mface;
 +      totloop = 0;
 +      for (i=0; i<cddm->dm.numFaceData; i++, mf++) {
 +              totloop += mf->v4 ? 4 : 3;
 +      }
 +
 +      CustomData_free(&cddm->dm.polyData, cddm->dm.numPolyData);
 +      CustomData_free(&cddm->dm.loopData, cddm->dm.numLoopData);
 +      
 +      cddm->dm.numLoopData = totloop;
 +      cddm->dm.numPolyData = cddm->dm.numFaceData;
 +
 +      if (!totloop) return;
 +
 +      cddm->mloop = MEM_callocN(sizeof(MLoop)*totloop, "cddm->mloop in CDDM_tessfaces_to_faces");
 +      cddm->mpoly = MEM_callocN(sizeof(MPoly)*cddm->dm.numFaceData, "cddm->mpoly in CDDM_tessfaces_to_faces");
 +      
 +      CustomData_add_layer(&cddm->dm.loopData, CD_MLOOP, CD_ASSIGN, cddm->mloop, totloop);
 +      CustomData_add_layer(&cddm->dm.polyData, CD_MPOLY, CD_ASSIGN, cddm->mpoly, cddm->dm.numPolyData);
 +      CustomData_merge(&cddm->dm.faceData, &cddm->dm.polyData, 
 +              CD_MASK_ORIGINDEX, CD_DUPLICATE, cddm->dm.numFaceData);
 +
 +      index1 = CustomData_get_layer(&cddm->dm.faceData, CD_ORIGINDEX);
 +      index2 = CustomData_get_layer(&cddm->dm.polyData, CD_ORIGINDEX);
 +
 +      mf = cddm->mface;
 +      mp = cddm->mpoly;
 +      ml = cddm->mloop;
 +      l = 0;
 +      for (i=0; i<cddm->dm.numFaceData; i++, mf++, mp++) {
 +              mp->flag = mf->flag;
 +              mp->loopstart = l;
 +              mp->mat_nr = mf->mat_nr;
 +              mp->totloop = mf->v4 ? 4 : 3;
 +              
 +              ml->v = mf->v1;
 +              ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2));
 +              ml++, l++;
 +
 +              ml->v = mf->v2;
 +              ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v2, mf->v3));
 +              ml++, l++;
 +
 +              ml->v = mf->v3;
 +              ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v3, mf->v4?mf->v4:mf->v1));
 +              ml++, l++;
 +
 +              if (mf->v4) {
 +                      ml->v = mf->v4;
 +                      ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v4, mf->v1));
 +                      ml++, l++;
 +              }
 +
 +      }
 +
 +      BLI_edgehash_free(eh, NULL);
 +}
 +
 +void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +      
 +      if (!CustomData_has_layer(&dm->vertData, CD_MVERT))
 +              CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, mvert, dm->numVertData);
 +                              
 +      cddm->mvert = mvert;
 +}
 +
 +void CDDM_set_medge(DerivedMesh *dm, MEdge *medge)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +
 +      if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE))
 +              CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, medge, dm->numEdgeData);
 +
 +      cddm->medge = medge;
 +}
 +
 +void CDDM_set_mface(DerivedMesh *dm, MFace *mface)
 +{
 +      CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
 +
 +      if (!CustomData_has_layer(&dm->faceData, CD_MFACE))
 +              CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, mface, dm->numFaceData);
 +
 +      cddm->mface = mface;
 +}
index 1b9116a75338811a4cf30ad471ef104133ffff08,0000000000000000000000000000000000000000..acc58b1899ed5690ddd9fd620c79ae998bb98264
mode 100644,000000..100644
--- /dev/null
@@@ -1,1635 -1,0 +1,1639 @@@
-                                               glShadeModel((shade_prev= shade_type));
 +/**
 + * $Id: editderivedbmesh.c 18571 2009-01-19 06:04:57Z joeedh $
 + *
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Tbmple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2005 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): none yet.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +#include <string.h>
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "PIL_time.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_effect_types.h"
 +#include "DNA_mesh_types.h"
 +#include "DNA_key_types.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_modifier_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_object_force.h"
 +#include "DNA_object_fluidsim.h" // N_T
 +#include "DNA_scene_types.h" // N_T
 +#include "DNA_texture_types.h"
 +#include "DNA_view3d_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_space_types.h"
 +#include "DNA_particle_types.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_math.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_editVert.h"
 +#include "BLI_edgehash.h"
 +#include "BLI_linklist.h"
 +#include "BLI_memarena.h"
 +#include "BLI_scanfill.h"
 +#include "BLI_ghash.h"
 +#include "BLI_array.h"
 +
 +#include "BKE_cdderivedmesh.h"
 +#include "BKE_customdata.h"
 +#include "BKE_DerivedMesh.h"
 +#include "BKE_deform.h"
 +#include "BKE_displist.h"
 +#include "BKE_effect.h"
 +#include "BKE_fluidsim.h"
 +#include "BKE_global.h"
 +#include "BKE_key.h"
 +#include "BKE_material.h"
 +#include "BKE_modifier.h"
 +#include "BKE_mesh.h"
 +#include "BKE_object.h"
 +#include "BKE_subsurf.h"
 +#include "BKE_texture.h"
 +#include "BKE_particle.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "BLO_sys_types.h" // for intptr_t support
 +
 +#include "GL/glew.h"
 +
 +#include "GPU_draw.h"
 +#include "GPU_extensions.h"
 +#include "GPU_material.h"
 +
 +#include "bmesh.h"
 +
 +extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
 +
 +
 +BMEditMesh *BMEdit_Create(BMesh *bm)
 +{
 +      BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), __func__);
 +      
 +      tm->bm = bm;
 +
 +      BMEdit_RecalcTesselation(tm);
 +
 +      return tm;
 +}
 +
 +BMEditMesh *BMEdit_Copy(BMEditMesh *tm)
 +{
 +      BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), __func__);
 +      *tm2 = *tm;
 +      
 +      tm2->derivedCage = tm2->derivedFinal = NULL;
 +
 +      tm2->bm = BM_Copy_Mesh(tm->bm);
 +
 +      /*The tesselation is NOT calculated on the copy here,
 +        because currently all the callers of this function use
 +        it to make a backup copy of the BMEditMesh to restore
 +        it in the case of errors in an operation. For perf
 +        reasons, in that case it makes more sense to do the
 +        tesselation only when/if that copy ends up getting
 +        used.*/
 +      tm2->looptris = NULL;
 +
 +      tm2->vert_index = NULL;
 +      tm2->edge_index = NULL;
 +      tm2->face_index = NULL;
 +
 +      return tm2;
 +}
 +
 +static void BMEdit_RecalcTesselation_intern(BMEditMesh *tm)
 +{
 +      BMesh *bm = tm->bm;
 +      BMLoop **looptris = NULL;
 +      BLI_array_declare(looptris);
 +      BMIter iter, liter;
 +      BMFace *f;
 +      BMLoop *l;
 +      int i = 0, j;
 +      
 +      if (tm->looptris) MEM_freeN(tm->looptris);
 +
 +      f = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
 +      for ( ; f; f=BMIter_Step(&iter)) {
 +              EditVert *v, *lastv=NULL, *firstv=NULL;
 +              EditEdge *e;
 +              EditFace *efa;
 +
 +              /*don't consider two-edged faces*/
 +              if (f->len < 3) continue;
 +              
 +              BLI_begin_edgefill();
 +              /*scanfill time*/
 +              l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +              for (j=0; l; l=BMIter_Step(&liter), j++) {
 +                      /*mark order*/
 +                      l->_index = j;
 +
 +                      v = BLI_addfillvert(l->v->co);
 +                      v->tmp.p = l;
 +                      
 +                      if (lastv) {
 +                              e = BLI_addfilledge(lastv, v);
 +                      }
 +
 +                      lastv = v;
 +                      if (firstv==NULL) firstv = v;
 +              }
 +
 +              /*complete the loop*/
 +              BLI_addfilledge(firstv, v);
 +
 +              BLI_edgefill(2);
 +              
 +              for (efa = fillfacebase.first; efa; efa=efa->next) {
 +                      BMLoop *l1, *l2, *l3;
 +
 +                      BLI_array_growone(looptris);
 +                      BLI_array_growone(looptris);
 +                      BLI_array_growone(looptris);
 +                      
 +                      looptris[i*3] = l1 = efa->v1->tmp.p;
 +                      looptris[i*3+1] = l2 = efa->v2->tmp.p;
 +                      looptris[i*3+2] = l3 = efa->v3->tmp.p;
 +                      
 +                      if (l1->_index > l2->_index) {
 +                              SWAP(BMLoop*, l1, l2);
 +                      }
 +                      if (l2->_index > l3->_index) {
 +                              SWAP(BMLoop*, l2, l3);
 +                      }
 +                      if (l1->_index > l2->_index) {
 +                              SWAP(BMLoop*, l1, l2);
 +                      }
 +                      
 +                      looptris[i*3] = l1;
 +                      looptris[i*3+1] = l2;
 +                      looptris[i*3+2] = l3;
 +
 +                      i += 1;
 +              }
 +
 +              BLI_end_edgefill();
 +      }
 +
 +      tm->tottri = i;
 +      tm->looptris = (BMLoop *(*)[3])looptris;
 +}
 +
 +void BMEdit_RecalcTesselation(BMEditMesh *em)
 +{
 +      BMEdit_RecalcTesselation_intern(em);
 +
 +      if (em->derivedFinal && em->derivedFinal == em->derivedCage) {
 +              if (em->derivedFinal->recalcTesselation) 
 +                      em->derivedFinal->recalcTesselation(em->derivedFinal);
 +      } else if (em->derivedFinal) {
 +              if (em->derivedCage->recalcTesselation) 
 +                      em->derivedCage->recalcTesselation(em->derivedCage);
 +              if (em->derivedFinal->recalcTesselation) 
 +                      em->derivedFinal->recalcTesselation(em->derivedFinal);
 +      }
 +}
 +
 +void BMEdit_UpdateLinkedCustomData(BMEditMesh *em)
 +{
 +      BMesh *bm = em->bm;
 +      int act;
 +
 +      if (CustomData_has_layer(&bm->pdata, CD_MTEXPOLY)) {
 +              act = CustomData_get_active_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_active(&bm->ldata, CD_MLOOPUV, act);
 +
 +              act = CustomData_get_render_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_render(&bm->ldata, CD_MLOOPUV, act);
 +
 +              act = CustomData_get_clone_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_clone(&bm->ldata, CD_MLOOPUV, act);
 +
 +              act = CustomData_get_stencil_layer(&bm->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_stencil(&bm->ldata, CD_MLOOPUV, act);
 +      }
 +}
 +
 +/*does not free the BMEditMesh struct itself*/
 +void BMEdit_Free(BMEditMesh *em)
 +{
 +      if(em->derivedFinal) {
 +              if (em->derivedFinal!=em->derivedCage) {
 +                      em->derivedFinal->needsFree= 1;
 +                      em->derivedFinal->release(em->derivedFinal);
 +              }
 +              em->derivedFinal= NULL;
 +      }
 +      if(em->derivedCage) {
 +              em->derivedCage->needsFree= 1;
 +              em->derivedCage->release(em->derivedCage);
 +              em->derivedCage= NULL;
 +      }
 +
 +      em->retopo_paint_data= NULL;
 +
 +      if (em->looptris) MEM_freeN(em->looptris);
 +
 +      if (em->vert_index) MEM_freeN(em->vert_index);
 +      if (em->edge_index) MEM_freeN(em->edge_index);
 +      if (em->face_index) MEM_freeN(em->face_index);
 +
 +      if (em->bm)
 +              BM_Free_Mesh(em->bm);
 +}
 +
 +/*
 +ok, basic design:
 +
 +the bmesh derivedmesh exposes the mesh as triangles.  it stores pointers
 +to three loops per triangle.  the derivedmesh stores a cache of tesselations
 +for each face.  this cache will smartly update as needed (though at first
 +it'll simply be more brute force).  keeping track of face/edge counts may
 +be a small problbm.
 +
 +this won't be the most efficient thing, considering that internal edges and
 +faces of tesselations are exposed.  looking up an edge by index in particular
 +is likely to be a little slow.
 +*/
 +
 +typedef struct EditDerivedBMesh {
 +      DerivedMesh dm;
 +
 +      Object *ob;
 +      BMEditMesh *tc;
 +
 +      float (*vertexCos)[3];
 +      float (*vertexNos)[3];
 +      float (*faceNos)[3];
 +
 +      /*lookup caches; these are rebuilt on dm->RecalcTesselation()
 +        (or when the derivedmesh is created, of course)*/
 +      GHash *vhash, *ehash, *fhash;
 +      BMVert **vtable;
 +      BMEdge **etable;
 +      BMFace **ftable;
 +
 +      /*private variables, for number of verts/edges/faces
 +        within the above hash/table members*/
 +      int tv, te, tf;
 +} EditDerivedBMesh;
 +
 +static void bmdm_recalc_lookups(EditDerivedBMesh *bmdm)
 +{
 +      BMIter iter;
 +      BMHeader *h;
 +      int a, i, iters[3] = {BM_VERTS_OF_MESH, BM_EDGES_OF_MESH, BM_FACES_OF_MESH};
 +      
 +      bmdm->tv = bmdm->tc->bm->totvert;
 +      bmdm->te = bmdm->tc->bm->totedge;
 +      bmdm->tf = bmdm->tc->bm->totface;
 +
 +      if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
 +      if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
 +      if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
 +
 +      bmdm->vhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
 +      bmdm->ehash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
 +      bmdm->fhash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "bmesh derived");
 +      
 +      if (bmdm->vtable) MEM_freeN(bmdm->vtable);
 +      if (bmdm->etable) MEM_freeN(bmdm->etable);
 +      if (bmdm->ftable) MEM_freeN(bmdm->ftable);
 +      
 +      if (bmdm->tc->bm->totvert)
 +              bmdm->vtable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totvert, "bmdm->vtable");
 +      else bmdm->vtable = NULL;
 +
 +      if (bmdm->tc->bm->totedge)
 +              bmdm->etable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totedge, "bmdm->etable");
 +      else bmdm->etable = NULL;
 +      
 +      if (bmdm->tc->bm->totface)
 +              bmdm->ftable = MEM_mallocN(sizeof(void**)*bmdm->tc->bm->totface, "bmdm->ftable");
 +      else bmdm->ftable = NULL;
 +      
 +      for (a=0; a<3; a++) {
 +              h = BMIter_New(&iter, bmdm->tc->bm, iters[a], NULL);
 +              for (i=0; h; h=BMIter_Step(&iter), i++) {
 +                      switch (a) {
 +                              case 0:
 +                                      bmdm->vtable[i] = (BMVert*) h;
 +                                      BLI_ghash_insert(bmdm->vhash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +                              case 1:
 +                                      bmdm->etable[i] = (BMEdge*) h;
 +                                      BLI_ghash_insert(bmdm->ehash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +                              case 2:
 +                                      bmdm->ftable[i] = (BMFace*) h;
 +                                      BLI_ghash_insert(bmdm->fhash, h, SET_INT_IN_POINTER(i));
 +                                      break;
 +
 +                      }
 +              }
 +      }
 +}
 +
 +static void bmDM_recalcTesselation(DerivedMesh *UNUSED(dm))
 +{
 +      //EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      //bmdm_recalc_lookups(bmdm);
 +}
 +
 +static void bmDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMIter iter;
 +      int i;
 +      
 +      eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; eve; i++, eve=BMIter_Step(&iter)) {
 +              if (bmdm->vertexCos) {
 +                      func(userData, i, bmdm->vertexCos[i], bmdm->vertexNos[i], NULL);
 +              } else {
 +                      func(userData, i, eve->co, eve->no, NULL);
 +              }
 +      }
 +}
 +static void bmDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +      
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +              BMIter viter;
 +
 +              eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&viter), i++) {
 +                      BM_SetIndex(eve, i);
 +              }
 +
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter))
 +                      func(userData, i, 
 +                           bmdm->vertexCos[BM_GetIndex(eed->v1)], 
 +                           bmdm->vertexCos[BM_GetIndex(eed->v2)]);
 +      } else {
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter))
 +                      func(userData, i, eed->v1->co, eed->v2->co);
 +      }
 +
 +}
 +
 +static void bmDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) 
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +      
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +              BMIter viter;
 +
 +              eve = BMIter_New(&viter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&viter), i++) {
 +                      BM_SetIndex(eve, i);
 +              }
 +
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              glVertex3fv(bmdm->vertexCos[BM_GetIndex(eed->v1)]);
 +                              glVertex3fv(bmdm->vertexCos[BM_GetIndex(eed->v2)]);
 +                      }
 +              }
 +              glEnd();
 +
 +      } else {
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              glVertex3fv(eed->v1->co);
 +                              glVertex3fv(eed->v2->co);
 +                      }
 +              }
 +              glEnd();
 +      }
 +}
 +
 +static void bmDM_drawEdges(DerivedMesh *dm, int UNUSED(drawLooseEdges), int UNUSED(drawAllEdges))
 +{
 +      bmDM_drawMappedEdges(dm, NULL, NULL);
 +}
 +
 +static void bmDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) 
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEdge *eed;
 +      BMIter iter;
 +      int i;
 +
 +      if (bmdm->vertexCos) {
 +              BMVert *eve;
 +
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      BM_SetIndex(eve, i);
 +
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              setDrawInterpOptions(userData, i, 0.0);
 +                              glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(eed->v1)]);
 +                              setDrawInterpOptions(userData, i, 1.0);
 +                              glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(eed->v2)]);
 +                      }
 +              }
 +              glEnd();
 +      } else {
 +              glBegin(GL_LINES);
 +              eed = BMIter_New(&iter, bmdm->tc->bm, BM_EDGES_OF_MESH, NULL);
 +              for(i=0; eed; i++,eed=BMIter_Step(&iter)) {
 +                      if(!setDrawOptions || setDrawOptions(userData, i)) {
 +                              setDrawInterpOptions(userData, i, 0.0);
 +                              glVertex3fv(eed->v1->co);
 +                              setDrawInterpOptions(userData, i, 1.0);
 +                              glVertex3fv(eed->v2->co);
 +                      }
 +              }
 +              glEnd();
 +      }
 +}
 +
 +static void bmDM_drawUVEdges(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEditMesh *em = bmdm->tc;
 +      BMFace *efa;
 +      BMIter iter;
 +
 +      glBegin(GL_LINES);
 +      BM_ITER(efa, &iter, em->bm, BM_FACES_OF_MESH, NULL) {
 +              BMIter liter;
 +              BMLoop *l;
 +              MLoopUV *lastluv = NULL, *firstluv = NULL;
 +              
 +              if (BM_TestHFlag(efa, BM_HIDDEN))
 +                      continue;
 +              
 +              BM_ITER(l, &liter, em->bm, BM_LOOPS_OF_FACE, efa) {
 +                      MLoopUV *luv = CustomData_bmesh_get(&em->bm->ldata, l->head.data, CD_MLOOPUV);
 +                      
 +                      if (luv) {
 +                              if (lastluv) 
 +                                      glVertex2fv(luv->uv);
 +                              glVertex2fv(luv->uv);
 +                              
 +                              lastluv = luv;
 +                              if (!firstluv) 
 +                                      firstluv = luv;
 +                      }
 +              }
 +              
 +              if (lastluv) {
 +                      glVertex2fv(lastluv->uv);
 +                      glVertex2fv(firstluv->uv);
 +              }
 +      }
 +      glEnd();
 +}
 +
 +static void bmDM__calcFaceCent(BMesh *bm, BMFace *efa, float cent[3], 
 +                                                         float (*vertexCos)[3])
 +{
 +      BMIter iter;
 +      BMLoop *l;
 +      int tot = 0;
 +      
 +      cent[0] = cent[1] = cent[2] = 0.0f;
 +      
 +      /*simple (and stupid) median (average) based method :/ */
 +      
 +      if (vertexCos) {
 +              l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
 +              for (; l; l=BMIter_Step(&iter)) {
 +                      VECADD(cent, cent, vertexCos[BM_GetIndex(l->v)]);
 +                      tot++;
 +              }
 +      } else {
 +              l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
 +              for (; l; l=BMIter_Step(&iter)) {
 +                      VECADD(cent, cent, l->v->co);
 +                      tot++;
 +              }
 +      }
 +
 +      if (tot==0) return;
 +      mul_v3_fl(cent, 1.0f/(float)tot);
 +}
 +
 +static void bmDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMFace *efa;
 +      BMIter iter;
 +      float cent[3];
 +      int i;
 +
 +      if (bmdm->vertexCos) {
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      BM_SetIndex(eve, i);
 +      }
 +
 +      efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
 +      for (i=0; efa; efa=BMIter_Step(&iter), i++) {
 +              bmDM__calcFaceCent(bmdm->tc->bm, efa, cent, bmdm->vertexCos);
 +              func(userData, i, cent, bmdm->vertexCos?bmdm->faceNos[i]:efa->no);
 +      }
 +}
 +
 +static void bmDM_drawMappedFaces(DerivedMesh *dm, 
 +      int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), 
 +      void *userData, int useColors, 
 +      int (*setMaterial)(int, void *attribs),
 +      int (*compareDrawOptions)(void *userData, int cur_index, int next_index))
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMFace *efa;
 +      BMIter iter;
 +      int i, draw;
 +
 +      const int skip_normals= !glIsEnabled(GL_LIGHTING); /* could be passed as an arg */
 +
 +      /* GL_ZERO is used to detect if drawing has started or not */
 +      GLenum poly_prev= GL_ZERO;
 +      GLenum shade_prev= GL_ZERO;
 +
 +      /*BMESH_TODO*/
 +      (void)useColors;
 +
 +      (void)setMaterial; /* UNUSED */
 +
 +      /* currently unused -- each original face is handled separately */
 +      (void)compareDrawOptions;
 +
 +      if (bmdm->vertexCos) {
 +              /* add direct access */
 +              float (*vertexCos)[3]= bmdm->vertexCos;
 +              float (*vertexNos)[3]= bmdm->vertexNos;
 +              float (*faceNos)[3]=   bmdm->faceNos;
 +              BMVert *eve;
 +              
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      BM_SetIndex(eve, i);
 +
 +              efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
 +              for (i=0; efa; efa=BMIter_Step(&iter), i++)
 +                      BM_SetIndex(efa, i);
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      int drawSmooth;
 +                      
 +                      efa = l[0]->f;
 +                      drawSmooth = (efa->head.flag & BM_SMOOTH);
 +
 +                      draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BM_GetIndex(efa), &drawSmooth);
 +                      if(draw) {
 +                              const GLenum poly_type= GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
 +                              if (draw==2) { /* enabled with stipple */
 +
 +                                      if(poly_prev != GL_ZERO) glEnd();
 +                                      poly_prev= GL_ZERO; /* force glBegin */
 +
 +                                      glEnable(GL_POLYGON_STIPPLE);
 +                                      glPolygonStipple(stipple_quarttone);
 +                              }
 +                              
 +                              if(skip_normals) {
 +                                      if(poly_type != poly_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +                                      glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
 +                                      glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
 +                                      glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
 +                              }
 +                              else {
 +                                      const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
 +                                      if (shade_type != shade_prev) {
-                                               glShadeModel((shade_prev= shade_type));
++                                              if(poly_prev != GL_ZERO) glEnd();
++                                              glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
++                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +                                      if(poly_type != poly_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +
 +                                      if (!drawSmooth) {
 +                                              glNormal3fv(faceNos[i]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
 +                                      } else {
 +                                              glNormal3fv(vertexNos[(int) BM_GetIndex(l[0]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
 +                                              glNormal3fv(vertexNos[(int) BM_GetIndex(l[1]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
 +                                              glNormal3fv(vertexNos[(int) BM_GetIndex(l[2]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
 +                                      }
 +                              }
 +
 +                              if (draw==2) {
 +                                      glEnd();
 +                                      poly_prev= GL_ZERO; /* force glBegin */
 +
 +                                      glDisable(GL_POLYGON_STIPPLE);
 +                              }
 +                      }
 +              }
 +      } else {
 +              efa = BMIter_New(&iter, bmdm->tc->bm, BM_FACES_OF_MESH, NULL);
 +              for (i=0; efa; efa=BMIter_Step(&iter), i++)
 +                      BM_SetIndex(efa, i);
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      int drawSmooth;
 +
 +                      efa = l[0]->f;
 +                      drawSmooth = (efa->head.flag & BM_SMOOTH);
 +                      
 +                      draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BM_GetIndex(efa), &drawSmooth);
 +                      if(draw) {
 +                              const GLenum poly_type= GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
 +                              if (draw==2) { /* enabled with stipple */
 +
 +                                      if(poly_prev != GL_ZERO) glEnd();
 +                                      poly_prev= GL_ZERO; /* force glBegin */
 +
 +                                      glEnable(GL_POLYGON_STIPPLE);
 +                                      glPolygonStipple(stipple_quarttone);
 +                              }
 +                              
 +                              if(skip_normals) {
 +                                      if(poly_type != poly_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +                                      glVertex3fv(l[0]->v->co);
 +                                      glVertex3fv(l[1]->v->co);
 +                                      glVertex3fv(l[2]->v->co);
 +                              }
 +                              else {
 +                                      const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
 +                                      if (shade_type != shade_prev) {
++                                              if(poly_prev != GL_ZERO) glEnd();
++                                              glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
++                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +                                      if(poly_type != poly_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +
 +                                      if (!drawSmooth) {
 +                                              glNormal3fv(efa->no);
 +                                              glVertex3fv(l[0]->v->co);
 +                                              glVertex3fv(l[1]->v->co);
 +                                              glVertex3fv(l[2]->v->co);
 +                                      } else {
 +                                              glNormal3fv(l[0]->v->no);
 +                                              glVertex3fv(l[0]->v->co);
 +                                              glNormal3fv(l[1]->v->no);
 +                                              glVertex3fv(l[1]->v->co);
 +                                              glNormal3fv(l[2]->v->no);
 +                                              glVertex3fv(l[2]->v->co);
 +                                      }
 +                              }
 +                              if (draw==2) {
 +                                      glEnd();
 +                                      poly_prev= GL_ZERO; /* force glBegin */
 +
 +                                      glDisable(GL_POLYGON_STIPPLE);
 +                              }
 +                      }
 +              }
 +      }
 +
 +      /* if non zero we know a face was rendered */
 +      if(poly_prev != GL_ZERO) glEnd();
 +}
 +
 +static void bmdm_get_tri_tex(BMesh *bm, BMLoop **ls, MLoopUV *luv[3], MLoopCol *lcol[3], 
 +                           int has_uv, int has_col)
 +{
 +      if (has_uv) { 
 +              luv[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPUV);
 +              luv[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPUV);
 +              luv[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPUV);
 +      }
 +
 +      if (has_col) {
 +              lcol[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPCOL);
 +              lcol[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPCOL);
 +              lcol[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPCOL);
 +      }
 +
 +
 +}
 +
 +static void bmDM_drawFacesTex_common(DerivedMesh *dm,
 +               int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
 +               int (*drawParamsMapped)(void *userData, int index),
 +               void *userData) 
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMEditMesh *em = bmdm->tc;
 +      BMesh *bm= bmdm->tc->bm;
 +      float (*vertexCos)[3]= bmdm->vertexCos;
 +      float (*vertexNos)[3]= bmdm->vertexNos;
 +      BMFace *efa;
 +      BMVert *eve;
 +      BMIter iter;
 +      MLoopUV *luv[3], dummyluv = {{0}};
 +      MLoopCol *lcol[3], dummylcol = {0};
 +      int i, has_vcol = CustomData_has_layer(&bm->ldata, CD_MLOOPCOL);
 +      int has_uv = CustomData_has_layer(&bm->pdata, CD_MTEXPOLY);
 +      
 +      luv[0] = luv[1] = luv[2] = &dummyluv;
 +      lcol[0] = lcol[1] = lcol[2] = &dummylcol;
 +
 +      dummylcol.a = dummylcol.r = dummylcol.g = dummylcol.b = 255;
 +
 +      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 +      glShadeModel(GL_SMOOTH);
 +      
 +      i = 0;
 +      BM_ITER(efa, &iter, bm, BM_FACES_OF_MESH, NULL)
 +              BM_SetIndex(efa, i++);
 +
 +      if (vertexCos) {
 +              i = 0;
 +              BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
 +                      BM_SetIndex(eve, i++);
 +                              
 +              glBegin(GL_TRIANGLES);
 +              for (i=0; i<em->tottri; i++) {
 +                      BMLoop **ls = em->looptris[i];
 +                      MTexPoly *tp= CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY);
 +                      MTFace mtf = {{{0}}};
 +                      /*unsigned char *cp= NULL;*/ /*UNUSED*/
 +                      int drawSmooth= BM_TestHFlag(ls[0]->f, BM_SMOOTH);
 +                      int flag;
 +
 +                      efa = ls[0]->f;
 +                      
 +                      if (has_uv) {
 +                              mtf.flag = tp->flag;
 +                              mtf.tpage = tp->tpage;
 +                              mtf.transp = tp->transp;
 +                              mtf.mode = tp->mode;
 +                              mtf.tile = tp->tile;
 +                              mtf.unwrap = tp->unwrap;
 +                      }
 +
 +                      if(drawParams)
 +                              flag= drawParams(&mtf, has_vcol, efa->mat_nr);
 +                      else if(drawParamsMapped)
 +                              flag= drawParamsMapped(userData, BM_GetIndex(efa));
 +                      else
 +                              flag= 1;
 +
 +                      if(flag != 0) { /* flag 0 == the face is hidden or invisible */
 +                              
 +                              /* we always want smooth here since otherwise vertex colors dont interpolate */
 +                              if (!has_vcol) {
 +                                      glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +                              } 
 +                              
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(bmdm->faceNos[i]);
 +                                      
 +                                      bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
 +                                      
 +                                      glTexCoord2fv(luv[0]->uv);
 +                                      glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ls[0]->v)]);
 +
 +                                      glTexCoord2fv(luv[1]->uv);
 +                                      glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ls[1]->v)]);
 +
 +                                      glTexCoord2fv(luv[2]->uv);
 +                                      glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ls[2]->v)]);
 +                              } else {
 +                                      bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
 +                                      
 +                                      glTexCoord2fv(luv[0]->uv);
 +                                      glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ls[0]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ls[0]->v)]);
 +
 +                                      glTexCoord2fv(luv[1]->uv);
 +                                      glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ls[1]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ls[1]->v)]);
 +
 +                                      glTexCoord2fv(luv[2]->uv);
 +                                      glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ls[2]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ls[2]->v)]);
 +                              }
 +                      }
 +              }
 +              glEnd();
 +      } else {
 +              i = 0;
 +              BM_ITER(eve, &iter, bm, BM_VERTS_OF_MESH, NULL)
 +                      BM_SetIndex(eve, i++);
 +                              
 +              for (i=0; i<em->tottri; i++) {
 +                      BMLoop **ls = em->looptris[i];
 +                      MTexPoly *tp= CustomData_bmesh_get(&bm->pdata, ls[0]->f->head.data, CD_MTEXPOLY);
 +                      MTFace mtf = {{{0}}};
 +                      /*unsigned char *cp= NULL;*/ /*UNUSED*/
 +                      int drawSmooth= BM_TestHFlag(ls[0]->f, BM_SMOOTH);
 +                      int flag;
 +
 +                      efa = ls[0]->f;
 +                      
 +                      if (has_uv) {
 +                              mtf.flag = tp->flag;
 +                              mtf.tpage = tp->tpage;
 +                              mtf.transp = tp->transp;
 +                              mtf.mode = tp->mode;
 +                              mtf.tile = tp->tile;
 +                              mtf.unwrap = tp->unwrap;
 +                      }
 +
 +                      if(drawParams)
 +                              flag= drawParams(&mtf, has_vcol, efa->mat_nr);
 +                      else if(drawParamsMapped)
 +                              flag= drawParamsMapped(userData, BM_GetIndex(efa));
 +                      else
 +                              flag= 1;
 +
 +                      if(flag != 0) { /* flag 0 == the face is hidden or invisible */
 +                              
 +                              /* we always want smooth here since otherwise vertex colors dont interpolate */
 +                              if (!has_vcol) {
 +                                      glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +                              } 
 +                              
 +                              glBegin(GL_TRIANGLES);
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(efa->no);
 +                                      
 +                                      bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
 +                                      
 +                                      if (luv[0])
 +                                              glTexCoord2fv(luv[0]->uv);
 +                                      if (lcol[0])
 +                                              glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glVertex3fv(ls[0]->v->co);
 +
 +                                      if (luv[1])
 +                                              glTexCoord2fv(luv[1]->uv);
 +                                      if (lcol[1])
 +                                              glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glVertex3fv(ls[1]->v->co);
 +
 +                                      if (luv[2])
 +                                              glTexCoord2fv(luv[2]->uv);
 +                                      if (lcol[2])
 +                                              glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glVertex3fv(ls[2]->v->co);
 +                              } else {
 +                                      bmdm_get_tri_tex(bm, ls, luv, lcol, has_uv, has_vcol);
 +                                      
 +                                      if (luv[0])
 +                                              glTexCoord2fv(luv[0]->uv);
 +                                      if (lcol[0])
 +                                              glColor3ub(lcol[0]->b, lcol[0]->g, lcol[0]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glNormal3fv(ls[0]->v->no);
 +                                      glVertex3fv(ls[0]->v->co);
 +
 +                                      if (luv[1])
 +                                              glTexCoord2fv(luv[1]->uv);
 +                                      if (lcol[1])
 +                                              glColor3ub(lcol[1]->b, lcol[1]->g, lcol[1]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glNormal3fv(ls[1]->v->no);
 +                                      glVertex3fv(ls[1]->v->co);
 +
 +                                      if (luv[2])
 +                                              glTexCoord2fv(luv[2]->uv);
 +                                      if (lcol[2])
 +                                              glColor3ub(lcol[2]->b, lcol[2]->g, lcol[2]->r);
 +                                      else glColor3ub(0, 0, 0);
 +                                      glNormal3fv(ls[2]->v->no);
 +                                      glVertex3fv(ls[2]->v->co);
 +                              }
 +                              glEnd();
 +                      }
 +              }
 +      }
 +}
 +
 +static void bmDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
 +{
 +      bmDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
 +}
 +
 +static void bmDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
 +{
 +      bmDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 +}
 +
 +static void bmDM_drawMappedFacesGLSL(DerivedMesh *dm,
 +               int (*setMaterial)(int, void *attribs),
 +               int (*setDrawOptions)(void *userData, int index), void *userData)
 +{
 +#if 0
 +      (void)dm;
 +      (void)setMaterial;
 +      (void)setDrawOptions;
 +      (void)userData;
 +#else /*BMESH_TODO*/
 +
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      BMEditMesh *em = bmdm->tc;
 +      float (*vertexCos)[3]= bmdm->vertexCos;
 +      float (*vertexNos)[3]= bmdm->vertexNos;
 +      BMVert *eve;
 +      BMFace *efa;
 +      BMIter iter;
 +      BMLoop **ltri;
 +      DMVertexAttribs attribs;
 +      GPUVertexAttribs gattribs;
 +
 +      int i, b, matnr, new_matnr, dodraw;
 +
 +      dodraw = 0;
 +      matnr = -1;
 +
 +      memset(&attribs, 0, sizeof(attribs));
 +
 +      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 +      glShadeModel(GL_SMOOTH);
 +      BM_ITER_INDEX(eve, &iter, bm, BM_VERTS_OF_MESH, NULL, i) {
 +               BM_SetIndex(eve, i);
 +      }
 +
 +#define PASSATTRIB(loop, eve, vert) {                                                                                 \
 +      if(attribs.totorco) {                                                                                                           \
 +              float *orco = attribs.orco.array[BM_GetIndex(eve)];                                             \
 +              glVertexAttrib3fvARB(attribs.orco.glIndex, orco);                                               \
 +      }                                                                                                                                                       \
 +      for(b = 0; b < attribs.tottface; b++) {                                                                         \
 +              MLoopUV *_luv = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPUV, b);\
 +              glVertexAttrib2fvARB(attribs.tface[b].glIndex, _luv->uv);                               \
 +      }                                                                                                                                                       \
 +      for(b = 0; b < attribs.totmcol; b++) {                                                                          \
 +              MLoopCol *_cp = CustomData_bmesh_get_n(&bm->ldata, loop->head.data, CD_MLOOPCOL, b);\
 +              GLubyte _col[4];                                                                                                                \
 +              _col[0]= _cp->b; _col[1]= _cp->g; _col[2]= _cp->r; _col[3]= _cp->a;             \
 +              glVertexAttrib4ubvARB(attribs.mcol[b].glIndex, _col);                                   \
 +      }                                                                                                                                                       \
 +      if(attribs.tottang) {                                                                                                           \
 +              float *tang = attribs.tang.array[i*4 + vert];                                                   \
 +              glVertexAttrib3fvARB(attribs.tang.glIndex, tang);                                               \
 +      }                                                                                                                                                       \
 +      }
 +      
 +      BM_ITER_INDEX(efa, &iter, bm, BM_FACES_OF_MESH, NULL, i) {
 +              BM_SetIndex(efa, i);
 +      }
 +      
 +      for (i=0, ltri=em->looptris[0]; i<em->tottri; i++, ltri += 3) {
 +              int drawSmooth;
 +
 +              efa = ltri[0]->f;
 +              drawSmooth= BM_TestHFlag(efa, BM_SMOOTH);
 +              
 +              if(setDrawOptions && !setDrawOptions(userData, BM_GetIndex(efa)))
 +                      continue;
 +
 +              new_matnr = efa->mat_nr + 1;
 +              if(new_matnr != matnr) {
 +                      dodraw = setMaterial(matnr = new_matnr, &gattribs);
 +                      if(dodraw)
 +                              DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
 +              }
 +
 +              if(dodraw) {
 +                      glBegin(GL_TRIANGLES);
 +                      if (!drawSmooth) {
 +                              if(vertexCos) glNormal3fv(bmdm->faceNos[i]);
 +                              else glNormal3fv(efa->no);
 +
 +                              PASSATTRIB(ltri[0], ltri[0]->v, 0);
 +                              if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[0]->v)]);
 +                              else glVertex3fv(ltri[0]->v->co);
 +
 +                              PASSATTRIB(ltri[1], ltri[1]->v, 1);
 +                              if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[1]->v)]);
 +                              else glVertex3fv(ltri[1]->v->co);
 +
 +                              PASSATTRIB(ltri[2], ltri[2]->v, 2);
 +                              if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[2]->v)]);
 +                              else glVertex3fv(ltri[2]->v->co);
 +                      } else {
 +                              PASSATTRIB(ltri[0], ltri[0]->v, 0);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ltri[0]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ltri[0]->v)]);
 +                              }
 +                              else {
 +                                      glNormal3fv(ltri[0]->v->no);
 +                                      glVertex3fv(ltri[0]->v->co);
 +                              }
 +
 +                              PASSATTRIB(ltri[1], ltri[1]->v, 1);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ltri[1]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ltri[1]->v)]);
 +                              }
 +                              else {
 +                                      glNormal3fv(ltri[1]->v->no);
 +                                      glVertex3fv(ltri[1]->v->co);
 +                              }
 +
 +                              PASSATTRIB(ltri[2], ltri[2]->v, 2);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ltri[2]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ltri[2]->v)]);
 +                              }
 +                              else {
 +                                      glNormal3fv(ltri[2]->v->no);
 +                                      glVertex3fv(ltri[2]->v->co);
 +                              }
 +                      }
 +                      glEnd();
 +              }
 +      }
 +#endif
 +}
 +
 +static void bmDM_drawFacesGLSL(DerivedMesh *dm,
 +               int (*setMaterial)(int, void *attribs))
 +{
 +      dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
 +}
 +
 +static void bmDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMIter iter;
 +      int i;
 +
 +      if (bmdm->tc->bm->totvert) {
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++) {
 +                      if (bmdm->vertexCos) {
 +                              DO_MINMAX(bmdm->vertexCos[i], min_r, max_r);
 +                      } else {
 +                              DO_MINMAX(eve->co, min_r, max_r);
 +                      }
 +              }
 +      } else {
 +              min_r[0] = min_r[1] = min_r[2] = max_r[0] = max_r[1] = max_r[2] = 0.0;
 +      }
 +}
 +static int bmDM_getNumVerts(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      return bmdm->tc->bm->totvert;
 +}
 +
 +static int bmDM_getNumEdges(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +
 +      return bmdm->tc->bm->totedge;
 +}
 +
 +static int bmDM_getNumTessFaces(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      
 +      return bmdm->tc->tottri;
 +}
 +
 +static int bmDM_getNumFaces(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      
 +      return bmdm->tc->bm->totface;
 +}
 +
 +static int bmvert_to_mvert(BMesh *bm, BMVert *ev, MVert *vert_r)
 +{
 +      copy_v3_v3(vert_r->co, ev->co);
 +
 +      vert_r->no[0] = (short)(ev->no[0] * 32767.0f);
 +      vert_r->no[1] = (short)(ev->no[1] * 32767.0f);
 +      vert_r->no[2] = (short)(ev->no[2] * 32767.0f);
 +
 +      vert_r->flag = BMFlags_To_MEFlags(ev);
 +
 +      if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
 +              vert_r->bweight = (unsigned char) (BM_GetCDf(&bm->vdata, ev, CD_BWEIGHT)*255.0f);
 +      }
 +
 +      return 1;
 +}
 +
 +static void bmDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
 +{
 +      BMVert *ev;
 +
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tv) {
 +              printf("error in bmDM_getVert.\n");
 +              return;
 +      }
 +
 +      ev = ((EditDerivedBMesh *)dm)->vtable[index];
 +      bmvert_to_mvert(((EditDerivedBMesh *)dm)->tc->bm, ev, vert_r);
 +}
 +
 +static void bmDM_getEdge(DerivedMesh *dm, int index, MEdge *edge_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMEdge *e;
 +
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->te) {
 +              printf("error in bmDM_getEdge.\n");
 +              return;
 +      }
 +
 +      e = bmdm->etable[index];
 +
 +      if (CustomData_has_layer(&bm->edata, CD_BWEIGHT)) {
 +              edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, e, CD_BWEIGHT)*255.0f);
 +      }
 +
 +      if (CustomData_has_layer(&bm->edata, CD_CREASE)) {
 +              edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, e, CD_CREASE)*255.0f);
 +      }
 +
 +      edge_r->flag = BMFlags_To_MEFlags(e);
 +      
 +      edge_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v1));
 +      edge_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v2));
 +}
 +
 +static void bmDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMFace *ef;
 +      BMLoop **l;
 +      
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tf) {
 +              printf("error in bmDM_getTessFace.\n");
 +              return;
 +      }
 +
 +      l = ((EditDerivedBMesh *)dm)->tc->looptris[index];
 +
 +      ef = l[0]->f;
 +
 +      face_r->mat_nr = (unsigned char) ef->mat_nr;
 +      face_r->flag = BMFlags_To_MEFlags(ef);
 +
 +      face_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[0]->v));
 +      face_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[1]->v));
 +      face_r->v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[2]->v));
 +      face_r->v4 = 0;
 +
 +      test_index_face(face_r, NULL, 0, 3);
 +}
 +
 +static void bmDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
 +{
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMVert *ev;
 +      BMIter iter;
 +
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for( ; ev; ev = BMIter_Step(&iter), ++vert_r) {
 +              copy_v3_v3(vert_r->co, ev->co);
 +
 +              vert_r->no[0] = (short) (ev->no[0] * 32767.0);
 +              vert_r->no[1] = (short) (ev->no[1] * 32767.0);
 +              vert_r->no[2] = (short) (ev->no[2] * 32767.0);
 +
 +              vert_r->flag = BMFlags_To_MEFlags(ev);
 +
 +              if (CustomData_has_layer(&bm->vdata, CD_BWEIGHT)) {
 +                      vert_r->bweight = (unsigned char) (BM_GetCDf(&bm->vdata, ev, CD_BWEIGHT)*255.0f);
 +              }
 +      }
 +}
 +
 +static void bmDM_copyEdgeArray(DerivedMesh *dm, MEdge *edge_r)
 +{
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMEdge *ee;
 +      BMIter iter;
 +      BMVert *ev;
 +      int has_bweight = CustomData_has_layer(&bm->edata, CD_BWEIGHT);
 +      int i, has_crease = CustomData_has_layer(&bm->edata, CD_CREASE);
 +
 +      /* store vertex indices in tmp union */
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; ev; ev=BMIter_Step(&iter), i++)
 +              BM_SetIndex(ev, i);
 +
 +      ee = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
 +      for( ; ee; ee=BMIter_Step(&iter), edge_r++) {
 +              if (has_bweight) {
 +                      edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_BWEIGHT)*255.0f);
 +              }
 +
 +              if (has_crease) {
 +                      edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_CREASE)*255.0f);
 +              }
 +
 +              edge_r->flag = BMFlags_To_MEFlags(ee);
 +
 +              edge_r->v1 = (int)BM_GetIndex(ee->v1);
 +              edge_r->v2 = (int)BM_GetIndex(ee->v2);
 +      }
 +}
 +
 +static void bmDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMFace *ef;
 +      BMVert *ev;
 +      BMIter iter;
 +      BMLoop **l;
 +      int i;
 +
 +      /* store vertexes indices in tmp union */
 +      i = 0;
 +      BM_ITER(ev, &iter, bm, BM_VERTS_OF_MESH, NULL)
 +              BM_SetIndex(ev, i++);
 +
 +      for (i=0; i<bmdm->tc->tottri; i++, face_r++) {
 +              l = bmdm->tc->looptris[i];
 +              ef = l[0]->f;
 +
 +              face_r->mat_nr = (unsigned char) ef->mat_nr;
 +
 +              face_r->flag = BMFlags_To_MEFlags(ef);
 +
 +              face_r->v1 = BM_GetIndex(l[0]->v);
 +              face_r->v2 = BM_GetIndex(l[1]->v);
 +              face_r->v3 = BM_GetIndex(l[2]->v);
 +              face_r->v4 = 0;
 +
 +              test_index_face(face_r, NULL, 0, 3);
 +      }
 +}
 +
 +
 +static void bmDM_copyLoopArray(DerivedMesh *dm, MLoop *loop_r)
 +{
 +      /* EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; */ /* UNUSED */
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMIter iter, liter;
 +      BMVert *v;
 +      BMFace *f;
 +      BMLoop *l;
 +      BMEdge *e;
 +      int i;
 +
 +      i = 0;
 +      BM_ITER(v, &iter, bm, BM_VERTS_OF_MESH, NULL) {
 +              BM_SetIndex(v, i++);
 +      }
 +
 +      i = 0;
 +      BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
 +              BM_SetIndex(e, i++);
 +      }
 +
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
 +                      loop_r->v = BM_GetIndex(l->v);
 +                      loop_r->e = BM_GetIndex(l->e);
 +                      loop_r++;
 +              }
 +      }
 +}
 +
 +static void bmDM_copyPolyArray(DerivedMesh *dm, MPoly *poly_r)
 +{
 +      /* EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; */ /* UNUSED */
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMIter iter;
 +      BMFace *f;
 +      int i;
 +
 +      i = 0;
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              poly_r->flag = BMFlags_To_MEFlags(f);
 +              poly_r->loopstart = i;
 +              poly_r->totloop = f->len;
 +              poly_r->mat_nr = f->mat_nr;
 +
 +              poly_r++;
 +              i += f->len;
 +      }
 +}
 +
 +static void *bmDM_getFaceDataArray(DerivedMesh *dm, int type)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      BMFace *efa;
 +      char *data, *bmdata;
 +      void *datalayer;
 +      int index /*, offset*/ /*UNUSED */, size, i;
 +
 +      datalayer = DM_get_tessface_data_layer(dm, type);
 +      if(datalayer)
 +              return datalayer;
 +
 +      /* layers are store per face for editmesh, we convert to a tbmporary
 +       * data layer array in the derivedmesh when these are requested */
 +      if(type == CD_MTFACE || type == CD_MCOL) {
 +              index = CustomData_get_layer_index(&bm->pdata, type);
 +
 +              if(index != -1) {
 +                      /* offset = bm->pdata.layers[index].offset; */ /* UNUSED */
 +                      size = CustomData_sizeof(type);
 +
 +                      DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
 +                      index = CustomData_get_layer_index(&dm->faceData, type);
 +                      dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
 +
 +                      data = datalayer = DM_get_tessface_data_layer(dm, type);
 +                      for (i=0; i<bmdm->tc->tottri; i++, data+=size) {
 +                              efa = bmdm->tc->looptris[i][0]->f;
 +                              /*BMESH_TODO: need to still add tface data,
 +                                derived from the loops.*/
 +                              bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, type);
 +                              memcpy(data, bmdata, size);
 +                      }
 +              }
 +      }
 +
 +      return datalayer;
 +}
 +
 +static void bmDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
 +{
 +      EditDerivedBMesh *emdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMIter iter;
 +      int i;
 +
 +      i= 0;
 +      BM_ITER(eve, &iter, emdm->tc->bm, BM_VERTS_OF_MESH, NULL) {
 +              if (emdm->vertexCos) {
 +                      copy_v3_v3(cos_r[i], emdm->vertexCos[i]);
 +              } else {
 +                      copy_v3_v3(cos_r[i], eve->co);
 +              }
 +              
 +              i++;
 +      }
 +}
 +
 +static void bmDM_release(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh *)dm;
 +
 +      if (DM_release(dm)) {
 +              if (bmdm->vertexCos) {
 +                      MEM_freeN(bmdm->vertexCos);
 +                      MEM_freeN(bmdm->vertexNos);
 +                      MEM_freeN(bmdm->faceNos);
 +              }
 +              
 +              if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
 +              if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
 +              if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
 +
 +              if (bmdm->vtable) MEM_freeN(bmdm->vtable);
 +              if (bmdm->etable) MEM_freeN(bmdm->etable);
 +              if (bmdm->ftable) MEM_freeN(bmdm->ftable);
 +              
 +              MEM_freeN(bmdm);
 +      }
 +}
 +
 +static CustomData *bmDm_getVertDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->vdata;
 +}
 +
 +static CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->edata;
 +}
 +
 +static CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->dm.faceData;
 +}
 +
 +static CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->ldata;
 +}
 +
 +static CustomData *bmDm_getFaceDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->pdata;
 +}
 +
 +
 +DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, Object *UNUSED(ob),
 +                                           float (*vertexCos)[3])
 +{
 +      EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__);
 +      BMesh *bm = em->bm;
 +      
 +      bmdm->tc = em;
 +
 +      DM_init((DerivedMesh*)bmdm, DM_TYPE_EDITBMESH, em->bm->totvert, 
 +               em->bm->totedge, em->tottri, em->bm->totloop, em->bm->totface);
 +      
 +      CustomData_from_bmeshpoly(&bmdm->dm.faceData, &em->bm->pdata, &em->bm->ldata, 0);
 +      
 +      bmdm->dm.numVertData = bm->totvert;
 +      bmdm->dm.numEdgeData = bm->totedge;
 +      bmdm->dm.numFaceData = em->tottri;
 +      bmdm->dm.numLoopData = bm->totloop;
 +      bmdm->dm.numPolyData = bm->totface;
 +      
 +      bmdm->dm.getVertCos = bmDM_getVertCos;
 +      bmdm->dm.getMinMax = bmDM_getMinMax;
 +
 +      bmdm->dm.getVertDataLayout = bmDm_getVertDataLayout;
 +      bmdm->dm.getEdgeDataLayout = bmDm_getEdgeDataLayout;
 +      bmdm->dm.getTessFaceDataLayout = bmDm_getTessFaceDataLayout;
 +      bmdm->dm.getLoopDataLayout = bmDm_getLoopDataLayout;
 +      bmdm->dm.getFaceDataLayout = bmDm_getFaceDataLayout;
 +
 +      bmdm->dm.getNumVerts = bmDM_getNumVerts;
 +      bmdm->dm.getNumEdges = bmDM_getNumEdges;
 +      bmdm->dm.getNumTessFaces = bmDM_getNumTessFaces;
 +      bmdm->dm.getNumFaces = bmDM_getNumFaces;
 +
 +      bmdm->dm.getVert = bmDM_getVert;
 +      bmdm->dm.getEdge = bmDM_getEdge;
 +      bmdm->dm.getTessFace = bmDM_getTessFace;
 +      bmdm->dm.copyVertArray = bmDM_copyVertArray;
 +      bmdm->dm.copyEdgeArray = bmDM_copyEdgeArray;
 +      bmdm->dm.copyTessFaceArray = bmDM_copyFaceArray;
 +      bmdm->dm.copyLoopArray = bmDM_copyLoopArray;
 +      bmdm->dm.copyPolyArray = bmDM_copyPolyArray;
 +
 +      bmdm->dm.getTessFaceDataArray = bmDM_getFaceDataArray;
 +
 +      bmdm->dm.recalcTesselation = bmDM_recalcTesselation;
 +
 +      bmdm->dm.foreachMappedVert = bmDM_foreachMappedVert;
 +      bmdm->dm.foreachMappedEdge = bmDM_foreachMappedEdge;
 +      bmdm->dm.foreachMappedFaceCenter = bmDM_foreachMappedFaceCenter;
 +
 +      bmdm->dm.drawEdges = bmDM_drawEdges;
 +      bmdm->dm.drawMappedEdges = bmDM_drawMappedEdges;
 +      bmdm->dm.drawMappedEdgesInterp = bmDM_drawMappedEdgesInterp;
 +      bmdm->dm.drawMappedFaces = bmDM_drawMappedFaces;
 +      bmdm->dm.drawMappedFacesTex = bmDM_drawMappedFacesTex;
 +      bmdm->dm.drawMappedFacesGLSL = bmDM_drawMappedFacesGLSL;
 +      bmdm->dm.drawFacesTex = bmDM_drawFacesTex;
 +      bmdm->dm.drawFacesGLSL = bmDM_drawFacesGLSL;
 +      bmdm->dm.drawUVEdges = bmDM_drawUVEdges;
 +
 +      bmdm->dm.release = bmDM_release;
 +      
 +      bmdm->vertexCos = vertexCos;
 +
 +      if(CustomData_has_layer(&bm->vdata, CD_MDEFORMVERT)) {
 +              BMIter iter;
 +              BMVert *eve;
 +              int i;
 +
 +              DM_add_vert_layer(&bmdm->dm, CD_MDEFORMVERT, CD_CALLOC, NULL);
 +              
 +              eve = BMIter_New(&iter, bmdm->tc->bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      DM_set_vert_data(&bmdm->dm, i, CD_MDEFORMVERT,
 +                                       CustomData_bmesh_get(&bm->vdata, eve->head.data, CD_MDEFORMVERT));
 +      }
 +
 +      if(vertexCos) {
 +              BMVert *eve;
 +              BMIter iter;
 +              int totface = bmdm->tc->tottri;
 +              int i;
 +              
 +              eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++)
 +                      BM_SetIndex(eve, i);
 +
 +              bmdm->vertexNos = MEM_callocN(sizeof(*bmdm->vertexNos)*i, "bmdm_vno");
 +              bmdm->faceNos = MEM_mallocN(sizeof(*bmdm->faceNos)*totface, "bmdm_vno");
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      float *v1 = vertexCos[(int) BM_GetIndex(l[0]->v)];
 +                      float *v2 = vertexCos[(int) BM_GetIndex(l[1]->v)];
 +                      float *v3 = vertexCos[(int) BM_GetIndex(l[2]->v)];
 +                      float *no = bmdm->faceNos[i];
 +                      
 +                      normal_tri_v3( no,v1, v2, v3);
 +                      add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[0]->v)], bmdm->vertexNos[BM_GetIndex(l[0]->v)], no);
 +                      add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[1]->v)], bmdm->vertexNos[BM_GetIndex(l[1]->v)], no);
 +                      add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[2]->v)], bmdm->vertexNos[BM_GetIndex(l[2]->v)], no);
 +              }
 +
 +              eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++) {
 +                      float *no = bmdm->vertexNos[i];
 +                      /* following Mesh convention; we use vertex coordinate itself
 +                       * for normal in this case */
 +                      if (normalize_v3(no)==0.0) {
 +                              copy_v3_v3(no, vertexCos[i]);
 +                              normalize_v3(no);
 +                      }
 +              }
 +      }
 +
 +      //bmdm_recalc_lookups(bmdm);
 +
 +      return (DerivedMesh*) bmdm;
 +}
index ce2193fe09a0f098651219a409684d8228f2096b,2c7653b6e1c2354015a3d92d5d65ab6219ace725..01f521e3a0265f50531cca3ed1f15a51649a60f7
  #include "DNA_key_types.h"
  #include "DNA_meshdata_types.h"
  #include "DNA_ipo_types.h"
 +#include "DNA_customdata_types.h"
  
 +#include "BLI_utildefines.h"
  #include "BLI_blenlib.h"
  #include "BLI_editVert.h"
  #include "BLI_math.h"
  #include "BLI_edgehash.h"
 -#include "BLI_utildefines.h"
 +#include "BLI_scanfill.h"
  
  #include "BKE_animsys.h"
  #include "BKE_main.h"
 +#include "BKE_customdata.h"
  #include "BKE_DerivedMesh.h"
  #include "BKE_global.h"
  #include "BKE_mesh.h"
  #include "BKE_curve.h"
  /* -- */
  #include "BKE_object.h"
 +#include "BKE_tessmesh.h"
 +#include "BLI_edgehash.h"
 +
 +#include "BLI_blenlib.h"
 +#include "BLI_editVert.h"
 +#include "BLI_math.h"
 +#include "BLI_cellalloc.h"
 +#include "BLI_array.h"
 +#include "BLI_edgehash.h"
  
 +#include "bmesh.h"
 +
 +enum {
 +      MESHCMP_DVERT_WEIGHTMISMATCH = 1,
 +      MESHCMP_DVERT_GROUPMISMATCH,
 +      MESHCMP_DVERT_TOTGROUPMISMATCH,
 +      MESHCMP_LOOPCOLMISMATCH,
 +      MESHCMP_LOOPUVMISMATCH,
 +      MESHCMP_LOOPMISMATCH,
 +      MESHCMP_POLYVERTMISMATCH,
 +      MESHCMP_POLYMISMATCH,
 +      MESHCMP_EDGEUNKNOWN,
 +      MESHCMP_VERTCOMISMATCH,
 +      MESHCMP_CDLAYERS_MISMATCH,
 +};
  
 -EditMesh *BKE_mesh_get_editmesh(Mesh *me)
 +static const char *cmpcode_to_str(int code)
  {
 -      return me->edit_mesh;
 +      switch (code) {
 +              case MESHCMP_DVERT_WEIGHTMISMATCH:
 +                      return "Vertex Weight Mismatch";
 +              case MESHCMP_DVERT_GROUPMISMATCH:
 +                                      return "Vertex Group Mismatch";
 +              case MESHCMP_DVERT_TOTGROUPMISMATCH:
 +                                      return "Vertex Doesn't Belong To Same Number Of Groups";
 +              case MESHCMP_LOOPCOLMISMATCH:
 +                                      return "Vertex Color Mismatch";
 +              case MESHCMP_LOOPUVMISMATCH:
 +                                      return "UV Mismatch";
 +              case MESHCMP_LOOPMISMATCH:
 +                                      return "Loop Mismatch";
 +              case MESHCMP_POLYVERTMISMATCH:
 +                                      return "Loop Vert Mismatch In Poly Test";
 +              case MESHCMP_POLYMISMATCH:
 +                                      return "Loop Vert Mismatch";
 +              case MESHCMP_EDGEUNKNOWN:
 +                                      return "Edge Mismatch";
 +              case MESHCMP_VERTCOMISMATCH:
 +                                      return "Vertex Coordinate Mismatch";
 +              case MESHCMP_CDLAYERS_MISMATCH:
 +                                      "CustomData Layer Count Mismatch";
 +              default:
 +                              return "Mesh Comparison Code Unknown";
 +              }
  }
  
 -void BKE_mesh_end_editmesh(Mesh *UNUSED(me), EditMesh *UNUSED(em))
 +/*thresh is threshold for comparing vertices, uvs, vertex colors,
 +  weights, etc.*/
 +static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, float thresh)
  {
 +      CustomDataLayer *l1, *l2;
 +      int i, i1=0, i2=0, tot, j;
 +      
 +      for (i=0; i<c1->totlayer; i++) {
 +              if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))                
 +                      i1++;
 +      }
 +      
 +      for (i=0; i<c2->totlayer; i++) {
 +              if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))                
 +                      i2++;
 +      }
 +      
 +      if (i1 != i2)
 +              return MESHCMP_CDLAYERS_MISMATCH;
 +      
 +      l1 = c1->layers; l2 = c2->layers;
 +      tot = i1;
 +      i1 = 0; i2 = 0; 
 +      for (i=0; i < tot; i++) {
 +              while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
 +                      i1++, l1++;
 +
 +              while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
 +                      i2++, l2++;
 +              
 +              if (l1->type == CD_MVERT) {
 +                      MVert *v1 = l1->data;
 +                      MVert *v2 = l2->data;
 +                      int vtot = m1->totvert;
 +                      
 +                      for (j=0; j<vtot; j++, v1++, v2++) {
 +                              if (len_v3v3(v1->co, v2->co) > thresh)
 +                                      return MESHCMP_VERTCOMISMATCH;
 +                              /*I don't care about normals, let's just do coodinates*/
 +                      }
 +              }
 +              
 +              /*we're order-agnostic for edges here*/
 +              if (l1->type == CD_MEDGE) {
 +                      MEdge *e1 = l1->data;
 +                      MEdge *e2 = l2->data;
 +                      EdgeHash *eh = BLI_edgehash_new();
 +                      int etot = m1->totedge;
 +              
 +                      for (j=0; j<etot; j++, e1++) {
 +                              BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
 +                      }
 +                      
 +                      for (j=0; j<etot; j++, e2++) {
 +                              if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2))
 +                                      return MESHCMP_EDGEUNKNOWN;
 +                      }
 +                      BLI_edgehash_free(eh, NULL);
 +              }
 +              
 +              if (l1->type == CD_MPOLY) {
 +                      MPoly *p1 = l1->data;
 +                      MPoly *p2 = l2->data;
 +                      int ptot = m1->totpoly;
 +              
 +                      for (j=0; j<ptot; j++, p1++, p2++) {
 +                              MLoop *lp1, *lp2;
 +                              int k;
 +                              
 +                              if (p1->totloop != p2->totloop)
 +                                      return MESHCMP_POLYMISMATCH;
 +                              
 +                              lp1 = m1->mloop + p1->loopstart;
 +                              lp2 = m2->mloop + p2->loopstart;
 +                              
 +                              for (k=0; k<p1->totloop; k++, lp1++, lp2++) {
 +                                      if (lp1->v != lp2->v)
 +                                              return MESHCMP_POLYVERTMISMATCH;
 +                              }
 +                      }
 +              }
 +              if (l1->type == CD_MLOOP) {
 +                      MLoop *lp1 = l1->data;
 +                      MLoop *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (lp1->v != lp2->v)
 +                                      return MESHCMP_LOOPMISMATCH;
 +                      }
 +              }
 +              if (l1->type == CD_MLOOPUV) {
 +                      MLoopUV *lp1 = l1->data;
 +                      MLoopUV *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (len_v2v2(lp1->uv, lp2->uv) > thresh)
 +                                      return MESHCMP_LOOPUVMISMATCH;
 +                      }
 +              }
 +              
 +              if (l1->type == CD_MLOOPCOL) {
 +                      MLoopCol *lp1 = l1->data;
 +                      MLoopCol *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (ABS(lp1->r - lp2->r) > thresh || 
 +                                  ABS(lp1->g - lp2->g) > thresh || 
 +                                  ABS(lp1->b - lp2->b) > thresh || 
 +                                  ABS(lp1->a - lp2->a) > thresh)
 +                              {
 +                                      return MESHCMP_LOOPCOLMISMATCH;
 +                              }
 +                      }
 +              }
 +
 +              if (l1->type == CD_MDEFORMVERT) {
 +                      MDeformVert *dv1 = l1->data;
 +                      MDeformVert *dv2 = l2->data;
 +                      int dvtot = m1->totvert;
 +              
 +                      for (j=0; j<dvtot; j++, dv1++, dv2++) {
 +                              int k;
 +                              MDeformWeight *dw1 = dv1->dw, *dw2=dv2->dw;
 +                              
 +                              if (dv1->totweight != dv2->totweight)
 +                                      return MESHCMP_DVERT_TOTGROUPMISMATCH;
 +                              
 +                              for (k=0; k<dv1->totweight; k++, dw1++, dw2++) {
 +                                      if (dw1->def_nr != dw2->def_nr)
 +                                              return MESHCMP_DVERT_GROUPMISMATCH;
 +                                      if (ABS(dw1->weight - dw2->weight) > thresh)
 +                                              return MESHCMP_DVERT_WEIGHTMISMATCH;
 +                              }
 +                      }
 +              }
 +      }
 +      
 +      return 0;
 +}
 +
 +/*used for testing.  returns an error string the two meshes don't match*/
 +const char *mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
 +{
 +      int c;
 +      
 +      if (!me1 || !me2)
 +              return "Requires two input meshes";
 +      
 +      if (me1->totvert != me2->totvert) 
 +              return "Number of verts don't match";
 +      
 +      if (me1->totedge != me2->totedge)
 +              return "Number of edges don't match";
 +      
 +      if (me1->totpoly != me2->totpoly)
 +              return "Number of faces don't match";
 +                              
 +      if (me1->totloop !=me2->totloop)
 +              return "Number of loops don't match";
 +      
 +      if ((c = customdata_compare(&me1->vdata, &me2->vdata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->edata, &me2->edata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +      
 +      return NULL;
  }
  
 +static void mesh_ensure_tesselation_customdata(Mesh *me)
 +{
 +      int tottex, totcol;
 +
 +      tottex = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
 +      totcol = CustomData_number_of_layers(&me->fdata, CD_MCOL);
 +      
 +      if (tottex != CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY) ||
 +          totcol != CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL))
 +      {
 +              CustomData_free(&me->fdata, me->totface);
 +              
 +              me->mface = NULL;
 +              me->mtface = NULL;
 +              me->mcol = NULL;
 +              me->totface = 0;
 +
 +              memset(&me->fdata, 0, sizeof(&me->fdata));
 +
 +              CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface);
 +              printf("Warning! Tesselation uvs or vcol data got out of sync, had to reset!\n");
 +      }
 +}
 +
 +/*this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
 +  mloopcol and mcol) have the same relative active/render/clone/mask indices.*/
 +static void mesh_update_linked_customdata(Mesh *me)
 +{
 +      int act;
 +
 +      if (me->edit_btmesh)
 +              BMEdit_UpdateLinkedCustomData(me->edit_btmesh);
 +
 +      mesh_ensure_tesselation_customdata(me);
 +
 +      if (CustomData_has_layer(&me->pdata, CD_MTEXPOLY)) {
 +              act = CustomData_get_active_layer(&me->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_active(&me->ldata, CD_MLOOPUV, act);
 +              CustomData_set_layer_active(&me->fdata, CD_MTFACE, act);
 +
 +              act = CustomData_get_render_layer(&me->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_render(&me->ldata, CD_MLOOPUV, act);
 +              CustomData_set_layer_render(&me->fdata, CD_MTFACE, act);
 +
 +              act = CustomData_get_clone_layer(&me->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_clone(&me->ldata, CD_MLOOPUV, act);
 +              CustomData_set_layer_clone(&me->fdata, CD_MTFACE, act);
 +
 +              act = CustomData_get_stencil_layer(&me->pdata, CD_MTEXPOLY);
 +              CustomData_set_layer_stencil(&me->ldata, CD_MLOOPUV, act);
 +              CustomData_set_layer_stencil(&me->fdata, CD_MTFACE, act);
 +      }
 +
 +      if (CustomData_has_layer(&me->ldata, CD_MLOOPCOL)) {
 +              act = CustomData_get_active_layer(&me->ldata, CD_MLOOPCOL);
 +              CustomData_set_layer_active(&me->fdata, CD_MCOL, act);
 +
 +              act = CustomData_get_render_layer(&me->ldata, CD_MLOOPCOL);
 +              CustomData_set_layer_render(&me->fdata, CD_MCOL, act);
 +
 +              act = CustomData_get_clone_layer(&me->ldata, CD_MLOOPCOL);
 +              CustomData_set_layer_clone(&me->fdata, CD_MCOL, act);
 +
 +              act = CustomData_get_stencil_layer(&me->ldata, CD_MLOOPCOL);
 +              CustomData_set_layer_stencil(&me->fdata, CD_MCOL, act);
 +      }
 +}
  
  void mesh_update_customdata_pointers(Mesh *me)
  {
 +      mesh_update_linked_customdata(me);
 +
        me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
        me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
        me->msticky = CustomData_get_layer(&me->vdata, CD_MSTICKY);
        me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
        me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
        me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
 +      
 +      me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
 +      me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
 +
 +      me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY);
 +      me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
 +      me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
  }
  
  /* Note: unlinking is called when me->id.us is 0, question remains how
@@@ -428,10 -122,9 +428,10 @@@ void unlink_mesh(Mesh *me
  
  
  /* do not free mesh itself */
 -void free_mesh(Mesh *me)
 +void free_mesh(Mesh *me, int unlink)
  {
 -      unlink_mesh(me);
 +      if (unlink)
 +              unlink_mesh(me);
  
        if(me->pv) {
                if(me->pv->vert_map) MEM_freeN(me->pv->vert_map);
        CustomData_free(&me->vdata, me->totvert);
        CustomData_free(&me->edata, me->totedge);
        CustomData_free(&me->fdata, me->totface);
 -      
 +      CustomData_free(&me->ldata, me->totloop);
 +      CustomData_free(&me->pdata, me->totpoly);
 +
        if(me->adt) {
                BKE_free_animdata(&me->id);
                me->adt= NULL;
        
        if(me->bb) MEM_freeN(me->bb);
        if(me->mselect) MEM_freeN(me->mselect);
 -      if(me->edit_mesh) MEM_freeN(me->edit_mesh);
 +      if(me->edit_btmesh) MEM_freeN(me->edit_btmesh);
  }
  
  void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount)
        
        for (i=0; i<copycount; i++){
                if (src[i].dw){
 -                      dst[i].dw = MEM_callocN (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight");
 +                      dst[i].dw = BLI_cellalloc_calloc (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight");
                        memcpy (dst[i].dw, src[i].dw, sizeof (MDeformWeight)*src[i].totweight);
                }
        }
@@@ -493,7 -184,7 +493,7 @@@ void free_dverts(MDeformVert *dvert, in
  
        /* Free any special data from the verts */
        for (i=0; i<totvert; i++){
 -              if (dvert[i].dw) MEM_freeN (dvert[i].dw);
 +              if (dvert[i].dw) BLI_cellalloc_free (dvert[i].dw);
        }
        MEM_freeN (dvert);
  }
@@@ -518,7 -209,6 +518,7 @@@ Mesh *copy_mesh(Mesh *me
  {
        Mesh *men;
        MTFace *tface;
 +      MTexPoly *txface;
        int a, i;
        
        men= copy_libblock(me);
        CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert);
        CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge);
        CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface);
 +      CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop);
 +      CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly);
        mesh_update_customdata_pointers(men);
  
        /* ensure indirect linked data becomes lib-extern */
                                        id_lib_extern((ID*)tface->tpage);
                }
        }
 -      
 +
 +      for(i=0; i<me->pdata.totlayer; i++) {
 +              if(me->pdata.layers[i].type == CD_MTEXPOLY) {
 +                      txface= (MTexPoly*)me->pdata.layers[i].data;
 +
 +                      for(a=0; a<me->totpoly; a++, txface++)
 +                              if(txface->tpage)
 +                                      id_lib_extern((ID*)txface->tpage);
 +              }
 +      }
 +
        men->mselect= NULL;
 -      men->edit_mesh= NULL;
 +      men->edit_btmesh= NULL;
        men->pv= NULL; /* looks like this is no-longer supported but NULL just incase */
  
        men->bb= MEM_dupallocN(men->bb);
        return men;
  }
  
 +BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob)
 +{
 +      BMesh *bm;
 +      int allocsize[4] = {512,512,2048,512};
 +
 +      bm = BM_Make_Mesh(ob, allocsize);
 +
 +      BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", me, ob, 1);
 +
 +      return bm;
 +}
 +
  static void make_local_tface(Main *bmain, Mesh *me)
  {
        MTFace *tface;
 +      MTexPoly *txface;
        Image *ima;
        int a, i;
        
 +      for(i=0; i<me->pdata.totlayer; i++) {
 +              if(me->pdata.layers[i].type == CD_MTEXPOLY) {
 +                      txface= (MTexPoly*)me->fdata.layers[i].data;
 +                      
 +                      for(a=0; a<me->totpoly; a++, txface++) {
 +                              /* special case: ima always local immediately */
 +                              if(txface->tpage) {
 +                                      ima= txface->tpage;
 +                                      if(ima->id.lib) {
 +                                              ima->id.lib= 0;
 +                                              ima->id.flag= LIB_LOCAL;
 +                                              new_id(0, (ID *)ima, 0);
 +                                      }
 +                              }
 +                      }
 +              }
 +      }
 +
        for(i=0; i<me->fdata.totlayer; i++) {
                if(me->fdata.layers[i].type == CD_MTFACE) {
                        tface= (MTFace*)me->fdata.layers[i].data;
@@@ -954,17 -601,13 +954,17 @@@ static void mfaces_strip_loose(MFace *m
  }
  
  /* Create edges based on known verts and faces */
 -static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, int UNUSED(totvert), int totface,
 +static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *allloop,
 +      MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly,
        int old, MEdge **alledge, int *_totedge)
  {
 +      MPoly *mpoly;
 +      MLoop *mloop;
        MFace *mface;
        MEdge *medge;
 +      EdgeHash *hash = BLI_edgehash_new();
        struct edgesort *edsort, *ed;
 -      int a, totedge=0, final=0;
 +      int a, b, totedge=0, final=0;
  
        /* we put all edges in array, sort them, and detect doubles that way */
  
        medge->flag |= ME_EDGERENDER;
  
        MEM_freeN(edsort);
 +      
 +      /*set edge members of mloops*/
 +      medge= *alledge;
 +      for (a=0; a<*_totedge; a++, medge++) {
 +              BLI_edgehash_insert(hash, medge->v1, medge->v2, SET_INT_IN_POINTER(a));
 +      }
 +      
 +      mpoly = allpoly;
 +      for (a=0; a<totpoly; a++, mpoly++) {
 +              mloop = allloop + mpoly->loopstart;
 +              for (b=0; b<mpoly->totloop; b++) {
 +                      int v1, v2;
 +                      
 +                      v1 = mloop[b].v;
 +                      v2 = mloop[(b+1)%mpoly->totloop].v;
 +                      mloop[b].e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, v1, v2));
 +              }
 +      }
 +      
 +      BLI_edgehash_free(hash, NULL);
  }
  
  void make_edges(Mesh *me, int old)
        MEdge *medge;
        int totedge=0;
  
 -      make_edges_mdata(me->mvert, me->mface, me->totvert, me->totface, old, &medge, &totedge);
 +      make_edges_mdata(me->mvert, me->mface, me->mloop, me->mpoly, me->totvert, me->totface, me->totloop, me->totpoly, old, &medge, &totedge);
        if(totedge==0) {
                /* flag that mesh has edges */
                me->medge = medge;
@@@ -1159,37 -782,31 +1159,37 @@@ void mball_to_mesh(ListBase *lb, Mesh *
                }
  
                make_edges(me, 0);      // all edges
 -      }       
 +              convert_mfaces_to_mpolys(me);
 +      }
  }
  
  /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
  /* return non-zero on error */
  int nurbs_to_mdata(Object *ob, MVert **allvert, int *totvert,
 -      MEdge **alledge, int *totedge, MFace **allface, int *totface)
 +      MEdge **alledge, int *totedge, MFace **allface, MLoop **allloop, MPoly **allpoly, 
 +      int *totface, int *totloop, int *totpoly)
  {
        return nurbs_to_mdata_customdb(ob, &ob->disp,
 -              allvert, totvert, alledge, totedge, allface, totface);
 +              allvert, totvert, alledge, totedge, allface, allloop, allpoly, totface, totloop, totpoly);
  }
  
  /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
  /* use specified dispbase  */
  int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int *_totvert,
 -      MEdge **alledge, int *_totedge, MFace **allface, int *_totface)
 +      MEdge **alledge, int *_totedge, MFace **allface, MLoop **allloop, MPoly **allpoly, 
 +      int *_totface, int *_totloop, int *_totpoly)
  {
        DispList *dl;
        Curve *cu;
        MVert *mvert;
        MFace *mface;
 +      MPoly *mpoly;
 +      MLoop *mloop;
        float *data;
        int a, b, ofs, vertcount, startvert, totvert=0, totvlak=0;
        int p1, p2, p3, p4, *index;
        int conv_polys= 0;
 +      int i, j;
  
        cu= ob->data;
  
  
        *allvert= mvert= MEM_callocN(sizeof (MVert) * totvert, "nurbs_init mvert");
        *allface= mface= MEM_callocN(sizeof (MFace) * totvlak, "nurbs_init mface");
 -
 +      *allloop = mloop = MEM_callocN(sizeof(MLoop) * totvlak * 4, "nurbs_init mloop");
 +      *allpoly = mpoly = MEM_callocN(sizeof(MPoly) * totvlak * 4, "nurbs_init mloop");
 +      
        /* verts and faces */
        vertcount= 0;
  
  
                dl= dl->next;
        }
 -
 +      
 +      mface= *allface;
 +      j = 0;
 +      for (i=0; i<totvert; i++, mpoly++, mface++) {
 +              int k;
 +              
 +              if (!mface->v3) {
 +                      mpoly--;
 +                      i--;
 +                      continue;
 +              }
 +              
 +              if (mface >= *allface + totvlak)
 +                      break;
 +
 +              mpoly->flag |= mface->flag & ME_SMOOTH;
 +              mpoly->loopstart= j;
 +              mpoly->totloop= mface->v4 ? 4 : 3;
 +              for (k=0; k<mpoly->totloop; k++, mloop++, j++) {
 +                      mloop->v = (&mface->v1)[k];
 +              }
 +      }
 +      
 +      *_totpoly= i;
 +      *_totloop= j;
        *_totvert= totvert;
        *_totface= totvlak;
  
 -      make_edges_mdata(*allvert, *allface, totvert, totvlak, 0, alledge, _totedge);
 +      make_edges_mdata(*allvert, *allface, *allloop, *allpoly, totvert, totvlak, *_totloop, *_totpoly, 0, alledge, _totedge);
        mfaces_strip_loose(*allface, _totface);
  
        return 0;
@@@ -1413,14 -1004,12 +1413,14 @@@ void nurbs_to_mesh(Object *ob
        MVert *allvert= NULL;
        MEdge *alledge= NULL;
        MFace *allface= NULL;
 -      int totvert, totedge, totface;
 +      MLoop *allloop = NULL;
 +      MPoly *allpoly = NULL;
 +      int totvert, totedge, totface, totloop, totpoly;
  
        cu= ob->data;
  
        if (dm == NULL) {
 -              if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &totface) != 0) {
 +              if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &allloop, &allpoly, &totface, &totloop, &totpoly) != 0) {
                        /* Error initializing */
                        return;
                }
                me->totvert= totvert;
                me->totface= totface;
                me->totedge= totedge;
 +              me->totloop = totloop;
 +              me->totpoly = totpoly;
  
                me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
 -              me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, allface, me->totface);
                me->medge= CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
 +              me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, allface, me->totface);
 +              me->mloop= CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
 +              me->mpoly= CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
  
 -              mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
 +              mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
        } else {
                me= add_mesh("Mesh");
 -              DM_to_mesh(dm, me);
 +              DM_to_mesh(dm, me, ob);
        }
  
        me->totcol= cu->totcol;
@@@ -1503,10 -1088,10 +1503,10 @@@ void mesh_to_curve(Scene *scene, Objec
  
        MVert *mverts= dm->getVertArray(dm);
        MEdge *med, *medge= dm->getEdgeArray(dm);
 -      MFace *mf,  *mface= dm->getFaceArray(dm);
 +      MFace *mf,  *mface= dm->getTessFaceArray(dm);
  
        int totedge = dm->getNumEdges(dm);
 -      int totface = dm->getNumFaces(dm);
 +      int totface = dm->getNumTessFaces(dm);
        int totedges = 0;
        int i, needsFree = 0;
  
  
  void mesh_delete_material_index(Mesh *me, short index)
  {
 -      MFace *mf;
        int i;
  
 -      for (i=0, mf=me->mface; i<me->totface; i++, mf++) {
 +      for (i=0; i<me->totpoly; i++) {
 +              MPoly *mp = &((MPoly*) me->mpoly)[i];
 +              if (mp->mat_nr && mp->mat_nr>=index) 
 +                      mp->mat_nr--;
 +      }
 +      
 +      for (i=0; i<me->totface; i++) {
 +              MFace *mf = &((MFace*) me->mface)[i];
                if (mf->mat_nr && mf->mat_nr>=index) 
                        mf->mat_nr--;
        }
@@@ -1689,16 -1268,6 +1689,16 @@@ void mesh_set_smooth_flag(Object *meshO
        Mesh *me = meshOb->data;
        int i;
  
 +      for (i=0; i<me->totpoly; i++) {
 +              MPoly *mp = &((MPoly*) me->mpoly)[i];
 +
 +              if (enableSmooth) {
 +                      mp->flag |= ME_SMOOTH;
 +              } else {
 +                      mp->flag &= ~ME_SMOOTH;