svn merge -r39765:39781 https://svn.blender.org/svnroot/bf-blender/trunk/blender
authorCampbell Barton <ideasman42@gmail.com>
Tue, 30 Aug 2011 00:23:11 +0000 (00:23 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Tue, 30 Aug 2011 00:23:11 +0000 (00:23 +0000)
1  2 
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/editderivedbmesh.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/drawobject.c
source/blenderplayer/bad_level_call_stubs/stubs.c

index fae7e1492a2404beca5adea46d08ca7d6d209f43,6e17b056685e9d5cc789040f90f0204862b4a64b..73f0602cf3e4be45209af520675b1aece61f79e6
  #ifndef BKE_DERIVEDMESH_H
  #define BKE_DERIVEDMESH_H
  
 -/** \file BKE_DerivedMesh.h
 - *  \ingroup bke
 - *
 - *  \todo
 - *  - Make drawMapped* functions take a predicate function that
 - *    determines whether to draw the edge (this predicate can
 - *    also set color, etc). This will be slightly more general 
 - *    and allow some of the functions to be collapsed.
 - *  - Once accessor functions are added then single element draw
 - *    functions can be implemented using primitive accessors.
 - *  - Add function to dispatch to renderer instead of using
 - *    conversion to DLM.
 +/*
 +  Basic design of the DerivedMesh system:
 +
 +  DerivedMesh is a common set of interfaces for mesh systems.
 +
 +  There are three main mesh data structures in Blender: Mesh, CDDM, and BMesh.
 +  These, and a few others, all implement DerivedMesh interfaces, 
 +  which contains unified drawing interfaces, a few utility interfaces, 
 +  and a bunch of read-only interfaces intended mostly for conversion from 
 +  one format to another.
 +
 +  All Mesh structures in blender make use of CustomData, which is used to store
 +  per-element attributes and interpolate them (e.g. uvs, vcols, vgroups, etc).
 +  
 +  Mesh is the "serialized" structure, used for storing object-mode mesh data
 +  and also for saving stuff to disk.  It's interfaces are also what DerivedMesh
 +  uses to communicate with.
 +  
 +  CDDM is a little mesh library, that uses Mesh data structures in the backend.
 +  It's mostly used for modifiers, and has the advantages of not taking much
 +  resources.
 +
 +  BMesh is a full-on brep, used for editmode, some modifiers, etc.  It's much
 +  more capable (if memory-intensive) then CDDM.
 +
 +  DerivedMesh is somewhat hackish.  Many places assumes that a DerivedMesh is
 +  a CDDM (most of the time by simply copying it and converting it to one).
 +  CDDM is the original structure for modifiers, but has since been superseded
 +  by BMesh, at least for the foreseeable future.
 +*/
 +
 +/* 
 + * Note: This sturcture is read-only, for all practical purposes.
 + *       At some point in the future, we may want to consider
 + *       creating a replacement structure that implements a proper
 + *       abstract mesh kernel interface.  Or, we can leave this
 + *       as it is and stick with using BMesh and CDDM.
   */
  
 +
  #include "DNA_customdata_types.h"
 +#include "DNA_meshdata_types.h"
 +
  #include "BKE_customdata.h"
  #include "BKE_bvhutils.h"
  
@@@ -83,26 -55,20 +83,26 @@@ struct MTFace
  struct Object;
  struct Scene;
  struct Mesh;
 -struct EditMesh;
 +struct BMEditMesh;
  struct KeyBlock;
  struct ModifierData;
  struct MCol;
  struct ColorBand;
  struct GPUVertexAttribs;
  struct GPUDrawObject;
 +struct BMEditMesh;
  struct ListBase;
  struct PBVH;
  
  /* number of sub-elements each mesh element has (for interpolation) */
  #define SUB_ELEMS_VERT 0
  #define SUB_ELEMS_EDGE 2
 -#define SUB_ELEMS_FACE 4
 +#define SUB_ELEMS_FACE 50
 +
 +/*
 +Note: all mface interfaces now officially operate on tesselated data.
 +      Also, the mface origindex layer indexes mpolys, not mfaces.
 +*/
  
  typedef struct DMGridData {
        float co[3];
@@@ -116,15 -82,15 +116,15 @@@ typedef struct DMGridAdjacency 
  
  typedef enum DerivedMeshType {
        DM_TYPE_CDDM,
 -      DM_TYPE_EDITMESH,
 +      DM_TYPE_EDITBMESH,
        DM_TYPE_CCGDM
  } DerivedMeshType;
  
  typedef struct DerivedMesh DerivedMesh;
  struct DerivedMesh {
        /* Private DerivedMesh data, only for internal DerivedMesh use */
 -      CustomData vertData, edgeData, faceData;
 -      int numVertData, numEdgeData, numFaceData;
 +      CustomData vertData, edgeData, faceData, loopData, polyData;
 +      int numVertData, numEdgeData, numFaceData, numLoopData, numPolyData;
        int needsFree; /* checked on ->release, is set to 0 for cached results */
        int deformedOnly; /* set by modifier stack if only deformed from original */
        BVHCache bvhCache;
        DerivedMeshType type;
  
        /* Misc. Queries */
 +      
 +      /*recalculates mesh tesselation*/
 +      void (*recalcTesselation)(DerivedMesh *dm);
  
        /* Also called in Editmode */
        int (*getNumVerts)(DerivedMesh *dm);
 -      /* Also called in Editmode */
 -      int (*getNumFaces)(DerivedMesh *dm);
 -
        int (*getNumEdges)(DerivedMesh *dm);
 +      int (*getNumTessFaces)(DerivedMesh *dm);
 +      int (*getNumFaces) (DerivedMesh *dm);
  
 -      /* copy a single vert/edge/face from the derived mesh into
 +      /* copy a single vert/edge/tesselated face from the derived mesh into
         * *{vert/edge/face}_r. note that the current implementation
         * of this function can be quite slow, iterating over all
         * elements (editmesh)
         */
        void (*getVert)(DerivedMesh *dm, int index, struct MVert *vert_r);
        void (*getEdge)(DerivedMesh *dm, int index, struct MEdge *edge_r);
 -      void (*getFace)(DerivedMesh *dm, int index, struct MFace *face_r);
 +      void (*getTessFace)(DerivedMesh *dm, int index, struct MFace *face_r);
  
        /* return a pointer to the entire array of verts/edges/face from the
         * derived mesh. if such an array does not exist yet, it will be created,
         */
        struct MVert *(*getVertArray)(DerivedMesh *dm);
        struct MEdge *(*getEdgeArray)(DerivedMesh *dm);
 -      struct MFace *(*getFaceArray)(DerivedMesh *dm);
 +      struct MFace *(*getTessFaceArray)(DerivedMesh *dm);
 +      struct MLoop *(*getLoopArray)(DerivedMesh *dm);
 +      struct MPoly *(*getPolyArray)(DerivedMesh *dm);
  
        /* copy all verts/edges/faces from the derived mesh into
         * *{vert/edge/face}_r (must point to a buffer large enough)
         */
        void (*copyVertArray)(DerivedMesh *dm, struct MVert *vert_r);
        void (*copyEdgeArray)(DerivedMesh *dm, struct MEdge *edge_r);
 -      void (*copyFaceArray)(DerivedMesh *dm, struct MFace *face_r);
 +      void (*copyTessFaceArray)(DerivedMesh *dm, struct MFace *face_r);
 +              void (*copyLoopArray)(DerivedMesh *dm, struct MLoop *loop_r);
 +              void (*copyPolyArray)(DerivedMesh *dm, struct MPoly *poly_r);
  
        /* return a copy of all verts/edges/faces from the derived mesh
         * it is the caller's responsibility to free the returned pointer
         */
        struct MVert *(*dupVertArray)(DerivedMesh *dm);
        struct MEdge *(*dupEdgeArray)(DerivedMesh *dm);
 -      struct MFace *(*dupFaceArray)(DerivedMesh *dm);
 +      struct MFace *(*dupTessFaceArray)(DerivedMesh *dm);
 +              struct MLoop *(*dupLoopArray)(DerivedMesh *dm);
 +              struct MPoly *(*dupPolyArray)(DerivedMesh *dm);
  
        /* return a pointer to a single element of vert/edge/face custom data
         * from the derived mesh (this gives a pointer to the actual data, not
         */
        void *(*getVertData)(DerivedMesh *dm, int index, int type);
        void *(*getEdgeData)(DerivedMesh *dm, int index, int type);
 -      void *(*getFaceData)(DerivedMesh *dm, int index, int type);
 +      void *(*getTessFaceData)(DerivedMesh *dm, int index, int type);
  
        /* return a pointer to the entire array of vert/edge/face custom data
         * from the derived mesh (this gives a pointer to the actual data, not
         */
        void *(*getVertDataArray)(DerivedMesh *dm, int type);
        void *(*getEdgeDataArray)(DerivedMesh *dm, int type);
 -      void *(*getFaceDataArray)(DerivedMesh *dm, int type);
 -
 +      void *(*getTessFaceDataArray)(DerivedMesh *dm, int type);
 +      
 +      /*retrieves the base CustomData structures for 
 +        verts/edges/tessfaces/loops/facdes*/
 +      CustomData *(*getVertDataLayout)(DerivedMesh *dm);
 +      CustomData *(*getEdgeDataLayout)(DerivedMesh *dm);
 +      CustomData *(*getTessFaceDataLayout)(DerivedMesh *dm);
 +      CustomData *(*getLoopDataLayout)(DerivedMesh *dm);
 +      CustomData *(*getFaceDataLayout)(DerivedMesh *dm);
 +      
 +      /*copies all customdata for an element source into dst at index dest*/
 +      void (*copyFromVertCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
 +      void (*copyFromEdgeCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
 +      void (*copyFromFaceCData)(DerivedMesh *dm, int source, CustomData *dst, int dest);
 +      
        /* optional grid access for subsurf */
        int (*getNumGrids)(DerivedMesh *dm);
        int (*getGridSize)(DerivedMesh *dm);
         *  o Drawing options too complicated to enumerate, look at code.
         */
        void (*drawFacesTex)(DerivedMesh *dm,
 -                                               int (*setDrawOptions)(struct MTFace *tface,
 -                                               struct MCol *mcol, int matnr));
 +                           int (*setDrawOptions)(struct MTFace *tface,
 +                           int has_vcol, int matnr));
  
        /* Draw all faces with GLSL materials
         *  o setMaterial is called for every different material nr
                                                        int (*setDrawOptions)(void *userData, int index,
                                                                                                  int *drawSmooth_r),
                                                        void *userData, int useColors,
-                                                       int (*setMaterial)(int, void *attribs));
+                                                       int (*setMaterial)(int, void *attribs),
+                                                       int (*compareDrawOptions)(void *userData, int cur_index, int next_index));
  
        /* Draw mapped faces using MTFace 
         *  o Drawing options too complicated to enumerate, look at code.
@@@ -394,16 -340,15 +395,16 @@@ void DM_init_funcs(DerivedMesh *dm)
   * of vertices, edges and faces (doesn't allocate memory for them, just
   * sets up the custom data layers)
   */
 -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 numPolys);
  
  /* utility function to initialise a DerivedMesh for the desired number
   * of vertices, edges and faces, with a layer setup copied from source
   */
  void DM_from_template(DerivedMesh *dm, DerivedMesh *source,
 -                                        DerivedMeshType type,
 -                                        int numVerts, int numEdges, int numFaces);
 +                        DerivedMeshType type,
 +                        int numVerts, int numEdges, int numFaces,
 +                    int numLoops, int numPolys);
  
  /* utility function to release a DerivedMesh's layers
   * returns 1 if DerivedMesh has to be released by the backend, 0 otherwise
@@@ -412,7 -357,7 +413,7 @@@ int DM_release(DerivedMesh *dm)
  
  /* utility function to convert a DerivedMesh to a Mesh
   */
 -void DM_to_mesh(DerivedMesh *dm, struct Mesh *me);
 +void DM_to_mesh(DerivedMesh *dm, struct Mesh *me, struct Object *ob);
  
  /* utility function to convert a DerivedMesh to a shape key block 
   */
@@@ -433,8 -378,6 +434,8 @@@ void DM_add_vert_layer(struct DerivedMe
                                           void *layer);
  void DM_add_edge_layer(struct DerivedMesh *dm, int type, int alloctype,
                                           void *layer);
 +void DM_add_tessface_layer(struct DerivedMesh *dm, int type, int alloctype,
 +                       void *layer);
  void DM_add_face_layer(struct DerivedMesh *dm, int type, int alloctype,
                                           void *layer);
  
@@@ -454,7 -397,6 +455,7 @@@ void *DM_get_face_data(struct DerivedMe
   */
  void *DM_get_vert_data_layer(struct DerivedMesh *dm, int type);
  void *DM_get_edge_data_layer(struct DerivedMesh *dm, int type);
 +void *DM_get_tessface_data_layer(struct DerivedMesh *dm, int type);
  void *DM_get_face_data_layer(struct DerivedMesh *dm, int type);
  
  /* custom data setting functions
@@@ -473,10 -415,6 +474,10 @@@ void DM_copy_vert_data(struct DerivedMe
                                           int source_index, int dest_index, int count);
  void DM_copy_edge_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                                           int source_index, int dest_index, int count);
 +void DM_copy_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest,
 +                       int source_index, int dest_index, int count);
 +void DM_copy_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest,
 +                       int source_index, int dest_index, int count);
  void DM_copy_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                                           int source_index, int dest_index, int count);
  
   */
  void DM_free_vert_data(struct DerivedMesh *dm, int index, int count);
  void DM_free_edge_data(struct DerivedMesh *dm, int index, int count);
 +void DM_free_tessface_data(struct DerivedMesh *dm, int index, int count);
 +void DM_free_loop_data(struct DerivedMesh *dm, int index, int count);
  void DM_free_face_data(struct DerivedMesh *dm, int index, int count);
  
 +/*sets up mpolys for a DM based on face iterators in source*/
 +void DM_DupPolys(DerivedMesh *source, DerivedMesh *target);
 +
  /* interpolates vertex data from the vertices indexed by src_indices in the
   * source mesh using the given weights and stores the result in the vertex
   * indexed by dest_index in the dest mesh
@@@ -522,20 -455,12 +523,20 @@@ void DM_interp_edge_data(struct Derived
   * vert_weights[i] multiplied by weights[i].
   */
  typedef float FaceVertWeight[SUB_ELEMS_FACE][SUB_ELEMS_FACE];
 -void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
 +void DM_interp_tessface_data(struct DerivedMesh *source, struct DerivedMesh *dest,
                                                 int *src_indices,
                                                 float *weights, FaceVertWeight *vert_weights,
                                                 int count, int dest_index);
  
 -void DM_swap_face_data(struct DerivedMesh *dm, int index, const int *corner_indices);
 +void DM_swap_tessface_data(struct DerivedMesh *dm, int index, const int *corner_indices);
 +
 +void DM_interp_loop_data(struct DerivedMesh *source, struct DerivedMesh *dest,
 +                         int *src_indices,
 +                         float *weights, int count, int dest_index);
 +
 +void DM_interp_face_data(struct DerivedMesh *source, struct DerivedMesh *dest,
 +                         int *src_indices,
 +                         float *weights, int count, int dest_index);
  
  /* Temporary? A function to give a colorband to derivedmesh for vertexcolor ranges */
  void vDM_ColorBand_store(struct ColorBand *coba);
@@@ -551,15 -476,11 +552,15 @@@ DerivedMesh *mesh_get_derived_final(str
  DerivedMesh *mesh_get_derived_deform(struct Scene *scene, struct Object *ob,
                                                                         CustomDataMask dataMask);
  
 -DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object *ob, struct ModifierData *md);
 +DerivedMesh *mesh_create_derived_for_modifier(struct Scene *scene, struct Object *ob,
 +                                                                                        struct ModifierData *md, int build_shapekey_layers);
  
  DerivedMesh *mesh_create_derived_render(struct Scene *scene, struct Object *ob,
                                                                                CustomDataMask dataMask);
  
 +DerivedMesh *getEditDerivedBMesh(struct BMEditMesh *em, struct Object *ob,
 +                                           float (*vertexCos)[3]);
 +
  DerivedMesh *mesh_create_derived_index_render(struct Scene *scene, struct Object *ob, CustomDataMask dataMask, int index);
  
                /* same as above but wont use render settings */
@@@ -578,21 -499,20 +579,21 @@@ DerivedMesh *mesh_create_derived_no_vir
  DerivedMesh *mesh_create_derived_physics(struct Scene *scene, struct Object *ob, float (*vertCos)[3],
                                                                                        CustomDataMask dataMask);
  
 -DerivedMesh *editmesh_get_derived(struct EditMesh *em, float (*vertexCos)[3]);
 -DerivedMesh *editmesh_get_derived_base(struct Object *, struct EditMesh *em);
 -DerivedMesh *editmesh_get_derived_cage(struct Scene *scene, struct Object *, 
 -                                                                         struct EditMesh *em, CustomDataMask dataMask);
 -DerivedMesh *editmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *, 
 -                                                                                               struct EditMesh *em, DerivedMesh **final_r,
 +DerivedMesh *editbmesh_get_derived(struct BMEditMesh *em, float (*vertexCos)[3]);
 +DerivedMesh *editbmesh_get_derived_base(struct Object *, struct BMEditMesh *em);
 +DerivedMesh *editbmesh_get_derived_cage(struct Scene *scene, struct Object *, 
 +                                                                         struct BMEditMesh *em, CustomDataMask dataMask);
 +DerivedMesh *editbmesh_get_derived_cage_and_final(struct Scene *scene, struct Object *, 
 +                                               struct BMEditMesh *em, DerivedMesh **final_r,
                                                                                                 CustomDataMask dataMask);
 -float (*editmesh_get_vertex_cos(struct EditMesh *em, int *numVerts_r))[3];
 -int editmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
 -void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct EditMesh *em, CustomDataMask dataMask);
 +float (*editbmesh_get_vertex_cos(struct BMEditMesh *em, int *numVerts_r))[3];
 +int editbmesh_modifier_is_enabled(struct Scene *scene, struct ModifierData *md, DerivedMesh *dm);
 +void makeDerivedMesh(struct Scene *scene, struct Object *ob, struct BMEditMesh *em, 
 +      CustomDataMask dataMask, int build_shapekey_layers);
  
  /* returns an array of deform matrices for crazyspace correction, and the
     number of modifiers left */
 -int editmesh_get_first_deform_matrices(struct Scene *, struct Object *, struct EditMesh *em,
 +int editbmesh_get_first_deform_matrices(struct Scene *, struct Object *, struct BMEditMesh *em,
                                                                           float (**deformmats)[3][3], float (**deformcos)[3]);
  
  /* returns an array of deform matrices for crazyspace correction when sculpting,
index e517f4ae7b105ead0525efeef96a650ef6a1b551,5eb97630e83d16fd03ddde1018b2cd846e4b27bd..ad70e00a33ce1f350a47ace908c4b3ada52d3022
@@@ -1,4 -1,4 +1,4 @@@
 -/*
 + /*
  * $Id$
  *
  * ***** BEGIN GPL LICENSE BLOCK *****
  #include <string.h>
  #include "BIF_gl.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"
@@@ -89,8 -77,6 +89,8 @@@ typedef struct 
        MVert *mvert;
        MEdge *medge;
        MFace *mface;
 +      MLoop *mloop;
 +      MPoly *mpoly;
  
        /* Cached */
        struct PBVH *pbvh;
@@@ -112,16 -98,11 +112,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;
@@@ -158,18 -139,6 +158,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;
@@@ -328,7 -297,7 +328,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) {
@@@ -499,7 -468,7 +499,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) {                                             \
@@@ -681,21 -650,21 +681,21 @@@ static void cdDM_drawFacesColored(Deriv
  }
  
  static void cdDM_drawFacesTex_common(DerivedMesh *dm,
 -                         int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
 -                         int (*drawParamsMapped)(void *userData, int index),
 -                         void *userData) 
 +               int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
 +               int (*drawParamsMapped)(void *userData, int index),
 +               void *userData) 
  {
        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);
  
                        unsigned char *cp = NULL;
  
                        if(drawParams) {
 -                              flag = drawParams(tf? &tf[i]: NULL, mcol? &mcol[i*4]: NULL, mf->mat_nr);
 +                              flag = drawParams(tf? &tf[i]: NULL, mcol!=NULL, mf->mat_nr);
                        }
                        else {
                                if(index) {
                        }
                        
                        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;
                                                colors[i*12+j*3+1] = col[i*4+j].g;
                                int flag = 1;
  
                                if(drawParams) {
 -                                      flag = drawParams(tf? &tf[actualFace]: NULL, mcol? &mcol[actualFace*4]: NULL, mf[actualFace].mat_nr);
 +                                      flag = drawParams(tf? &tf[actualFace]: NULL, mcol!=NULL, mf[actualFace].mat_nr);
                                }
                                else {
                                        if(index) {
        }
  }
  
 -static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
 +static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
  {
        cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
  }
  
- static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs))
+ static void cdDM_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))
  {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        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;
                }
                                        MFace *mface= mf + actualFace;
                                        int drawSmooth= (mface->flag & ME_SMOOTH);
                                        int draw = 1;
+                                       int flush = 0;
  
                                        if(i != tottri-1)
                                                next_actualFace= dm->drawObject->triangle_to_mface[i+1];
                                        /* Goal is to draw as long of a contiguous triangle
                                           array as possible, so draw when we hit either an
                                           invisible triangle or at the end of the array */
-                                       if(!draw || i == tottri - 1 || mf[actualFace].mat_nr != mf[next_actualFace].mat_nr) {
-                                               if(prevstart != i)
-                                                       /* Add one to the length (via `draw')
-                                                          if we're drawing at the end of the array */
-                                                       glDrawArrays(GL_TRIANGLES,prevstart*3, (i-prevstart+draw)*3);
+                                       /* flush buffer if current triangle isn't drawable or it's last triangle... */
+                                       flush= !draw || i == tottri - 1;
+                                       /* ... or when material setting is dissferent  */
+                                       flush|= mf[actualFace].mat_nr != mf[next_actualFace].mat_nr;
+                                       if(!flush && compareDrawOptions) {
+                                               int next_orig= (index==NULL) ? next_actualFace : index[next_actualFace];
+                                               /* also compare draw options and flush buffer if they're different
+                                                  need for face selection highlight in edit mode */
+                                               flush|= compareDrawOptions(userData, orig, next_orig) == 0;
+                                       }
+                                       if(flush) {
+                                               int first= prevstart*3;
+                                               int count= (i-prevstart+(draw ? 1 : 0))*3; /* Add one to the length if we're drawing at the end of the array */
+                                               if(count)
+                                                       glDrawArrays(GL_TRIANGLES, first, count);
                                                prevstart = i + 1;
                                        }
                                }
@@@ -1026,7 -1012,6 +1045,7 @@@ static void cdDM_drawMappedFacesTex(Der
        cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
  }
  
 +
  static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, MVert *mvert, int a, int index, int vert, int smoothnormal)
  {
        int b;
        /* vertex normal */
        if(smoothnormal)
                glNormal3sv(mvert[index].no);
 -      
 +
        /* vertex coordinate */
        glVertex3fv(mvert[index].co);
  }
  
 +
  static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData)
  {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        DMVertexAttribs attribs;
        MVert *mvert = cddm->mvert;
        MFace *mface = cddm->mface;
 -      MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
 -      float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
 +      MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
 +      float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
        int a, b, dodraw, matnr, new_matnr;
        int transp, new_transp, orig_transp;
 -      int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
 +      int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
  
        cdDM_update_normals_from_pbvh(dm);
  
                        cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v1, 0, smoothnormal);
                        cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v2, 1, smoothnormal);
                        cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v3, 2, smoothnormal);
 -
                        if(mface->v4)
                                cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v4, 3, smoothnormal);
                        else
                                cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v3, 2, smoothnormal);
 +
                }
                glEnd();
        }
@@@ -1487,72 -1471,35 +1506,72 @@@ 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];
  
                if (index) {
                        orig = *index++;
                        if(orig == ORIGINDEX_NONE) continue;
 -              }
 -              else
 +              } 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)
@@@ -1571,11 -1518,6 +1590,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;
  }
@@@ -1677,8 -1608,7 +1696,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];
@@@ -1817,17 -1736,15 +1836,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);
 +              med->flag = ME_EDGEDRAW|ME_EDGERENDER;
 +
 +              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;
  }
@@@ -2174,228 -1859,22 +2193,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)
@@@ -2564,7 -1966,7 +2583,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];
  }
@@@ -2579,125 -1981,8 +2598,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 9098ce248e09d5d1b81dcb6e540dc1d45117f126,0000000000000000000000000000000000000000..bd9bbf7646a2d0ba61635ac10aafb306f1487257
mode 100644,000000..100644
--- /dev/null
@@@ -1,1589 -1,0 +1,1594 @@@
-       int (*setMaterial)(int, void *attribs))
 +/**
 + * $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 "BIF_gl.h"
 +#include "BIF_glutil.h"
 +
 +#include "GPU_draw.h"
 +#include "GPU_extensions.h"
 +#include "GPU_material.h"
 +
 +#include "bmesh.h"
 +
 +BMEditMesh *BMEdit_Create(BMesh *bm)
 +{
 +      BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), "tm");
 +      
 +      tm->bm = bm;
 +
 +      BMEdit_RecalcTesselation(tm);
 +
 +      return tm;
 +}
 +
 +BMEditMesh *BMEdit_Copy(BMEditMesh *tm)
 +{
 +      BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), "tm2");
 +      *tm2 = *tm;
 +      
 +      tm2->derivedCage = tm2->derivedFinal = NULL;
 +      
 +      tm2->looptris = NULL;
 +      tm2->bm = BM_Copy_Mesh(tm->bm);
 +      BMEdit_RecalcTesselation(tm2);
 +
 +      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, 
-       (void)setMaterial;
++      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;
 +
 +      /*BMESH_TODO*/
 +      (void)useColors;
++
++      (void)setMaterial; /* UNUSED */
++
++      /* currently unused -- each original face is handled separately */
++      (void)compareDrawOptions;
 +
 +      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);
 +
 +              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) {
 +                              if (draw==2) { /* enabled with stipple */
 +                                      glEnable(GL_POLYGON_STIPPLE);
 +                                      glPolygonStipple(stipple_quarttone);
 +                              }
 +                              
 +                              glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +
 +                              glBegin(GL_TRIANGLES);
 +
 +                              if (!drawSmooth) {
 +                                      glNormal3fv(bmdm->faceNos[i]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(l[0]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(l[1]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(l[2]->v)]);
 +                              } else {
 +                                      glNormal3fv(bmdm->vertexNos[(int) BM_GetIndex(l[0]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(l[0]->v)]);
 +                                      glNormal3fv(bmdm->vertexNos[(int) BM_GetIndex(l[1]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(l[1]->v)]);
 +                                      glNormal3fv(bmdm->vertexNos[(int) BM_GetIndex(l[2]->v)]);
 +                                      glVertex3fv(bmdm->vertexCos[(int) BM_GetIndex(l[2]->v)]);
 +                              }
 +                              glEnd();
 +
 +                              if (draw==2)
 +                                      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) {
 +                              if (draw==2) { /* enabled with stipple */
 +                                      glEnable(GL_POLYGON_STIPPLE);
 +                                      glPolygonStipple(stipple_quarttone);
 +                              }
 +                              glShadeModel(drawSmooth?GL_SMOOTH:GL_FLAT);
 +                              
 +                              glBegin(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);
 +                              }
 +                              glEnd();
 +                              
 +                              if (draw==2)
 +                                      glDisable(GL_POLYGON_STIPPLE);
 +                      }
 +              }
 +      }
 +}
 +
 +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;
 +      MTexPoly *tp;
 +      int transp, new_transp, orig_transp;
 +      int i, b, matnr, new_matnr, dodraw;
 +
 +      dodraw = 0;
 +      matnr = -1;
 +
 +      transp = GPU_get_material_blend_mode();
 +      orig_transp = transp;
 +
 +      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(attribs.tottface) {
 +                      tp = CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_MTEXPOLY);
 +                      new_transp = tp->transp;
 +
 +                      if(new_transp != transp) {
 +                              if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
 +                                      GPU_set_material_blend_mode(orig_transp);
 +                              else
 +                                      GPU_set_material_blend_mode(new_transp);
 +                              transp = new_transp;
 +                      }
 +              }
 +
 +              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)
 +{
 +      VECCOPY(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 = ME_EDGEDRAW|ME_EDGERENDER;
 +      edge_r->flag |= BMFlags_To_MEFlags(e);
 +#if 0
 +      /* this needs setup of f2 field */
 +      if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
 +#endif
 +      
 +      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) {
 +              VECCOPY(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)) {
 +              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 = ME_EDGEDRAW|ME_EDGERENDER;
 +              if (ee->head.flag & BM_SEAM) edge_r->flag |= ME_SEAM;
 +              if (ee->head.flag & BM_SHARP) edge_r->flag |= ME_SHARP;
 +#if 0
 +              /* this needs setup of f2 (edge draw flags, if I remember right) field */
 +              if (!ee->f2) edge_r->flag |= ME_LOOSEEDGE;
 +#endif
 +
 +              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 */
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for (i=0; ev; ev=BMIter_Step(&iter), i++)
 +              BM_SetIndex(ev, i);
 +
 +      for (i=0; i<bmdm->tc->tottri; i++) {
 +              l = bmdm->tc->looptris[i];
 +              ef = l[0]->f;
 +
 +              face_r->mat_nr = (unsigned char) ef->mat_nr;
 +
 +              /*HACK/BMESH_TODO: need to convert this*/
 +              face_r->flag = ef->head.flag;
 +
 +              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++);
 +      }
 +
 +      i = 0;
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
 +                      loop_r[i].v = BM_GetIndex(l->v);
 +                      loop_r[i].e = BM_GetIndex(l->e);
 +                      i++;
 +              }
 +      }
 +}
 +
 +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, j;
 +
 +      i = j = 0;
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              poly_r[i].flag = BMFlags_To_MEFlags(f);
 +              poly_r[i].loopstart = j;
 +              poly_r[i].totloop = f->len;
 +              poly_r[i].mat_nr = f->mat_nr;
 +
 +              i++;
 +              j += 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, 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;
 +                      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), "bmdm");
 +      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) {
 +                              VECCOPY(no, vertexCos[i]);
 +                              normalize_v3(no);
 +                      }
 +              }
 +      }
 +
 +      //bmdm_recalc_lookups(bmdm);
 +
 +      return (DerivedMesh*) bmdm;
 +}
index 5a96ce295fbf4f06fd7232540e0ea42e1058cce9,186a5ea1852926ed30427b60e44b88806a04f7d1..429323e38dd1a70122447f8a8a169b1ebb66f4c0
  #include "DNA_object_types.h"
  #include "DNA_scene_types.h"
  
 +#include "BLI_utildefines.h"
  #include "BLI_blenlib.h"
  #include "BLI_edgehash.h"
  #include "BLI_math.h"
  #include "BLI_memarena.h"
  #include "BLI_pbvh.h"
 -#include "BLI_utildefines.h"
  
  #include "BKE_cdderivedmesh.h"
  #include "BKE_global.h"
  #include "BKE_paint.h"
  #include "BKE_scene.h"
  #include "BKE_subsurf.h"
 +#include "BKE_tessmesh.h"
  
 +#include "PIL_time.h"
 +#include "BLI_array.h"
  
  #include "BIF_gl.h"
  #include "BIF_glutil.h"
  
  #include "CCGSubSurf.h"
  
 -static int ccgDM_getVertMapIndex(CCGSubSurf *ss, CCGVert *v);
 -static int ccgDM_getEdgeMapIndex(CCGSubSurf *ss, CCGEdge *e);
 -static int ccgDM_getFaceMapIndex(CCGSubSurf *ss, CCGFace *f);
 +static CCGDerivedMesh *getCCGDerivedMesh(CCGSubSurf *ss,
 +                                         int drawInteriorEdges,
 +                                         int useSubsurfUv,
 +                                         DerivedMesh *dm);
  static int ccgDM_use_grid_pbvh(CCGDerivedMesh *ccgdm);
  
  ///
@@@ -165,8 -161,7 +165,8 @@@ static int getEdgeIndex(CCGSubSurf *ss
                return edgeBase + x-1;
        }
  }
 -static int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) {
 +
 +BM_INLINE int getFaceIndex(CCGSubSurf *ss, CCGFace *f, int S, int x, int y, int edgeSize, int gridSize) {
        int faceBase = *((int*) ccgSubSurf_getFaceUserData(ss, f));
        int numVerts = ccgSubSurf_getFaceNumVerts(f);
  
@@@ -221,16 -216,10 +221,16 @@@ static void get_face_uv_map_vert(UvVert
  }
  
  static int ss_sync_from_uv(CCGSubSurf *ss, CCGSubSurf *origss, DerivedMesh *dm, MTFace *tface) {
 -      MFace *mface = dm->getFaceArray(dm);
 +#if 1 /*BMESH_TODO*/
 +      (void)ss;
 +      (void)origss;
 +      (void)dm;
 +      (void)tface;
 +#else
 +      MFace *mface = dm->getTessFaceArray(dm);
        MVert *mvert = dm->getVertArray(dm);
        int totvert = dm->getNumVerts(dm);
 -      int totface = dm->getNumFaces(dm);
 +      int totface = dm->getNumTessFaces(dm);
        int i, j, seam;
        UvMapVert *v;
        UvVertMap *vmap;
        free_uv_vert_map(vmap);
        ccgSubSurf_processSync(ss);
  
 +#endif
        return 1;
  }
  
@@@ -394,123 -382,65 +394,123 @@@ static void set_subsurf_uv(CCGSubSurf *
  }
  
  /* face weighting */
 -static void calc_ss_weights(int gridFaces,
 -                                                      FaceVertWeight **qweight, FaceVertWeight **tweight)
 +typedef struct FaceVertWeightEntry {
 +      FaceVertWeight *weight;
 +      float *w;
 +      int valid;
 +} FaceVertWeightEntry;
 +
 +typedef struct WeightTable {
 +      FaceVertWeightEntry *weight_table;
 +      int len;
 +} WeightTable;
 +
 +static float *get_ss_weights(WeightTable *wtable, int gridCuts, int faceLen)
  {
 -      FaceVertWeight *qw, *tw;
 -      int x, y, j;
 -      int numWeights = gridFaces * gridFaces;
 -
 -      *tweight = MEM_mallocN(sizeof(**tweight) * numWeights, "ssTriWeight");
 -      *qweight = MEM_mallocN(sizeof(**qweight) * numWeights, "ssQuadWeight");
 -
 -      qw = *qweight;
 -      tw = *tweight;
 -
 -      for (y = 0; y < gridFaces; y++) {
 -              for (x = 0; x < gridFaces; x++) {
 -                      for (j = 0; j < 4; j++) {
 -                              int fx = x + (j == 2 || j == 3);
 -                              int fy = y + (j == 1 || j == 2);
 -                              float x_v = (float) fx / gridFaces;
 -                              float y_v = (float) fy / gridFaces;
 -                              float tx_v = (1.0f - x_v), ty_v = (1.0f - y_v);
 -                              float center = (1.0f / 3.0f) * tx_v * ty_v;
 -
 -                              (*tw)[j][0] = center + 0.5f * tx_v * y_v;
 -                              (*tw)[j][2] = center + 0.5f * x_v * ty_v;
 -                              (*tw)[j][1] = 1.0f - (*tw)[j][0] - (*tw)[j][2];
 -                              (*tw)[j][3] = 0.0f;
 -
 -                              tx_v *= 0.5f;
 -                              ty_v *= 0.5f;
 -
 -                              (*qw)[j][3] = tx_v * ty_v;
 -                              (*qw)[j][0] = (*qw)[j][3] + tx_v * y_v;
 -                              (*qw)[j][2] = (*qw)[j][3] + x_v * ty_v;
 -                              (*qw)[j][1] = 1.0f - (*qw)[j][0] - (*qw)[j][2] - (*qw)[j][3];
 +      int x, y, i, j;
 +      float *w, w1, w2, w4, fac, fac2, fx, fy;
 +
 +      if (wtable->len <= faceLen) {
 +              void *tmp = MEM_callocN(sizeof(FaceVertWeightEntry)*(faceLen+1), "weight table alloc 2");
 +              
 +              if (wtable->len) {
 +                      memcpy(tmp, wtable->weight_table, sizeof(FaceVertWeightEntry)*wtable->len);
 +                      MEM_freeN(wtable->weight_table);
 +              }
 +              
 +              wtable->weight_table = tmp;
 +              wtable->len = faceLen+1;
 +      }
 +
 +      if (!wtable->weight_table[faceLen].valid) {
 +              wtable->weight_table[faceLen].valid = 1;
 +              wtable->weight_table[faceLen].w = w = MEM_callocN(sizeof(float)*faceLen*faceLen*(gridCuts+2)*(gridCuts+2), "weight table alloc");
 +              fac = 1.0f / (float)faceLen;
  
 +              for (i=0; i<faceLen; i++) {
 +                      for (x=0; x<gridCuts+2; x++) {
 +                              for (y=0; y<gridCuts+2; y++) {
 +                                      fx = 0.5f - (float)x / (float)(gridCuts+1) / 2.0f;
 +                                      fy = 0.5f - (float)y / (float)(gridCuts+1) / 2.0f;
 +                              
 +                                      fac2 = faceLen - 4;
 +                                      w1 = (1.0f - fx) * (1.0f - fy) + (-fac2*fx*fy*fac);
 +                                      w2 = (1.0f - fx + fac2*fx*-fac) * (fy);
 +                                      w4 = (fx) * (1.0f - fy + -fac2*fy*fac);
 +                                      
 +                                      fac2 = 1.0f - (w1+w2+w4);
 +                                      fac2 = fac2 / (float)(faceLen-3);
 +                                      for (j=0; j<faceLen; j++)
 +                                              w[j] = fac2;
 +                                      
 +                                      w[i] = w1;
 +                                      w[(i-1+faceLen)%faceLen] = w2;
 +                                      w[(i+1)%faceLen] = w4;
 +
 +                                      w += faceLen;
 +                              }
                        }
 -                      tw++;
 -                      qw++;
                }
        }
 +
 +      return wtable->weight_table[faceLen].w;
 +}
 +
 +static void free_ss_weights(WeightTable *wtable)
 +{
 +      int i;
 +
 +      for (i=0; i<wtable->len; i++) {
 +              if (wtable->weight_table[i].valid)
 +                      MEM_freeN(wtable->weight_table[i].w);
 +      }
 +      
 +      if (wtable->weight_table)
 +              MEM_freeN(wtable->weight_table);
 +}
 +
 +#if 0
 +static DerivedMesh *ss_to_cdderivedmesh(CCGSubSurf *ss, int ssFromEditmesh,
 +                                                               int drawInteriorEdges, int useSubsurfUv,
 +                                                               DerivedMesh *dm, struct MultiresSubsurf *ms)
 +{
 +      DerivedMesh *cgdm, *result;
 +      double curt = PIL_check_seconds_timer();
 +
 +      cgdm = getCCGDerivedMesh(ss, drawInteriorEdges, useSubsurfUv, dm);
 +      result = CDDM_copy(cgdm, 1);
 +
 +      printf("subsurf conversion time: %.6lf\n", PIL_check_seconds_timer() - curt);
 +
 +      cgdm->needsFree = 1;
 +      cgdm->release(cgdm);
 +
 +      CDDM_calc_normals(result);
 +
 +      return result;
  }
 +#endif
  
 -static void ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
 +static int ss_sync_from_derivedmesh(CCGSubSurf *ss, DerivedMesh *dm,
                                                                         float (*vertexCos)[3], int useFlatSubdiv)
  {
        float creaseFactor = (float) ccgSubSurf_getSubdivisionLevels(ss);
 -      CCGVertHDL fVerts[4];
 -      int totvert = dm->getNumVerts(dm);
 -      int totedge = dm->getNumEdges(dm);
 -      int totface = dm->getNumFaces(dm);
 -      int i;
 -      int *index;
 +      CCGVertHDL *fVerts = NULL;
 +      BLI_array_declare(fVerts);
        MVert *mvert = dm->getVertArray(dm);
        MEdge *medge = dm->getEdgeArray(dm);
 -      MFace *mface = dm->getFaceArray(dm);
 +      /* MFace *mface = dm->getTessFaceArray(dm); */ /* UNUSED */
        MVert *mv;
        MEdge *me;
 -      MFace *mf;
 +      MLoop *mloop = dm->getLoopArray(dm), *ml;
 +      MPoly *mpoly = dm->getPolyArray(dm), *mp;
 +      /*MFace *mf;*/ /*UNUSED*/
 +      int totvert = dm->getNumVerts(dm);
 +      int totedge = dm->getNumEdges(dm);
 +      /*int totface = dm->getNumTessFaces(dm);*/ /*UNUSED*/
 +      /*int totpoly = dm->getNumFaces(dm);*/ /*UNUSED*/
 +      int i, j;
 +      int *index;
  
        ccgSubSurf_initFullSync(ss);
  
                ((int*)ccgSubSurf_getEdgeUserData(ss, e))[1] = (index)? *index++: i;
        }
  
 -      mf = mface;
 -      index = (int *)dm->getFaceDataArray(dm, CD_ORIGINDEX);
 -      for (i = 0; i < totface; i++, mf++) {
 -              CCGFace *f;
 +      mp = mpoly;
 +      index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
 +      for (i=0; i<dm->numPolyData; i++, mp++) {
 +              CCGFace *f=NULL;
  
 -              fVerts[0] = SET_INT_IN_POINTER(mf->v1);
 -              fVerts[1] = SET_INT_IN_POINTER(mf->v2);
 -              fVerts[2] = SET_INT_IN_POINTER(mf->v3);
 -              fVerts[3] = SET_INT_IN_POINTER(mf->v4);
 +              BLI_array_empty(fVerts);
  
 -              // this is very bad, means mesh is internally consistent.
 -              // it is not really possible to continue without modifying
 -              // other parts of code significantly to handle missing faces.
 -              // since this really shouldn't even be possible we just bail.
 -              if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), fVerts[3] ? 4 : 3,
 +              ml = mloop + mp->loopstart;
 +              for (j=0; j<mp->totloop; j++, ml++) {
 +                      BLI_array_append(fVerts, SET_INT_IN_POINTER(ml->v));
 +              }
 +
 +              /* this is very bad, means mesh is internally inconsistent.
 +               * it is not really possible to continue without modifying
 +               * other parts of code significantly to handle missing faces.
 +               * since this really shouldn't even be possible we just bail.*/
 +              if(ccgSubSurf_syncFace(ss, SET_INT_IN_POINTER(i), mp->totloop,
                                                           fVerts, &f) == eCCGError_InvalidValue) {
                        static int hasGivenError = 0;
  
                        if(!hasGivenError) {
 -                              //XXX error("Unrecoverable error in SubSurf calculation,"
 -                              //      " mesh is inconsistent.");
 +                              printf("Unrecoverable error in SubSurf calculation,"
 +                                         " mesh is inconsistent.\n");
  
                                hasGivenError = 1;
                        }
  
 -                      return;
 +                      return 0;
                }
  
 -              ((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = (index)? *index++: i;
 +              ((int*)ccgSubSurf_getFaceUserData(ss, f))[1] = index ? *index++: i;
        }
  
        ccgSubSurf_processSync(ss);
 +
 +      BLI_array_free(fVerts);
 +      return 1;
  }
  
  /***/
@@@ -596,9 -521,9 +596,9 @@@ static int ccgDM_getFaceMapIndex(CCGSub
        return ((int*) ccgSubSurf_getFaceUserData(ss, f))[1];
  }
  
 -static void ccgDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void cgdm_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3]) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGVertIterator *vi = ccgSubSurf_getVertIterator(ss);
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
        ccgEdgeIterator_free(ei);
        ccgVertIterator_free(vi);
  }
 -static int ccgDM_getNumVerts(DerivedMesh *dm) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 +static int cgdm_getNumVerts(DerivedMesh *dm) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
  
 -      return ccgSubSurf_getNumFinalVerts(ccgdm->ss);
 +      return ccgSubSurf_getNumFinalVerts(cgdm->ss);
  }
 -static int ccgDM_getNumEdges(DerivedMesh *dm) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 +static int cgdm_getNumEdges(DerivedMesh *dm) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
  
 -      return ccgSubSurf_getNumFinalEdges(ccgdm->ss);
 +      return ccgSubSurf_getNumFinalEdges(cgdm->ss);
  }
 -static int ccgDM_getNumFaces(DerivedMesh *dm) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 +static int cgdm_getNumTessFaces(DerivedMesh *dm) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
  
 -      return ccgSubSurf_getNumFinalFaces(ccgdm->ss);
 +      return ccgSubSurf_getNumFinalFaces(cgdm->ss);
  }
  
  static void ccgDM_getFinalVert(DerivedMesh *dm, int vertNum, MVert *mv)
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        DMGridData *vd;
        int i;
  
        memset(mv, 0, sizeof(*mv));
  
 -      if((vertNum < ccgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
 +      if((vertNum < cgdm->edgeMap[0].startVert) && (ccgSubSurf_getNumFaces(ss) > 0)) {
                /* this vert comes from face data */
                int lastface = ccgSubSurf_getNumFaces(ss) - 1;
                CCGFace *f;
                int gridInternalEnd;
  
                i = 0;
 -              while(i < lastface && vertNum >= ccgdm->faceMap[i + 1].startVert)
 +              while(i < lastface && vertNum >= cgdm->faceMap[i + 1].startVert)
                        ++i;
  
 -              f = ccgdm->faceMap[i].face;
 +              f = cgdm->faceMap[i].face;
                numVerts = ccgSubSurf_getFaceNumVerts(f);
  
                gridSideVerts = gridSize - 2;
                gridSideEnd = 1 + numVerts * gridSideVerts;
                gridInternalEnd = gridSideEnd + numVerts * gridInternalVerts;
  
 -              offset = vertNum - ccgdm->faceMap[i].startVert;
 +              offset = vertNum - cgdm->faceMap[i].startVert;
                if(offset < 1) {
                        vd = ccgSubSurf_getFaceCenterData(f);
                        copy_v3_v3(mv->co, vd->co);
                        copy_v3_v3(mv->co, vd->co);
                        normal_float_to_short_v3(mv->no, vd->no);
                }
 -      } else if((vertNum < ccgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
 +      } else if((vertNum < cgdm->vertMap[0].startVert) && (ccgSubSurf_getNumEdges(ss) > 0)) {
                /* this vert comes from edge data */
                CCGEdge *e;
                int lastedge = ccgSubSurf_getNumEdges(ss) - 1;
                int x;
  
                i = 0;
 -              while(i < lastedge && vertNum >= ccgdm->edgeMap[i + 1].startVert)
 +              while(i < lastedge && vertNum >= cgdm->edgeMap[i + 1].startVert)
                        ++i;
  
 -              e = ccgdm->edgeMap[i].edge;
 +              e = cgdm->edgeMap[i].edge;
  
 -              x = vertNum - ccgdm->edgeMap[i].startVert + 1;
 +              x = vertNum - cgdm->edgeMap[i].startVert + 1;
                vd = ccgSubSurf_getEdgeData(ss, e, x);
                copy_v3_v3(mv->co, vd->co);
                normal_float_to_short_v3(mv->no, vd->no);
        } else {
                /* this vert comes from vert data */
                CCGVert *v;
 -              i = vertNum - ccgdm->vertMap[0].startVert;
 +              i = vertNum - cgdm->vertMap[0].startVert;
  
 -              v = ccgdm->vertMap[i].vert;
 +              v = cgdm->vertMap[i].vert;
                vd = ccgSubSurf_getVertData(ss, v);
                copy_v3_v3(mv->co, vd->co);
                normal_float_to_short_v3(mv->no, vd->no);
@@@ -758,13 -683,13 +758,13 @@@ static void ccgDM_getFinalVertNo(Derive
  
  static void ccgDM_getFinalEdge(DerivedMesh *dm, int edgeNum, MEdge *med)
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        int i;
  
        memset(med, 0, sizeof(*med));
  
 -      if(edgeNum < ccgdm->edgeMap[0].startEdge) {
 +      if(edgeNum < cgdm->edgeMap[0].startEdge) {
                /* this edge comes from face data */
                int lastface = ccgSubSurf_getNumFaces(ss) - 1;
                CCGFace *f;
                int edgeSize = ccgSubSurf_getEdgeSize(ss);
                int gridSideEdges;
                int gridInternalEdges;
 +                              int lasti, previ;
 +
 +                              i = lastface;
 +                              lasti = 0;
 +                              while (1) {
 +                                      previ = i;
 +                                      if (cgdm->faceMap[i].startEdge >= edgeNum) {
 +                                              i -= fabsf(i-lasti)/2.0f;
 +                                      } else if (cgdm->faceMap[i].startEdge < edgeNum) {
 +                                              i += fabsf(i-lasti)/2.0f;
 +                                      } else {
 +                                              break;
 +                                      }
  
 -              i = 0;
 -              while(i < lastface && edgeNum >= ccgdm->faceMap[i + 1].startEdge)
 +                                      if (i < 0) {
 +                                              i = 0;
 +                                              break;
 +                                      }
 +
 +                                      if (i > lastface) {
 +                                              i = lastface;
 +                                              break;
 +
 +                                      }
 +
 +                                      if (i == lasti)
 +                                         break;
 +
 +                                      lasti = previ;
 +                              }
 +
 +                              i = i > 0 ? i - 1 : i;
 +              while(i < lastface && edgeNum >= cgdm->faceMap[i + 1].startEdge)
                        ++i;
  
 -              f = ccgdm->faceMap[i].face;
 +              f = cgdm->faceMap[i].face;
                /* numVerts = ccgSubSurf_getFaceNumVerts(f); */ /*UNUSED*/
  
                gridSideEdges = gridSize - 1;
                gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; 
  
 -              offset = edgeNum - ccgdm->faceMap[i].startEdge;
 +              offset = edgeNum - cgdm->faceMap[i].startEdge;
                grid = offset / (gridSideEdges + gridInternalEdges);
                offset %= (gridSideEdges + gridInternalEdges);
  
                short *edgeFlag;
                unsigned int flags = 0;
  
 -              i = (edgeNum - ccgdm->edgeMap[0].startEdge) / (edgeSize - 1);
 +              i = (edgeNum - cgdm->edgeMap[0].startEdge) / (edgeSize - 1);
  
 -              e = ccgdm->edgeMap[i].edge;
 +              e = cgdm->edgeMap[i].edge;
  
                if(!ccgSubSurf_getEdgeNumFaces(e)) flags |= ME_LOOSEEDGE;
  
 -              x = edgeNum - ccgdm->edgeMap[i].startEdge;
 +              x = edgeNum - cgdm->edgeMap[i].startEdge;
  
                med->v1 = getEdgeIndex(ss, e, x, edgeSize);
                med->v2 = getEdgeIndex(ss, e, x+1, edgeSize);
  
 -              edgeFlag = (ccgdm->edgeFlags)? &ccgdm->edgeFlags[i]: NULL;
 +              edgeFlag = (cgdm->edgeFlags)? &cgdm->edgeFlags[i]: NULL;
                if(edgeFlag)
                        flags |= (*edgeFlag & (ME_SEAM | ME_SHARP))
                                         | ME_EDGEDRAW | ME_EDGERENDER;
  
  static void ccgDM_getFinalFace(DerivedMesh *dm, int faceNum, MFace *mf)
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        int gridSize = ccgSubSurf_getGridSize(ss);
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int gridSideEdges = gridSize - 1;
        int offset;
        int grid;
        int x, y;
 -      int lastface = ccgSubSurf_getNumFaces(ss) - 1;
 -      char *faceFlags = ccgdm->faceFlags;
 +      /*int lastface = ccgSubSurf_getNumFaces(ss) - 1;*/ /*UNUSED*/
 +      char *faceFlags = cgdm->faceFlags;
  
        memset(mf, 0, sizeof(*mf));
 +      if (faceNum >= cgdm->dm.numFaceData)
 +              return;
  
 -      i = 0;
 -      while(i < lastface && faceNum >= ccgdm->faceMap[i + 1].startFace)
 -              ++i;
 +      i = cgdm->reverseFaceMap[faceNum];
  
 -      f = ccgdm->faceMap[i].face;
 +      f = cgdm->faceMap[i].face;
        /*numVerts = ccgSubSurf_getFaceNumVerts(f);*/ /*UNUSED*/
  
 -      offset = faceNum - ccgdm->faceMap[i].startFace;
 +      offset = faceNum - cgdm->faceMap[i].startFace;
        grid = offset / gridFaces;
        offset %= gridFaces;
        y = offset / gridSideEdges;
  
  static void ccgDM_copyFinalVertArray(DerivedMesh *dm, MVert *mvert)
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        DMGridData *vd;
        int index;
        int totvert, totedge, totface;
  
        totface = ccgSubSurf_getNumFaces(ss);
        for(index = 0; index < totface; index++) {
 -              CCGFace *f = ccgdm->faceMap[index].face;
 +              CCGFace *f = cgdm->faceMap[index].face;
                int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
  
                vd= ccgSubSurf_getFaceCenterData(f);
  
        totedge = ccgSubSurf_getNumEdges(ss);
        for(index = 0; index < totedge; index++) {
 -              CCGEdge *e = ccgdm->edgeMap[index].edge;
 +              CCGEdge *e = cgdm->edgeMap[index].edge;
                int x;
  
                for(x = 1; x < edgeSize - 1; x++, i++) {
  
        totvert = ccgSubSurf_getNumVerts(ss);
        for(index = 0; index < totvert; index++) {
 -              CCGVert *v = ccgdm->vertMap[index].vert;
 +              CCGVert *v = cgdm->vertMap[index].vert;
  
                vd= ccgSubSurf_getVertData(ss, v);
                copy_v3_v3(mvert[i].co, vd->co);
  
  static void ccgDM_copyFinalEdgeArray(DerivedMesh *dm, MEdge *medge)
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        int index;
        int totedge, totface;
        int gridSize = ccgSubSurf_getGridSize(ss);
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int i = 0;
 -      short *edgeFlags = ccgdm->edgeFlags;
 +      short *edgeFlags = cgdm->edgeFlags;
  
        totface = ccgSubSurf_getNumFaces(ss);
        for(index = 0; index < totface; index++) {
 -              CCGFace *f = ccgdm->faceMap[index].face;
 +              CCGFace *f = cgdm->faceMap[index].face;
                int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
  
                for(S = 0; S < numVerts; S++) {
                        for(x = 0; x < gridSize - 1; x++) {
                                MEdge *med = &medge[i];
  
 -                              if(ccgdm->drawInteriorEdges)
 +                              if(cgdm->drawInteriorEdges)
                                        med->flag = ME_EDGEDRAW | ME_EDGERENDER;
                                med->v1 = getFaceIndex(ss, f, S, x, 0, edgeSize, gridSize);
                                med->v2 = getFaceIndex(ss, f, S, x + 1, 0, edgeSize, gridSize);
                                        MEdge *med;
  
                                        med = &medge[i];
 -                                      if(ccgdm->drawInteriorEdges)
 +                                      if(cgdm->drawInteriorEdges)
                                                med->flag = ME_EDGEDRAW | ME_EDGERENDER;
                                        med->v1 = getFaceIndex(ss, f, S, x, y,
                                                                                   edgeSize, gridSize);
                                        i++;
  
                                        med = &medge[i];
 -                                      if(ccgdm->drawInteriorEdges)
 +                                      if(cgdm->drawInteriorEdges)
                                                med->flag = ME_EDGEDRAW | ME_EDGERENDER;
                                        med->v1 = getFaceIndex(ss, f, S, y, x,
                                                                                   edgeSize, gridSize);
  
        totedge = ccgSubSurf_getNumEdges(ss);
        for(index = 0; index < totedge; index++) {
 -              CCGEdge *e = ccgdm->edgeMap[index].edge;
 +              CCGEdge *e = cgdm->edgeMap[index].edge;
                unsigned int flags = 0;
                int x;
                int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e));
  
  static void ccgDM_copyFinalFaceArray(DerivedMesh *dm, MFace *mface)
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        int index;
        int totface;
        int gridSize = ccgSubSurf_getGridSize(ss);
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int i = 0;
 -      char *faceFlags = ccgdm->faceFlags;
 +      char *faceFlags = cgdm->faceFlags;
  
        totface = ccgSubSurf_getNumFaces(ss);
        for(index = 0; index < totface; index++) {
 -              CCGFace *f = ccgdm->faceMap[index].face;
 +              CCGFace *f = cgdm->faceMap[index].face;
                int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
                int flag = (faceFlags)? faceFlags[index*2]: ME_SMOOTH;
                int mat_nr = (faceFlags)? faceFlags[index*2+1]: 0;
                                                                                  edgeSize, gridSize);
                                        mf->v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
                                                                                  edgeSize, gridSize);
 +                                      if (faceFlags) {
 +                                              mat_nr = faceFlags[index*2+1];
 +                                              mf->flag = faceFlags[index*2];
 +                                      } else mf->flag = flag;
 +
                                        mf->mat_nr = mat_nr;
                                        mf->flag = flag;
  
        }
  }
  
 -static void ccgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void ccgDM_copyFinalLoopArray(DerivedMesh *dm, MLoop *mloop)
 +{
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
 +      int index;
 +      int totface;
 +      int gridSize = ccgSubSurf_getGridSize(ss);
 +      int edgeSize = ccgSubSurf_getEdgeSize(ss);
 +      int i = 0;
 +      MLoop *mv;
 +      /* char *faceFlags = cgdm->faceFlags; */ /* UNUSED */
 +
 +      if (!cgdm->ehash) {
 +              MEdge *medge;
 +
 +              cgdm->ehash = BLI_edgehash_new();
 +              medge = cgdm->dm.getEdgeArray((DerivedMesh*)cgdm);
 +
 +              for (i=0; i<cgdm->dm.numEdgeData; i++) {
 +                      BLI_edgehash_insert(cgdm->ehash, medge[i].v1, medge[i].v2, SET_INT_IN_POINTER(i));
 +              }
 +      }
 +
 +      totface = ccgSubSurf_getNumFaces(ss);
 +      mv = mloop;
 +      for(index = 0; index < totface; index++) {
 +              CCGFace *f = cgdm->faceMap[index].face;
 +              int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
 +              /* int flag = (faceFlags)? faceFlags[index*2]: ME_SMOOTH; */ /* UNUSED */
 +              /* int mat_nr = (faceFlags)? faceFlags[index*2+1]: 0; */ /* UNUSED */
 +
 +              for(S = 0; S < numVerts; S++) {
 +                      for(y = 0; y < gridSize - 1; y++) {
 +                              for(x = 0; x < gridSize - 1; x++) {
 +                                      int v1, v2, v3, v4;
 +
 +                                      v1 = getFaceIndex(ss, f, S, x + 0, y + 0,
 +                                                                                edgeSize, gridSize);
 +
 +                                      v2 = getFaceIndex(ss, f, S, x + 0, y + 1,
 +                                                                                edgeSize, gridSize);
 +                                      v3 = getFaceIndex(ss, f, S, x + 1, y + 1,
 +                                                                                edgeSize, gridSize);
 +                                      v4 = getFaceIndex(ss, f, S, x + 1, y + 0,
 +                                                                                edgeSize, gridSize);
 +
 +                                      mv->v = v1;
 +                                      mv->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(cgdm->ehash, v1, v2));
 +                                      mv++, i++;
 +
 +                                      mv->v = v2;
 +                                      mv->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(cgdm->ehash, v2, v3));
 +                                      mv++, i++;
 +
 +                                      mv->v = v3;
 +                                      mv->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(cgdm->ehash, v3, v4));
 +                                      mv++, i++;
 +
 +                                      mv->v = v4;
 +                                      mv->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(cgdm->ehash, v4, v1));
 +                                      mv++, i++;
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +
 +static void ccgDM_copyFinalPolyArray(DerivedMesh *dm, MPoly *mface)
 +{
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
 +      int index;
 +      int totface;
 +      int gridSize = ccgSubSurf_getGridSize(ss);
 +      /* int edgeSize = ccgSubSurf_getEdgeSize(ss); */ /* UNUSED */
 +      int i = 0, k = 0;
 +      char *faceFlags = cgdm->faceFlags;
 +
 +      totface = ccgSubSurf_getNumFaces(ss);
 +      for(index = 0; index < totface; index++) {
 +              CCGFace *f = cgdm->faceMap[index].face;
 +              int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
 +              int flag = (faceFlags)? faceFlags[index*2]: ME_SMOOTH;
 +              int mat_nr = (faceFlags)? faceFlags[index*2+1]: 0;
 +
 +              for(S = 0; S < numVerts; S++) {
 +                      for(y = 0; y < gridSize - 1; y++) {
 +                              for(x = 0; x < gridSize - 1; x++) {
 +                                      MPoly *mf = &mface[i];
 +
 +                                      if (faceFlags) {
 +                                              mat_nr = faceFlags[index*2+1];
 +                                              mf->flag = faceFlags[index*2];
 +                                      } else mf->flag = flag;
 +
 +                                      mf->mat_nr = mat_nr;
 +                                      mf->flag = flag;
 +                                      mf->loopstart = k;
 +                                      mf->totloop = 4;
 +
 +                                      k += 4;
 +                                      i++;
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +static void cgdm_getVertCos(DerivedMesh *dm, float (*cos)[3]) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int gridSize = ccgSubSurf_getGridSize(ss);
        int i;
        MEM_freeN(edgeMap2);
        MEM_freeN(faceMap2);
  }
 -static void ccgDM_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGVertIterator *vi = ccgSubSurf_getVertIterator(ccgdm->ss);
 +static void cgdm_foreachMappedVert(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no_f, short *no_s), void *userData) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGVertIterator *vi = ccgSubSurf_getVertIterator(cgdm->ss);
  
        for (; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
                CCGVert *v = ccgVertIterator_getCurrent(vi);
 -              DMGridData *vd = ccgSubSurf_getVertData(ccgdm->ss, v);
 -              int index = ccgDM_getVertMapIndex(ccgdm->ss, v);
 +              DMGridData *vd = ccgSubSurf_getVertData(cgdm->ss, v);
 +              int index = ccgDM_getVertMapIndex(cgdm->ss, v);
  
                if (index!=-1)
                        func(userData, index, vd->co, vd->no, NULL);
  
        ccgVertIterator_free(vi);
  }
 -static void ccgDM_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void cgdm_foreachMappedEdge(DerivedMesh *dm, void (*func)(void *userData, int index, float *v0co, float *v1co), void *userData) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
  
  }
  
  static void ccgDM_drawVerts(DerivedMesh *dm) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int gridSize = ccgSubSurf_getGridSize(ss);
        CCGVertIterator *vi;
@@@ -1463,8 -1244,8 +1463,8 @@@ static void ccgDM_drawEdges(DerivedMes
        ccgEdgeIterator_free(ei);
  }
  static void ccgDM_drawLooseEdges(DerivedMesh *dm) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        int i, edgeSize = ccgSubSurf_getEdgeSize(ss);
  
@@@ -1587,21 -1368,21 +1587,21 @@@ static void ccgDM_drawFacesSolid(Derive
  }
  
        /* Only used by non-editmesh types */
 -static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void cgdm_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
        GPUVertexAttribs gattribs;
        DMVertexAttribs attribs= {{{NULL}}};
 -      MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
 +      MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
        int gridSize = ccgSubSurf_getGridSize(ss);
        int gridFaces = gridSize - 1;
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
        int transp, orig_transp, new_transp;
 -      char *faceFlags = ccgdm->faceFlags;
 +      char *faceFlags = cgdm->faceFlags;
        int a, b, i, doDraw, numVerts, matnr, new_matnr, totface;
  
 -      ccgdm_pbvh_update(ccgdm);
 +      ccgdm_pbvh_update(cgdm);
  
        doDraw = 0;
        matnr = -1;
  
        totface = ccgSubSurf_getNumFaces(ss);
        for(a = 0, i = 0; i < totface; i++) {
 -              CCGFace *f = ccgdm->faceMap[i].face;
 +              CCGFace *f = cgdm->faceMap[i].face;
                int S, x, y, drawSmooth;
                int index = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
                int origIndex = ccgDM_getFaceMapIndex(ss, f);
        ccgFaceIterator_free(fi);
  }
  
 -static void ccgDM_drawFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs)) {
 +static void cgdm_drawFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs)) {
        dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
  }
  
 -static void ccgDM_drawFacesColored(DerivedMesh *dm, int UNUSED(useTwoSided), unsigned char *col1, unsigned char *col2) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void cgdm_drawFacesColored(DerivedMesh *dm, int UNUSED(useTwoSided), unsigned char *col1, unsigned char *col2) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
        int gridSize = ccgSubSurf_getGridSize(ss);
        unsigned char *cp1, *cp2;
        int useTwoSide=1;
  
 -      ccgdm_pbvh_update(ccgdm);
 +      ccgdm_pbvh_update(cgdm);
  
        cp1= col1;
        if(col2) {
        ccgFaceIterator_free(fi);
  }
  
 -static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
 -      int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
 +static void cgdm_drawFacesTex_common(DerivedMesh *dm,
 +      int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
        int (*drawParamsMapped)(void *userData, int index),
        void *userData) 
  {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 -      MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
 -      MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
 -      char *faceFlags = ccgdm->faceFlags;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
 +      MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
 +      MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
 +      char *faceFlags = cgdm->faceFlags;
        int i, totface, flag, gridSize = ccgSubSurf_getGridSize(ss);
        int gridFaces = gridSize - 1;
  
 -      ccgdm_pbvh_update(ccgdm);
 +      ccgdm_pbvh_update(cgdm);
  
        if(!mcol)
 -              mcol = dm->getFaceDataArray(dm, CD_MCOL);
 +              mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
  
        totface = ccgSubSurf_getNumFaces(ss);
        for(i = 0; i < totface; i++) {
 -              CCGFace *f = ccgdm->faceMap[i].face;
 +              CCGFace *f = cgdm->faceMap[i].face;
                int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
                int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
                int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
                }
  
                if(drawParams)
 -                      flag = drawParams(tf, mcol, mat_nr);
 +                      flag = drawParams(tf, mcol!=NULL, mat_nr);
                else if (index != ORIGINDEX_NONE)
                        flag= (drawParamsMapped)? drawParamsMapped(userData, index): 1;
                else
        }
  }
  
 -static void ccgDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
 +static void cgdm_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
  {
 -      ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
 +      cgdm_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
  }
  
 -static void ccgDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
 +static void cgdm_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
  {
 -      ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 +      cgdm_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
  }
  
 -static void ccgDM_drawUVEdges(DerivedMesh *dm)
 +static void cgdm_drawUVEdges(DerivedMesh *dm)
  {
  
 -      MFace *mf = dm->getFaceArray(dm);
 -      MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
 +      MFace *mf = dm->getTessFaceArray(dm);
 +      MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
        int i;
        
        if (tf) {
        }
  }
  
- static void ccgDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs)) {
+ static void ccgDM_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)) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        MCol *mcol= NULL;
        int i, gridSize = ccgSubSurf_getGridSize(ss);
 -      char *faceFlags = ccgdm->faceFlags;
 +      char *faceFlags = cgdm->faceFlags;
        int gridFaces = gridSize - 1, totface;
  
+       /* currently unused -- each original face is handled separately */
+       (void)compareDrawOptions;
        if(useColors) {
 -              mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
 +              mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
                if(!mcol)
 -                      mcol = dm->getFaceDataArray(dm, CD_MCOL);
 +                      mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
        }
  
        totface = ccgSubSurf_getNumFaces(ss);
        for(i = 0; i < totface; i++) {
 -              CCGFace *f = ccgdm->faceMap[i].face;
 +              CCGFace *f = cgdm->faceMap[i].face;
                int S, x, y, numVerts = ccgSubSurf_getFaceNumVerts(f);
                int drawSmooth, index = ccgDM_getFaceMapIndex(ss, f);
                int origIndex;
                }
        }
  }
 -static void ccgDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void cgdm_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
  
  
        ccgEdgeIterator_free(ei);
  }
 -static void ccgDM_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void cgdm_drawMappedEdgesInterp(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void (*setDrawInterpOptions)(void *userData, int index, float t), void *userData) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGEdgeIterator *ei = ccgSubSurf_getEdgeIterator(ss);
        int i, useAging, edgeSize = ccgSubSurf_getEdgeSize(ss);
  
  
        ccgEdgeIterator_free(ei);
  }
 -static void ccgDM_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +static void cgdm_foreachMappedFaceCenter(DerivedMesh *dm, void (*func)(void *userData, int index, float *co, float *no), void *userData) {
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        CCGFaceIterator *fi = ccgSubSurf_getFaceIterator(ss);
  
        for (; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
        ccgFaceIterator_free(fi);
  }
  
 -static void ccgDM_release(DerivedMesh *dm) {
 +static void cgdm_release(DerivedMesh *dm) {
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
  
        if (DM_release(dm)) {
                                ccgdm->multires.update(dm);
                }
  
 +              if (ccgdm->ehash)
 +                      BLI_edgehash_free(ccgdm->ehash, NULL);
 +
 +              if(ccgdm->reverseFaceMap) MEM_freeN(ccgdm->reverseFaceMap);
                if(ccgdm->gridFaces) MEM_freeN(ccgdm->gridFaces);
                if(ccgdm->gridData) MEM_freeN(ccgdm->gridData);
                if(ccgdm->gridAdjacency) MEM_freeN(ccgdm->gridAdjacency);
        }
  }
  
 +static void ccg_loops_to_corners(CustomData *fdata, CustomData *ldata, 
 +                        CustomData *pdata, int loopstart, int findex, 
 +                        int polyindex, int numTex, int numCol) 
 +{
 +      MTFace *texface;
 +      MTexPoly *texpoly;
 +      MCol *mcol;
 +      MLoopCol *mloopcol;
 +      MLoopUV *mloopuv;
 +      int i, j, hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL);
 +
 +      for(i=0; i < numTex; i++){
 +              texface = CustomData_get_n(fdata, CD_MTFACE, findex, i);
 +              texpoly = CustomData_get_n(pdata, CD_MTEXPOLY, polyindex, 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;
 +
 +              mloopuv = CustomData_get_n(ldata, CD_MLOOPUV, loopstart, i);
 +              for (j=0; j<4; j++, mloopuv++) {
 +                      texface->uv[j][0] = mloopuv->uv[0];
 +                      texface->uv[j][1] = mloopuv->uv[1];
 +              }
 +      }
 +
 +      for(i=0; i < numCol; i++){
 +              mloopcol = CustomData_get_n(ldata, CD_MLOOPCOL, loopstart, i);
 +              mcol = CustomData_get_n(fdata, CD_MCOL, findex, i);
 +
 +              for (j=0; j<4; j++, mloopcol++) {
 +                      mcol[j].r = mloopcol->r;
 +                      mcol[j].g = mloopcol->g;
 +                      mcol[j].b = mloopcol->b;
 +                      mcol[j].a = mloopcol->a;
 +              }
 +      }
 +      
 +      if (hasWCol) {
 +              mloopcol = CustomData_get(ldata, loopstart, CD_WEIGHT_MLOOPCOL);
 +              mcol = CustomData_get(fdata, findex, CD_WEIGHT_MCOL);
 +
 +              for (j=0; j<4; j++, mloopcol++) {
 +                      mcol[j].r = mloopcol->r;
 +                      mcol[j].g = mloopcol->g;
 +                      mcol[j].b = mloopcol->b;
 +                      mcol[j].a = mloopcol->a;
 +              }
 +      }
 +}
 +
  static void *ccgDM_get_vert_data_layer(DerivedMesh *dm, int type)
  {
        if(type == CD_ORIGINDEX) {
                /* create origindex on demand to save memory */
 -              CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 -              CCGSubSurf *ss= ccgdm->ss;
 +              CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
 +              CCGSubSurf *ss= cgdm->ss;
                int *origindex;
                int a, index, totnone, totorig;
  
                        origindex[a]= ORIGINDEX_NONE;
  
                for(index=0; index<totorig; index++, a++) {
 -                      CCGVert *v = ccgdm->vertMap[index].vert;
 -                      origindex[a] = ccgDM_getVertMapIndex(ccgdm->ss, v);
 +                      CCGVert *v = cgdm->vertMap[index].vert;
 +                      origindex[a] = ccgDM_getVertMapIndex(cgdm->ss, v);
                }
  
                return origindex;
@@@ -2316,8 -2043,8 +2320,8 @@@ static void *ccgDM_get_edge_data_layer(
  {
        if(type == CD_ORIGINDEX) {
                /* create origindex on demand to save memory */
 -              CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 -              CCGSubSurf *ss= ccgdm->ss;
 +              CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
 +              CCGSubSurf *ss= cgdm->ss;
                int *origindex;
                int a, i, index, totnone, totorig, totedge;
                int edgeSize= ccgSubSurf_getEdgeSize(ss);
                        origindex[a]= ORIGINDEX_NONE;
  
                for(index=0; index<totedge; index++) {
 -                      CCGEdge *e= ccgdm->edgeMap[index].edge;
 +                      CCGEdge *e= cgdm->edgeMap[index].edge;
                        int mapIndex= ccgDM_getEdgeMapIndex(ss, e);
  
                        for(i = 0; i < edgeSize - 1; i++, a++)
@@@ -2351,19 -2078,19 +2355,19 @@@ static void *ccgDM_get_face_data_layer(
  {
        if(type == CD_ORIGINDEX) {
                /* create origindex on demand to save memory */
 -              CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 -              CCGSubSurf *ss= ccgdm->ss;
 +              CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
 +              CCGSubSurf *ss= cgdm->ss;
                int *origindex;
                int a, i, index, totface;
                int gridFaces = ccgSubSurf_getGridSize(ss) - 1;
  
                DM_add_face_layer(dm, CD_ORIGINDEX, CD_CALLOC, NULL);
 -              origindex= DM_get_face_data_layer(dm, CD_ORIGINDEX);
 +              origindex= DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
  
                totface= ccgSubSurf_getNumFaces(ss);
  
                for(a=0, index=0; index<totface; index++) {
 -                      CCGFace *f = ccgdm->faceMap[index].face;
 +                      CCGFace *f = cgdm->faceMap[index].face;
                        int numVerts = ccgSubSurf_getFaceNumVerts(f);
                        int mapIndex = ccgDM_getFaceMapIndex(ss, f);
  
                return origindex;
        }
  
 -      return DM_get_face_data_layer(dm, type);
 +      return DM_get_tessface_data_layer(dm, type);
  }
  
  static int ccgDM_getNumGrids(DerivedMesh *dm)
  {
 -      CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 +      CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
        int index, numFaces, numGrids;
  
 -      numFaces= ccgSubSurf_getNumFaces(ccgdm->ss);
 +      numFaces= ccgSubSurf_getNumFaces(cgdm->ss);
        numGrids= 0;
  
        for(index=0; index<numFaces; index++) {
 -              CCGFace *f = ccgdm->faceMap[index].face;
 +              CCGFace *f = cgdm->faceMap[index].face;
                numGrids += ccgSubSurf_getFaceNumVerts(f);
        }
  
  
  static int ccgDM_getGridSize(DerivedMesh *dm)
  {
 -      CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 -      return ccgSubSurf_getGridSize(ccgdm->ss);
 +      CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
 +      return ccgSubSurf_getGridSize(cgdm->ss);
  }
  
 -static int ccgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int S, int offset)
 +static int cgdm_adjacent_grid(CCGSubSurf *ss, int *gridOffset, CCGFace *f, int S, int offset)
  {
        CCGFace *adjf;
        CCGEdge *e;
  
  static void ccgdm_create_grids(DerivedMesh *dm)
  {
 -      CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 -      CCGSubSurf *ss= ccgdm->ss;
 +      CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
 +      CCGSubSurf *ss= cgdm->ss;
        DMGridData **gridData;
        DMGridAdjacency *gridAdjacency, *adj;
        CCGFace **gridFaces;
        int *gridOffset;
        int index, numFaces, numGrids, S, gIndex /*, gridSize*/;
  
 -      if(ccgdm->gridData)
 +      if(cgdm->gridData)
                return;
        
        numGrids = ccgDM_getNumGrids(dm);
        /*gridSize = ccgDM_getGridSize(dm);*/  /*UNUSED*/
  
        /* compute offset into grid array for each face */
 -      gridOffset = MEM_mallocN(sizeof(int)*numFaces, "ccgdm.gridOffset");
 +      gridOffset = MEM_mallocN(sizeof(int)*numFaces, "cgdm.gridOffset");
  
        for(gIndex = 0, index = 0; index < numFaces; index++) {
 -              CCGFace *f = ccgdm->faceMap[index].face;
 +              CCGFace *f = cgdm->faceMap[index].face;
                int numVerts = ccgSubSurf_getFaceNumVerts(f);
  
                gridOffset[index] = gIndex;
        }
  
        /* compute grid data */
 -      gridData = MEM_mallocN(sizeof(DMGridData*)*numGrids, "ccgdm.gridData");
 -      gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency)*numGrids, "ccgdm.gridAdjacency");
 -      gridFaces = MEM_mallocN(sizeof(CCGFace*)*numGrids, "ccgdm.gridFaces");
 +      gridData = MEM_mallocN(sizeof(DMGridData*)*numGrids, "cgdm.gridData");
 +      gridAdjacency = MEM_mallocN(sizeof(DMGridAdjacency)*numGrids, "cgdm.gridAdjacency");
 +      gridFaces = MEM_mallocN(sizeof(CCGFace*)*numGrids, "cgdm.gridFaces");
  
        for(gIndex = 0, index = 0; index < numFaces; index++) {
 -              CCGFace *f = ccgdm->faceMap[index].face;
 +              CCGFace *f = cgdm->faceMap[index].face;
                int numVerts = ccgSubSurf_getFaceNumVerts(f);
  
                for(S = 0; S < numVerts; S++, gIndex++) {
  
                        adj->index[0] = gIndex - S + nextS;
                        adj->rotation[0] = 3;
 -                      adj->index[1] = ccgdm_adjacent_grid(ss, gridOffset, f, prevS, 0);
 +                      adj->index[1] = cgdm_adjacent_grid(ss, gridOffset, f, prevS, 0);
                        adj->rotation[1] = 1;
 -                      adj->index[2] = ccgdm_adjacent_grid(ss, gridOffset, f, S, 1);
 +                      adj->index[2] = cgdm_adjacent_grid(ss, gridOffset, f, S, 1);
                        adj->rotation[2] = 3;
                        adj->index[3] = gIndex - S + prevS;
                        adj->rotation[3] = 1;
                }
        }
  
 -      ccgdm->gridData = gridData;
 -      ccgdm->gridFaces = gridFaces;
 -      ccgdm->gridAdjacency = gridAdjacency;
 -      ccgdm->gridOffset = gridOffset;
 +      cgdm->gridData = gridData;
 +      cgdm->gridFaces = gridFaces;
 +      cgdm->gridAdjacency = gridAdjacency;
 +      cgdm->gridOffset = gridOffset;
  }
  
  static DMGridData **ccgDM_getGridData(DerivedMesh *dm)
  {
 -      CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 +      CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
  
        ccgdm_create_grids(dm);
 -      return ccgdm->gridData;
 +      return cgdm->gridData;
  }
  
  static DMGridAdjacency *ccgDM_getGridAdjacency(DerivedMesh *dm)
  {
 -      CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 +      CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
  
        ccgdm_create_grids(dm);
 -      return ccgdm->gridAdjacency;
 +      return cgdm->gridAdjacency;
  }
  
  static int *ccgDM_getGridOffset(DerivedMesh *dm)
  {
 -      CCGDerivedMesh *ccgdm= (CCGDerivedMesh*)dm;
 +      CCGDerivedMesh *cgdm= (CCGDerivedMesh*)dm;
  
        ccgdm_create_grids(dm);
 -      return ccgdm->gridOffset;
 +      return cgdm->gridOffset;
  }
  
  static ListBase *ccgDM_getFaceMap(Object *ob, DerivedMesh *dm)
@@@ -2601,74 -2328,50 +2605,74 @@@ static CCGDerivedMesh *getCCGDerivedMes
                                                                                 int useSubsurfUv,
                                                                                 DerivedMesh *dm)
  {
 -      CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "ccgdm");
 +      CCGDerivedMesh *ccgdm = MEM_callocN(sizeof(*ccgdm), "cgdm");
        CCGVertIterator *vi;
        CCGEdgeIterator *ei;
        CCGFaceIterator *fi;
        int index, totvert, totedge, totface;
        int i;
        int vertNum, edgeNum, faceNum;
 +      int *vertOrigIndex, *faceOrigIndex, *polyOrigIndex, *base_polyOrigIndex; /* *edgeOrigIndex - as yet, unused  */
        short *edgeFlags;
        char *faceFlags;
 -      int edgeSize;
 +      int *loopidx = NULL, *vertidx = NULL;
 +      BLI_array_declare(loopidx);
 +      BLI_array_declare(vertidx);
 +      int loopindex, loopindex2;
 +      int edgeSize, has_edge_origindex;
        int gridSize;
 -      int gridFaces;
 +      int gridFaces, gridCuts;
        /*int gridSideVerts;*/
        int gridSideEdges;
 +      int numTex, numCol;
        int gridInternalEdges;
 +      float *w = NULL;
 +      WeightTable wtable = {0};
 +      MCol *mcol;
        MEdge *medge = NULL;
        MFace *mface = NULL;
 -      int *orig_indices;
 -      FaceVertWeight *qweight, *tweight;
 +      MPoly *mpoly = NULL;
  
        DM_from_template(&ccgdm->dm, dm, DM_TYPE_CCGDM,
                                         ccgSubSurf_getNumFinalVerts(ss),
                                         ccgSubSurf_getNumFinalEdges(ss),
 +                                       ccgSubSurf_getNumFinalFaces(ss),
 +                                       ccgSubSurf_getNumFinalFaces(ss)*4, 
                                         ccgSubSurf_getNumFinalFaces(ss));
 +      
 +      numTex = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPUV);
 +      numCol = CustomData_number_of_layers(&ccgdm->dm.loopData, CD_MLOOPCOL);
 +      
 +      if (numTex && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MTFACE) != numTex)
 +              CustomData_from_bmeshpoly(&ccgdm->dm.faceData, &ccgdm->dm.polyData, &ccgdm->dm.loopData, ccgSubSurf_getNumFinalFaces(ss));
 +      else if (numCol && CustomData_number_of_layers(&ccgdm->dm.faceData, CD_MCOL) != numCol)
 +              CustomData_from_bmeshpoly(&ccgdm->dm.faceData, &ccgdm->dm.polyData, &ccgdm->dm.loopData, ccgSubSurf_getNumFinalFaces(ss));
 +
 +      ccgdm->dm.getMinMax = cgdm_getMinMax;
 +      ccgdm->dm.getNumVerts = cgdm_getNumVerts;
 +      ccgdm->dm.getNumEdges = cgdm_getNumEdges;
 +      ccgdm->dm.getNumTessFaces = cgdm_getNumTessFaces;
 +      ccgdm->dm.getNumFaces = cgdm_getNumTessFaces;
  
 -      ccgdm->dm.getMinMax = ccgDM_getMinMax;
 -      ccgdm->dm.getNumVerts = ccgDM_getNumVerts;
 -      ccgdm->dm.getNumFaces = ccgDM_getNumFaces;
 +      ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
 +      ccgdm->dm.getPBVH = ccgDM_getPBVH;
  
 -      ccgdm->dm.getNumEdges = ccgDM_getNumEdges;
        ccgdm->dm.getVert = ccgDM_getFinalVert;
        ccgdm->dm.getEdge = ccgDM_getFinalEdge;
 -      ccgdm->dm.getFace = ccgDM_getFinalFace;
 +      ccgdm->dm.getTessFace = ccgDM_getFinalFace;
        ccgdm->dm.getVertCo = ccgDM_getFinalVertCo;
        ccgdm->dm.getVertNo = ccgDM_getFinalVertNo;
        ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
        ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
 -      ccgdm->dm.copyFaceArray = ccgDM_copyFinalFaceArray;
 +      ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
 +      ccgdm->dm.copyLoopArray = ccgDM_copyFinalLoopArray;
 +      ccgdm->dm.copyPolyArray = ccgDM_copyFinalPolyArray;
        ccgdm->dm.getVertData = DM_get_vert_data;
        ccgdm->dm.getEdgeData = DM_get_edge_data;
 -      ccgdm->dm.getFaceData = DM_get_face_data;
 +      ccgdm->dm.getTessFaceData = DM_get_face_data;
        ccgdm->dm.getVertDataArray = ccgDM_get_vert_data_layer;
        ccgdm->dm.getEdgeDataArray = ccgDM_get_edge_data_layer;
 -      ccgdm->dm.getFaceDataArray = ccgDM_get_face_data_layer;
 +      ccgdm->dm.getTessFaceDataArray = ccgDM_get_face_data_layer;
        ccgdm->dm.getNumGrids = ccgDM_getNumGrids;
        ccgdm->dm.getGridSize = ccgDM_getGridSize;
        ccgdm->dm.getGridData = ccgDM_getGridData;
        ccgdm->dm.getFaceMap = ccgDM_getFaceMap;
        ccgdm->dm.getPBVH = ccgDM_getPBVH;
  
 -      ccgdm->dm.getVertCos = ccgdm_getVertCos;
 -      ccgdm->dm.foreachMappedVert = ccgDM_foreachMappedVert;
 -      ccgdm->dm.foreachMappedEdge = ccgDM_foreachMappedEdge;
 -      ccgdm->dm.foreachMappedFaceCenter = ccgDM_foreachMappedFaceCenter;
 +      ccgdm->dm.getTessFace = ccgDM_getFinalFace;
 +      ccgdm->dm.copyVertArray = ccgDM_copyFinalVertArray;
 +      ccgdm->dm.copyEdgeArray = ccgDM_copyFinalEdgeArray;
 +      ccgdm->dm.copyTessFaceArray = ccgDM_copyFinalFaceArray;
 +      ccgdm->dm.getVertData = DM_get_vert_data;
 +      ccgdm->dm.getEdgeData = DM_get_edge_data;
 +      ccgdm->dm.getTessFaceData = DM_get_face_data;
 +      ccgdm->dm.getVertDataArray = DM_get_vert_data_layer;
 +      ccgdm->dm.getEdgeDataArray = DM_get_edge_data_layer;
 +      ccgdm->dm.getTessFaceDataArray = DM_get_tessface_data_layer;
 +
 +      ccgdm->dm.getVertCos = cgdm_getVertCos;
 +      ccgdm->dm.foreachMappedVert = cgdm_foreachMappedVert;
 +      ccgdm->dm.foreachMappedEdge = cgdm_foreachMappedEdge;
 +      ccgdm->dm.foreachMappedFaceCenter = cgdm_foreachMappedFaceCenter;
        
        ccgdm->dm.drawVerts = ccgDM_drawVerts;
        ccgdm->dm.drawEdges = ccgDM_drawEdges;
        ccgdm->dm.drawLooseEdges = ccgDM_drawLooseEdges;
        ccgdm->dm.drawFacesSolid = ccgDM_drawFacesSolid;
 -      ccgdm->dm.drawFacesColored = ccgDM_drawFacesColored;
 -      ccgdm->dm.drawFacesTex = ccgDM_drawFacesTex;
 -      ccgdm->dm.drawFacesGLSL = ccgDM_drawFacesGLSL;
 +      ccgdm->dm.drawFacesColored = cgdm_drawFacesColored;
 +      ccgdm->dm.drawFacesTex = cgdm_drawFacesTex;
 +      ccgdm->dm.drawFacesGLSL = cgdm_drawFacesGLSL;
        ccgdm->dm.drawMappedFaces = ccgDM_drawMappedFaces;
 -      ccgdm->dm.drawMappedFacesTex = ccgDM_drawMappedFacesTex;
 -      ccgdm->dm.drawMappedFacesGLSL = ccgDM_drawMappedFacesGLSL;
 -      ccgdm->dm.drawUVEdges = ccgDM_drawUVEdges;
 +      ccgdm->dm.drawMappedFacesTex = cgdm_drawMappedFacesTex;
 +      ccgdm->dm.drawMappedFacesGLSL = cgdm_drawMappedFacesGLSL;
 +      ccgdm->dm.drawUVEdges = cgdm_drawUVEdges;
  
 -      ccgdm->dm.drawMappedEdgesInterp = ccgDM_drawMappedEdgesInterp;
 -      ccgdm->dm.drawMappedEdges = ccgDM_drawMappedEdges;
 +      ccgdm->dm.drawMappedEdgesInterp = cgdm_drawMappedEdgesInterp;
 +      ccgdm->dm.drawMappedEdges = cgdm_drawMappedEdges;
        
 -      ccgdm->dm.release = ccgDM_release;
 +      ccgdm->dm.release = cgdm_release;
        
        ccgdm->ss = ss;
        ccgdm->drawInteriorEdges = drawInteriorEdges;
        ccgdm->useSubsurfUv = useSubsurfUv;
  
        totvert = ccgSubSurf_getNumVerts(ss);
 -      ccgdm->vertMap = MEM_mallocN(totvert * sizeof(*ccgdm->vertMap), "vertMap");
 +      ccgdm->vertMap = MEM_callocN(totvert * sizeof(*ccgdm->vertMap), "vertMap");
        vi = ccgSubSurf_getVertIterator(ss);
        for(; !ccgVertIterator_isStopped(vi); ccgVertIterator_next(vi)) {
                CCGVert *v = ccgVertIterator_getCurrent(vi);
        ccgVertIterator_free(vi);
  
        totedge = ccgSubSurf_getNumEdges(ss);
 -      ccgdm->edgeMap = MEM_mallocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap");
 +      ccgdm->edgeMap = MEM_callocN(totedge * sizeof(*ccgdm->edgeMap), "edgeMap");
        ei = ccgSubSurf_getEdgeIterator(ss);
        for(; !ccgEdgeIterator_isStopped(ei); ccgEdgeIterator_next(ei)) {
                CCGEdge *e = ccgEdgeIterator_getCurrent(ei);
        }
  
        totface = ccgSubSurf_getNumFaces(ss);
 -      ccgdm->faceMap = MEM_mallocN(totface * sizeof(*ccgdm->faceMap), "faceMap");
 +      ccgdm->faceMap = MEM_callocN(totface * sizeof(*ccgdm->faceMap), "faceMap");
        fi = ccgSubSurf_getFaceIterator(ss);
        for(; !ccgFaceIterator_isStopped(fi); ccgFaceIterator_next(fi)) {
                CCGFace *f = ccgFaceIterator_getCurrent(fi);
        }
        ccgFaceIterator_free(fi);
  
 +      ccgdm->reverseFaceMap = MEM_callocN(sizeof(int)*ccgSubSurf_getNumFinalFaces(ss), "reverseFaceMap");
 +
        edgeSize = ccgSubSurf_getEdgeSize(ss);
        gridSize = ccgSubSurf_getGridSize(ss);
        gridFaces = gridSize - 1;
 -      /*gridSideVerts = gridSize - 2;*/ /*UNUSED*/
 -      /*gridInternalVerts = gridSideVerts * gridSideVerts; */ /*UNUSED*/
 +      gridCuts = gridSize - 2;
 +      /*gridInternalVerts = gridSideVerts * gridSideVerts; - as yet, unused */
        gridSideEdges = gridSize - 1;
        gridInternalEdges = (gridSideEdges - 1) * gridSideEdges * 2; 
  
 -      calc_ss_weights(gridFaces, &qweight, &tweight);
 -
        vertNum = 0;
        edgeNum = 0;
        faceNum = 0;
  
        /* mvert = dm->getVertArray(dm); - as yet unused */
        medge = dm->getEdgeArray(dm);
 -      mface = dm->getFaceArray(dm);
 +      mface = dm->getTessFaceArray(dm);
  
 +      mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
 +      base_polyOrigIndex = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
 +      
 +      /*CDDM hack*/
 +      edgeFlags = ccgdm->edgeFlags = MEM_callocN(sizeof(short)*totedge, "faceFlags");
        faceFlags = ccgdm->faceFlags = MEM_callocN(sizeof(char)*2*totface, "faceFlags");
  
 -      orig_indices = (int*)ccgdm->dm.getFaceDataArray(&ccgdm->dm, CD_ORIGINDEX);
 -      for(index = 0; index < totface; ++index) {
 +      vertOrigIndex = DM_get_vert_data_layer(&ccgdm->dm, CD_ORIGINDEX);
 +      /*edgeOrigIndex = DM_get_edge_data_layer(&cgdm->dm, CD_ORIGINDEX);*/
 +      faceOrigIndex = DM_get_tessface_data_layer(&ccgdm->dm, CD_ORIGINDEX);
 +
 +      polyOrigIndex = DM_get_face_data_layer(&ccgdm->dm, CD_ORIGINDEX);
 +
 +      if (!CustomData_has_layer(&ccgdm->dm.faceData, CD_MCOL))
 +              DM_add_tessface_layer(&ccgdm->dm, CD_MCOL, CD_CALLOC, NULL);
 +
 +      mcol = DM_get_tessface_data_layer(&ccgdm->dm, CD_MCOL);
 +      has_edge_origindex = CustomData_has_layer(&ccgdm->dm.edgeData, CD_ORIGINDEX);
 +
 +      faceNum = 0;
 +      loopindex = loopindex2 = 0; //current loop index
 +      for (index = 0; index < totface; index++) {
                CCGFace *f = ccgdm->faceMap[index].face;
                int numVerts = ccgSubSurf_getFaceNumVerts(f);
                int numFinalEdges = numVerts * (gridSideEdges + gridInternalEdges);
                int origIndex = GET_INT_FROM_POINTER(ccgSubSurf_getFaceFaceHandle(ss, f));
 -              FaceVertWeight *weight = (numVerts == 4) ? qweight : tweight;
 -              int S, x, y;
 -              int vertIdx[4];
 +              int g2_wid = gridCuts+2;
 +              float *w2;
 +              int s, x, y;
 +              
 +              origIndex = base_polyOrigIndex ? base_polyOrigIndex[origIndex] : origIndex;
 +              
 +              w = get_ss_weights(&wtable, gridCuts, numVerts);
  
                ccgdm->faceMap[index].startVert = vertNum;
                ccgdm->faceMap[index].startEdge = edgeNum;
                ccgdm->faceMap[index].startFace = faceNum;
 -
 -              if(orig_indices)
 -                      orig_indices[faceNum] = origIndex;
 +              
 +              faceFlags[0] = mpoly ?  mpoly[origIndex].flag : 0;
 +              faceFlags[1] = mpoly ? mpoly[origIndex].mat_nr : 0;
 +              faceFlags += 2;
  
                /* set the face base vert */
                *((int*)ccgSubSurf_getFaceUserData(ss, f)) = vertNum;
  
 -              for(S = 0; S < numVerts; S++) {
 -                      CCGVert *v = ccgSubSurf_getFaceVert(ss, f, S);
 +              BLI_array_empty(loopidx);               
 +              for (s=0; s<numVerts; s++) {
 +                      BLI_array_growone(loopidx);
 +                      loopidx[s] = loopindex++;
 +              }
 +              
 +              BLI_array_empty(vertidx);
 +                              for(s = 0; s < numVerts; s++) {
 +                      CCGVert *v = ccgSubSurf_getFaceVert(ss, f, s);
 +                      
 +                      BLI_array_growone(vertidx);
 +                      vertidx[s] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
 +              }
 +              
  
 -                      vertIdx[S] = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
 +              /*I think this is for interpolating the center vert?*/
 +              w2 = w; // + numVerts*(g2_wid-1)*(g2_wid-1); //numVerts*((g2_wid-1)*g2_wid+g2_wid-1);
 +              DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
 +                                  numVerts, vertNum);
 +              if (vertOrigIndex) {
 +                      *vertOrigIndex = ORIGINDEX_NONE;
 +                      ++vertOrigIndex;
                }
  
 -              DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, weight[0][0],
 -                                                      numVerts, vertNum);
                ++vertNum;
  
 -              for(S = 0; S < numVerts; S++) {
 -                      int prevS = (S - 1 + numVerts) % numVerts;
 -                      int nextS = (S + 1) % numVerts;
 -                      int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
 +              /*interpolate per-vert data*/
 +              for(s = 0; s < numVerts; s++) {
                        for(x = 1; x < gridFaces; x++) {
 -                              float w[4];
 -                              w[prevS]  = weight[x][0][0];
 -                              w[S]      = weight[x][0][1];
 -                              w[nextS]  = weight[x][0][2];
 -                              w[otherS] = weight[x][0][3];
 -                              DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w,
 -                                                                      numVerts, vertNum);
 +                              w2 = w + s*numVerts*g2_wid*g2_wid + x*numVerts;
 +                              DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
 +                                                  numVerts, vertNum);
 +
 +                              if (vertOrigIndex) {
 +                                      *vertOrigIndex = ORIGINDEX_NONE;
 +                                      ++vertOrigIndex;
 +                              }
 +
                                ++vertNum;
                        }
                }
  
 -              for(S = 0; S < numVerts; S++) {
 -                      int prevS = (S - 1 + numVerts) % numVerts;
 -                      int nextS = (S + 1) % numVerts;
 -                      int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
 +              /*interpolate per-vert data*/
 +              for(s = 0; s < numVerts; s++) {
                        for(y = 1; y < gridFaces; y++) {
                                for(x = 1; x < gridFaces; x++) {
 -                                      float w[4];
 -                                      w[prevS]  = weight[y * gridFaces + x][0][0];
 -                                      w[S]      = weight[y * gridFaces + x][0][1];
 -                                      w[nextS]  = weight[y * gridFaces + x][0][2];
 -                                      w[otherS] = weight[y * gridFaces + x][0][3];
 -                                      DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w,
 -                                                                              numVerts, vertNum);
 +                                      w2 = w + s*numVerts*g2_wid*g2_wid + (y*g2_wid+x)*numVerts;
 +                                      DM_interp_vert_data(dm, &ccgdm->dm, vertidx, w2,
 +                                                          numVerts, vertNum);
 +
 +                                      if (vertOrigIndex) {
 +                                              *vertOrigIndex = ORIGINDEX_NONE;
 +                                              ++vertOrigIndex;
 +                                      }
 +
                                        ++vertNum;
                                }
                        }
                }
  
 -              for(S = 0; S < numVerts; S++) {
 -                      int prevS = (S - 1 + numVerts) % numVerts;
 -                      int nextS = (S + 1) % numVerts;
 -                      int otherS = (numVerts == 4) ? (S + 2) % numVerts : 3;
 -
 -                      weight = (numVerts == 4) ? qweight : tweight;
 -
 -                      for(y = 0; y < gridFaces; y++) {
 -                              for(x = 0; x < gridFaces; x++) {
 -                                      FaceVertWeight w;
 -                                      int j;
 -
 -                                      for(j = 0; j < 4; ++j) {
 -                                              w[j][prevS]  = (*weight)[j][0];
 -                                              w[j][S]      = (*weight)[j][1];
 -                                              w[j][nextS]  = (*weight)[j][2];
 -                                              w[j][otherS] = (*weight)[j][3];
 +              if (has_edge_origindex) {
 +                      for(i = 0; i < numFinalEdges; ++i)
 +                              *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i,
 +                                                       CD_ORIGINDEX) = ORIGINDEX_NONE;
 +              }
 +
 +              for (s=0; s<numVerts; s++) {
 +                      /*interpolate per-face data*/
 +                      for (y=0; y<gridFaces; y++) {
 +                              for (x=0; x<gridFaces; x++) {
 +                                      w2 = w + s*numVerts*g2_wid*g2_wid + (y*g2_wid+x)*numVerts;
 +                                      CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
 +                                                        loopidx, w2, NULL, numVerts, loopindex2);
 +                                      loopindex2++;
 +
 +                                      w2 = w + s*numVerts*g2_wid*g2_wid + ((y+1)*g2_wid+(x))*numVerts;
 +                                      CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
 +                                                        loopidx, w2, NULL, numVerts, loopindex2);
 +                                      loopindex2++;
 +
 +                                      w2 = w + s*numVerts*g2_wid*g2_wid + ((y+1)*g2_wid+(x+1))*numVerts;
 +                                      CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
 +                                                        loopidx, w2, NULL, numVerts, loopindex2);
 +                                      loopindex2++;
 +                                      
 +                                      w2 = w + s*numVerts*g2_wid*g2_wid + ((y)*g2_wid+(x+1))*numVerts;
 +                                      CustomData_interp(&dm->loopData, &ccgdm->dm.loopData,
 +                                                        loopidx, w2, NULL, numVerts, loopindex2);
 +                                      loopindex2++;
 +
 +                                      /*copy over poly data, e.g. mtexpoly*/
 +                                      CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1);
 +
 +                                      /*generate tesselated face data used for drawing*/
 +                                      ccg_loops_to_corners(&ccgdm->dm.faceData, &ccgdm->dm.loopData,
 +                                              &ccgdm->dm.polyData, loopindex2-4, faceNum, faceNum, numTex, numCol);
 +                                      
 +                                      /*set original index data*/
 +                                      if (faceOrigIndex) {
 +                                              *faceOrigIndex = origIndex;
 +                                              faceOrigIndex++;
 +                                      }
 +                                      if (polyOrigIndex) {
 +                                              *polyOrigIndex = origIndex;
 +                                              polyOrigIndex++;
                                        }
  
 -                                      DM_interp_face_data(dm, &ccgdm->dm, &origIndex, NULL,
 -                                                                              &w, 1, faceNum);
 -                                      weight++;
 +                                      ccgdm->reverseFaceMap[faceNum] = index;
  
 -                                      ++faceNum;
 +                                      faceNum++;
                                }
                        }
                }
  
 -              faceFlags[index*2] = mface[origIndex].flag;
 -              faceFlags[index*2 + 1] = mface[origIndex].mat_nr;
 -
                edgeNum += numFinalEdges;
        }
  
 -      if(useSubsurfUv) {
 -              CustomData *fdata = &ccgdm->dm.faceData;
 -              CustomData *dmfdata = &dm->faceData;
 -              int numlayer = CustomData_number_of_layers(fdata, CD_MTFACE);
 -              int dmnumlayer = CustomData_number_of_layers(dmfdata, CD_MTFACE);
 -
 -              for (i=0; i<numlayer && i<dmnumlayer; i++)
 -                      set_subsurf_uv(ss, dm, &ccgdm->dm, i);
 -      }
 -
 -      edgeFlags = ccgdm->edgeFlags = MEM_callocN(sizeof(short)*totedge, "edgeFlags");
 -
        for(index = 0; index < totedge; ++index) {
                CCGEdge *e = ccgdm->edgeMap[index].edge;
                int numFinalEdges = edgeSize - 1;
 +              int mapIndex = ccgDM_getEdgeMapIndex(ss, e);
                int x;
                int vertIdx[2];
                int edgeIdx = GET_INT_FROM_POINTER(ccgSubSurf_getEdgeEdgeHandle(e));
                ccgdm->edgeMap[index].startVert = vertNum;
                ccgdm->edgeMap[index].startEdge = edgeNum;
  
 +              if(edgeIdx >= 0 && edgeFlags)
 +                      edgeFlags[edgeIdx] = medge[edgeIdx].flag;
 +
                /* set the edge base vert */
                *((int*)ccgSubSurf_getEdgeUserData(ss, e)) = vertNum;
  
                        w[1] = (float) x / (edgeSize - 1);
                        w[0] = 1 - w[1];
                        DM_interp_vert_data(dm, &ccgdm->dm, vertIdx, w, 2, vertNum);
 +                      if (vertOrigIndex) {
 +                              *vertOrigIndex = ORIGINDEX_NONE;
 +                              ++vertOrigIndex;
 +                      }
                        ++vertNum;
                }
  
 -              edgeFlags[index]= medge[edgeIdx].flag;
 +              for(i = 0; i < numFinalEdges; ++i) {
 +                      if (has_edge_origindex) {
 +                              *(int *)DM_get_edge_data(&ccgdm->dm, edgeNum + i,
 +                                               CD_ORIGINDEX) = mapIndex;
 +                      }
 +              }
  
                edgeNum += numFinalEdges;
        }
  
        for(index = 0; index < totvert; ++index) {
                CCGVert *v = ccgdm->vertMap[index].vert;
 -              int vertIdx;
 +              int mapIndex = ccgDM_getVertMapIndex(ccgdm->ss, v);
 +              int vidx;
  
 -              vertIdx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
 +              vidx = GET_INT_FROM_POINTER(ccgSubSurf_getVertVertHandle(v));
  
                ccgdm->vertMap[index].startVert = vertNum;
  
                /* set the vert base vert */
                *((int*) ccgSubSurf_getVertUserData(ss, v)) = vertNum;
  
 -              DM_copy_vert_data(dm, &ccgdm->dm, vertIdx, vertNum, 1);
 +              DM_copy_vert_data(dm, &ccgdm->dm, vidx, vertNum, 1);
  
 +              if (vertOrigIndex) {
 +                      *vertOrigIndex = mapIndex;
 +                      ++vertOrigIndex;
 +              }
                ++vertNum;
        }
  
 -      MEM_freeN(qweight);
 -      MEM_freeN(tweight);
 +      ccgdm->dm.numVertData = vertNum;
 +      ccgdm->dm.numEdgeData = edgeNum;
 +      ccgdm->dm.numFaceData = faceNum;
 +      ccgdm->dm.numLoopData = loopindex2;
 +      ccgdm->dm.numPolyData = faceNum;
 +
 +      BLI_array_free(vertidx);
 +      BLI_array_free(loopidx);
 +      free_ss_weights(&wtable);
  
        return ccgdm;
  }
@@@ -3014,7 -2631,7 +3018,7 @@@ struct DerivedMesh *subsurf_make_derive
        int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
        int useSubsurfUv = smd->flags & eSubsurfModifierFlag_SubsurfUv;
        int drawInteriorEdges = !(smd->flags & eSubsurfModifierFlag_ControlEdges);
 -      CCGDerivedMesh *result;
 +      CCGDerivedMesh *result = NULL;
  
        if(forEditMode) {
                int levels= (smd->modifier.scene)? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels): smd->levels;
  
                result->freeSS = 1;
        } else {
 -              int useIncremental = (smd->flags & eSubsurfModifierFlag_Incremental);
 +              int useIncremental = 1; //(smd->flags & eSubsurfModifierFlag_Incremental);
                int useAging = smd->flags & eSubsurfModifierFlag_DebugIncr;
                int levels= (smd->modifier.scene)? get_render_subsurf_level(&smd->modifier.scene->r, smd->levels): smd->levels;
                CCGSubSurf *ss;
                        smd->mCache = ss = _getSubSurf(smd->mCache, levels,
                                                                                   useAging, 0, useSimple);
  
 -                      ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
 +                      if (!ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple)) {
 +                              //ccgSubSurf_free(smd->mCache);
 +                              smd->mCache = ss = _getSubSurf(NULL, levels,
 +                                                                                         useAging, 0, useSimple);
 +                              
 +                              ss_sync_from_derivedmesh(ss, dm, vertCos, useSimple);
 +      
 +                      }
  
                        result = getCCGDerivedMesh(smd->mCache,
                                                                           drawInteriorEdges,
                                result->freeSS = 1;
                }
        }
 -
 -      return (DerivedMesh*)result;
 +      
 +      return (DerivedMesh *)result;
  }
  
  void subsurf_calculate_limit_positions(Mesh *me, float (*positions_r)[3]) 
index 9a6e14fcbad7ce4575505728e01e7e2f33428c2a,6e02ecbd5a866fed660736117a8949ce4e32fc75..0b671dd970507c9184df0a8eae5929a709248976
@@@ -34,7 -34,6 +34,7 @@@
  
  #include "MEM_guardedalloc.h"
  
 +#include "BLI_utildefines.h"
  #include "BLI_blenlib.h"
  #include "BLI_math.h"
  #include "BLI_edgehash.h"
@@@ -47,7 -46,6 +47,7 @@@
  #include "DNA_scene_types.h"
  #include "DNA_screen_types.h"
  #include "DNA_view3d_types.h"
 +#include "DNA_windowmanager_types.h"
  #include "DNA_object_types.h"
  
  #include "BKE_DerivedMesh.h"
@@@ -56,7 -54,6 +56,7 @@@
  #include "BKE_material.h"
  #include "BKE_paint.h"
  #include "BKE_property.h"
 +#include "BKE_tessmesh.h"
  
  
  #include "BIF_gl.h"
@@@ -348,10 -345,9 +348,10 @@@ static void draw_textured_end(void
        glPopMatrix();
  }
  
 -static int draw_tface__set_draw_legacy(MTFace *tface, MCol *mcol, int matnr)
 +static int draw_tface__set_draw_legacy(MTFace *tface, int has_vcol, int matnr)
  {
 -      if (tface && (tface->mode&TF_INVISIBLE)) return 0;
 +      if (tface && (tface->mode&TF_INVISIBLE))
 +              return 0;
  
        if (tface && set_draw_settings_cached(0, Gtexdraw.istex, tface, Gtexdraw.islit, Gtexdraw.ob, matnr, TF_TWOSIDE)) {
                glColor3ub(0xFF, 0x00, 0xFF);
        } else if (tface && tface->mode&TF_OBCOL) {
                glColor3ubv(Gtexdraw.obcol);
                return 2; /* Don't set color */
 -      } else if (!mcol) {
 +      } else if (!has_vcol) {
                if (tface) glColor3f(1.0, 1.0, 1.0);
                else {
                        Material *ma= give_current_material(Gtexdraw.ob, matnr+1);
                return 1; /* Set color from mcol */
        }
  }
 -static int draw_tface__set_draw(MTFace *tface, MCol *mcol, int matnr)
 +static int draw_tface__set_draw(MTFace *tface, int has_vcol, int matnr)
  {
        if (tface && (tface->mode&TF_INVISIBLE)) return 0;
  
                return 2; /* Don't set color */
        } else if (tface && tface->mode&TF_OBCOL) {
                return 2; /* Don't set color */
 -      } else if (!mcol) {
 +      } else if (!has_vcol) {
                return 1; /* Don't set color */
        } else {
                return 1; /* Set color from mcol */
  static void add_tface_color_layer(DerivedMesh *dm)
  {
        MTFace *tface = DM_get_face_data_layer(dm, CD_MTFACE);
 -      MFace *mface = DM_get_face_data_layer(dm, CD_MFACE);
 +      MFace *mface = dm->getTessFaceArray(dm);
        MCol *finalCol;
        int i,j;
 -      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);
  
 -      finalCol = MEM_mallocN(sizeof(MCol)*4*dm->getNumFaces(dm),"add_tface_color_layer");
 -      for(i=0;i<dm->getNumFaces(dm);i++) {
 +      finalCol = MEM_mallocN(sizeof(MCol)*4*dm->getNumTessFaces(dm),"add_tface_color_layer");
 +      for(i=0;i<dm->getNumTessFaces(dm);i++) {
                if (tface && (tface->mode&TF_INVISIBLE)) {
                        if( mcol )
                                memcpy(&finalCol[i*4],&mcol[i*4],sizeof(MCol)*4);
  static int draw_tface_mapped__set_draw(void *userData, int index)
  {
        Mesh *me = (Mesh*)userData;
 -      MTFace *tface = (me->mtface)? &me->mtface[index]: NULL;
 -      MFace *mface = &me->mface[index];
 -      MCol *mcol = (me->mcol)? &me->mcol[index]: NULL;
 -      const int matnr = mface->mat_nr;
 -      if (mface->flag & ME_HIDE) return 0;
 -      return draw_tface__set_draw(tface, mcol, matnr);
 +      MTexPoly *tpoly = (me->mtpoly)? &me->mtpoly[index]: NULL;
 +      MPoly *mpoly = (me->mpoly)? &me->mpoly[index]: NULL;
 +      MTFace mtf;
 +      int matnr = me->mpoly[index].mat_nr;
 +
 +      if (mpoly && mpoly->flag&ME_HIDE) return 0;
 +
 +      memset(&mtf, 0, sizeof(mtf));
 +      if (tpoly) {
 +              mtf.flag = tpoly->flag;
 +              mtf.tpage = tpoly->tpage;
 +              mtf.transp = tpoly->transp;
 +              mtf.mode = tpoly->mode;
 +              mtf.tile = tpoly->tile;
 +              mtf.unwrap = tpoly->unwrap;
 +      }
 +
 +      return draw_tface__set_draw(&mtf, CustomData_has_layer(&me->ldata, CD_MLOOPCOL), matnr);
  }
  
  static int draw_em_tf_mapped__set_draw(void *userData, int index)
  {
 -      EditMesh *em = userData;
 -      EditFace *efa= EM_get_face_for_index(index);
 -      MTFace *tface;
 -      MCol *mcol;
 -      int matnr;
 +      BMEditMesh *em = userData;
 +      BMFace *efa= EDBM_get_face_for_index(em, index);
 +      MTexPoly *tpoly;
 +      MTFace mtf;
 +      int matnr, has_vcol;
  
 -      if (efa->h)
 +      if (efa==NULL || BM_TestHFlag(efa, BM_HIDDEN))
                return 0;
  
 -      tface = CustomData_em_get(&em->fdata, efa->data, CD_MTFACE);
 -      mcol = CustomData_em_get(&em->fdata, efa->data, CD_MCOL);
 +      tpoly = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +      has_vcol = CustomData_has_layer(&em->bm->ldata, CD_MLOOPCOL);
        matnr = efa->mat_nr;
  
 -      return draw_tface__set_draw_legacy(tface, mcol, matnr);
 +      memset(&mtf, 0, sizeof(mtf));
 +
 +      if (tpoly) {
 +              mtf.flag = tpoly->flag;
 +              mtf.tpage = tpoly->tpage;
 +              mtf.transp = tpoly->transp;
 +              mtf.mode = tpoly->mode;
 +              mtf.tile = tpoly->tile;
 +              mtf.unwrap = tpoly->unwrap;
 +      }
 +
 +      return draw_tface__set_draw_legacy(&mtf, has_vcol, matnr);
  }
  
  static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
@@@ -630,11 -603,11 +630,11 @@@ void draw_mesh_textured(Scene *scene, V
        glColor4f(1.0f,1.0f,1.0f,1.0f);
  
        if(ob->mode & OB_MODE_EDIT) {
 -              dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_mesh);
 +              dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, me->edit_btmesh);
        }
        else if(faceselect) {
                if(ob->mode & OB_MODE_WEIGHT_PAINT)
-                       dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1, GPU_enable_material);
+                       dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1, GPU_enable_material, NULL);
                else
                        dm->drawMappedFacesTex(dm, me->mface ? draw_tface_mapped__set_draw : NULL, me);
        }
index 4b560048b68cd1321e8fd12dc1e553ae28dc9abe,8ca352ffe42ca1f9553cf064d07c4cb6f2cdf869..6cd27d6178a00b76d02f10397a9750af60cf7a6e
@@@ -48,7 -48,6 +48,7 @@@
  #include "DNA_world_types.h"
  #include "DNA_armature_types.h"
  
 +#include "BLI_utildefines.h"
  #include "BLI_blenlib.h"
  #include "BLI_math.h"
  #include "BLI_editVert.h"
@@@ -76,8 -75,6 +76,8 @@@
  #include "BKE_pointcache.h"
  #include "BKE_unit.h"
  
 +#include "BKE_tessmesh.h"
 +
  #include "smoke_API.h"
  
  #include "IMB_imbuf.h"
@@@ -229,7 -226,7 +229,7 @@@ static int check_material_alpha(Base *b
        if(G.f & G_PICKSEL)
                return 0;
                        
 -      if(me->edit_mesh)
 +      if(me->edit_btmesh)
                return 0;
        
        return (glsl || (base->object->dtx & OB_DRAWTRANSP));
@@@ -1637,18 -1634,16 +1637,18 @@@ static void drawlattice(Scene *scene, V
   * use the object matrix in the useual way */
  static void mesh_foreachScreenVert__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
  {
 -      struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
 -      EditVert *eve = EM_get_vert_for_index(index);
 +      struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
 +      BMVert *eve = EDBM_get_vert_for_index(data->vc.em, index);
  
 -      if (eve->h==0) {
 +      if (!BM_TestHFlag(eve, BM_HIDDEN)) {
                short s[2]= {IS_CLIPPED, 0};
  
                if (data->clipVerts) {
                        view3d_project_short_clip(data->vc.ar, co, s, 1);
                } else {
 -                      view3d_project_short_noclip(data->vc.ar, co, s);
 +                      float co2[2];
 +                      mul_v3_m4v3(co2, data->vc.obedit->obmat, co);
 +                      project_short_noclip(data->vc.ar, co2, s);
                }
  
                if (s[0]!=IS_CLIPPED)
        }
  }
  
 -void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, EditVert *eve, int x, int y, int index), void *userData, int clipVerts)
 +void mesh_foreachScreenVert(ViewContext *vc, void (*func)(void *userData, BMVert *eve, int x, int y, int index), void *userData, int clipVerts)
  {
 -      struct { void (*func)(void *userData, EditVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; } data;
 -      DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
 +      struct { void (*func)(void *userData, BMVert *eve, int x, int y, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
 +      DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
        
        data.vc= *vc;
        data.func = func;
        data.userData = userData;
        data.clipVerts = clipVerts;
  
 +      EDBM_init_index_arrays(vc->em, 1, 0, 0);
        if(clipVerts)
                ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
  
 -      EM_init_index_arrays(vc->em, 1, 0, 0);
        dm->foreachMappedVert(dm, mesh_foreachScreenVert__mapFunc, &data);
 -      EM_free_index_arrays();
 +      EDBM_free_index_arrays(vc->em);
  
        dm->release(dm);
  }
  
  static void mesh_foreachScreenEdge__mapFunc(void *userData, int index, float *v0co, float *v1co)
  {
 -      struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } *data = userData;
 -      EditEdge *eed = EM_get_edge_for_index(index);
 -      short s[2][2];
 +      struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } *data = userData;
 +      BMEdge *eed = EDBM_get_edge_for_index(data->vc.em, index);
 +
 +      if (!BM_TestHFlag(eed, BM_HIDDEN)) {
 +              short s[2][2];
  
 -      if (eed->h==0) {
                if (data->clipVerts==1) {
                        view3d_project_short_clip(data->vc.ar, v0co, s[0], 1);
                        view3d_project_short_clip(data->vc.ar, v1co, s[1], 1);
                } else {
 -                      view3d_project_short_noclip(data->vc.ar, v0co, s[0]);
 -                      view3d_project_short_noclip(data->vc.ar, v1co, s[1]);
 +                      float v1_co[3], v2_co[3];
 +
 +                      mul_v3_m4v3(v1_co, data->vc.obedit->obmat, v0co);
 +                      mul_v3_m4v3(v2_co, data->vc.obedit->obmat, v1co);
 +
 +                      project_short_noclip(data->vc.ar, v1_co, s[0]);
 +                      project_short_noclip(data->vc.ar, v2_co, s[1]);
  
                        if (data->clipVerts==2) {
                                if (!(s[0][0]>=0 && s[0][1]>= 0 && s[0][0]<data->vc.ar->winx && s[0][1]<data->vc.ar->winy))
        }
  }
  
 -void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
 +void mesh_foreachScreenEdge(ViewContext *vc, void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index), void *userData, int clipVerts)
  {
 -      struct { void (*func)(void *userData, EditEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; } data;
 -      DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
 +      struct { void (*func)(void *userData, BMEdge *eed, int x0, int y0, int x1, int y1, int index); void *userData; ViewContext vc; int clipVerts; float pmat[4][4], vmat[4][4]; } data;
 +      DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
  
        data.vc= *vc;
        data.func = func;
        data.userData = userData;
        data.clipVerts = clipVerts;
  
 +      EDBM_init_index_arrays(vc->em, 0, 1, 0);
        if(clipVerts)
                ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
  
 -      EM_init_index_arrays(vc->em, 0, 1, 0);
        dm->foreachMappedEdge(dm, mesh_foreachScreenEdge__mapFunc, &data);
 -      EM_free_index_arrays();
 +      EDBM_free_index_arrays(vc->em);
  
        dm->release(dm);
  }
  
  static void mesh_foreachScreenFace__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
  {
 -      struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } *data = userData;
 -      EditFace *efa = EM_get_face_for_index(index);
 -      short s[2];
 +      struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } *data = userData;
 +      BMFace *efa = EDBM_get_face_for_index(data->vc.em, index);
 +
 +      if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) {
 +              float cent2[3];
 +              short s[2];
  
 -      if (efa && efa->h==0 && efa->fgonf!=EM_FGON) {
 -              view3d_project_short_clip(data->vc.ar, cent, s, 1);
 +              mul_v3_m4v3(cent2, data->vc.obedit->obmat, cent);
 +              project_short(data->vc.ar, cent2, s);
  
 -              data->func(data->userData, efa, s[0], s[1], index);
 +              if (s[0] != IS_CLIPPED) {
 +                      data->func(data->userData, efa, s[0], s[1], index);
 +              }
        }
  }
  
 -void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, EditFace *efa, int x, int y, int index), void *userData)
 +void mesh_foreachScreenFace(ViewContext *vc, void (*func)(void *userData, BMFace *efa, int x, int y, int index), void *userData)
  {
 -      struct { void (*func)(void *userData, EditFace *efa, int x, int y, int index); void *userData; ViewContext vc; } data;
 -      DerivedMesh *dm = editmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
 +      struct { void (*func)(void *userData, BMFace *efa, int x, int y, int index); void *userData; ViewContext vc; float pmat[4][4], vmat[4][4]; } data;
 +      DerivedMesh *dm = editbmesh_get_derived_cage(vc->scene, vc->obedit, vc->em, CD_MASK_BAREMESH);
  
        data.vc= *vc;
        data.func = func;
        data.userData = userData;
  
 +      EDBM_init_index_arrays(vc->em, 0, 0, 1);
        //if(clipVerts)
        ED_view3d_local_clipping(vc->rv3d, vc->obedit->obmat); /* for local clipping lookups */
  
 -      EM_init_index_arrays(vc->em, 0, 0, 1);
        dm->foreachMappedFaceCenter(dm, mesh_foreachScreenFace__mapFunc, &data);
 -      EM_free_index_arrays();
 +      EDBM_free_index_arrays(vc->em);
  
        dm->release(dm);
  }
@@@ -1826,53 -1810,46 +1826,53 @@@ void nurbs_foreachScreenVert(ViewContex
  
  static void draw_dm_face_normals__mapFunc(void *userData, int index, float *cent, float *no)
  {
 -      ToolSettings *ts= ((Scene *)userData)->toolsettings;
 -      EditFace *efa = EM_get_face_for_index(index);
 +      Scene *scene= ((void **)userData)[0];
 +      BMEditMesh *em = ((void **)userData)[1];
 +      BMFace *efa = EDBM_get_face_for_index(em, index);
 +      ToolSettings *ts= scene->toolsettings;
  
 -      if (efa->h==0 && efa->fgonf!=EM_FGON) {
 +      if (!BM_TestHFlag(efa, BM_HIDDEN)) {
                glVertex3fv(cent);
                glVertex3f(     cent[0] + no[0]*ts->normalsize,
                                        cent[1] + no[1]*ts->normalsize,
                                        cent[2] + no[2]*ts->normalsize);
        }
  }
 -static void draw_dm_face_normals(Scene *scene, DerivedMesh *dm) 
 +static void draw_dm_face_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm) 
  {
 +      void *ptrs[2] = {scene, em};
 +
        glBegin(GL_LINES);
 -      dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, scene);
 +      dm->foreachMappedFaceCenter(dm, draw_dm_face_normals__mapFunc, ptrs);
        glEnd();
  }
  
  static void draw_dm_face_centers__mapFunc(void *userData, int index, float *cent, float *UNUSED(no))
  {
 -      EditFace *efa = EM_get_face_for_index(index);
 -      int sel = *((int*) userData);
 -
 -      if (efa->h==0 && efa->fgonf!=EM_FGON && (efa->f&SELECT)==sel) {
 +      BMFace *efa = EDBM_get_face_for_index(((void **)userData)[0], index);
 +      int sel = *(((int **)userData)[1]);
 +      
 +      if (efa && !BM_TestHFlag(efa, BM_HIDDEN) && BM_TestHFlag(efa, BM_SELECT)==sel) {
                bglVertex3fv(cent);
        }
  }
 -static void draw_dm_face_centers(DerivedMesh *dm, int sel)
 +static void draw_dm_face_centers(BMEditMesh *em, DerivedMesh *dm, int sel)
  {
 +      void *ptrs[2] = {em, &sel};
 +
        bglBegin(GL_POINTS);
 -      dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, &sel);
 +      dm->foreachMappedFaceCenter(dm, draw_dm_face_centers__mapFunc, ptrs);
        bglEnd();
  }
  
  static void draw_dm_vert_normals__mapFunc(void *userData, int index, float *co, float *no_f, short *no_s)
  {
 -      Scene *scene= (Scene *)userData;
 +      Scene *scene= ((void **)userData)[0];
        ToolSettings *ts= scene->toolsettings;
 -      EditVert *eve = EM_get_vert_for_index(index);
 +      BMEditMesh *em = ((void **)userData)[1];
 +      BMVert *eve = EDBM_get_vert_for_index(em, index);
  
 -      if (eve->h==0) {
 +      if (!BM_TestHFlag(eve, BM_HIDDEN)) {
                glVertex3fv(co);
  
                if (no_f) {
                }
        }
  }
 -static void draw_dm_vert_normals(Scene *scene, DerivedMesh *dm) 
 +static void draw_dm_vert_normals(BMEditMesh *em, Scene *scene, DerivedMesh *dm) 
  {
 +      void *ptrs[2] = {scene, em};
 +
        glBegin(GL_LINES);
 -      dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, scene);
 +      dm->foreachMappedVert(dm, draw_dm_vert_normals__mapFunc, ptrs);
        glEnd();
  }
  
 -      /* Draw verts with color set based on selection */
 +/* Draw verts with color set based on selection */
  static void draw_dm_verts__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
  {
 -      struct { int sel; EditVert *eve_act; } * data = userData;
 -      EditVert *eve = EM_get_vert_for_index(index);
 +      struct { BMEditMesh *em; int sel; BMVert *eve_act; } *data = userData;
 +      BMVert *eve = EDBM_get_vert_for_index(data->em, index);
  
 -      if (eve->h==0 && (eve->f&SELECT)==data->sel) {
 +      if (!BM_TestHFlag(eve, BM_HIDDEN) && BM_TestHFlag(eve, BM_SELECT)==data->sel) {
                /* draw active larger - need to stop/start point drawing for this :/ */
                if (eve==data->eve_act) {
                        float size = UI_GetThemeValuef(TH_VERTEX_SIZE);
        }
  }
  
 -static void draw_dm_verts(DerivedMesh *dm, int sel, EditVert *eve_act)
 +static void draw_dm_verts(BMEditMesh *em, DerivedMesh *dm, int sel, BMVert *eve_act)
  {
 -      struct { int sel; EditVert *eve_act; } data;
 +      struct { BMEditMesh *em; int sel; BMVert *eve_act; } data;
        data.sel = sel;
        data.eve_act = eve_act;
 +      data.em = em;
 +      
 +      bglBegin(GL_POINTS);
 +      dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
 +      bglEnd();
  
        bglBegin(GL_POINTS);
        dm->foreachMappedVert(dm, draw_dm_verts__mapFunc, &data);
        /* Draw edges with color set based on selection */
  static int draw_dm_edges_sel__setDrawOptions(void *userData, int index)
  {
 -      EditEdge *eed = EM_get_edge_for_index(index);
 +      BMEdge *eed;
        //unsigned char **cols = userData, *col;
 -      struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } * data = userData;
 +      struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } * data = userData;
        unsigned char *col;
  
 -      if (eed->h==0) {
 +      eed = EDBM_get_edge_for_index(data->em, index);
 +
 +      if (!BM_TestHFlag(eed, BM_HIDDEN)) {
                if (eed==data->eed_act) {
                        glColor4ubv(data->actCol);
                } else {
 -                      if (eed->f&SELECT) {
 +                      if (BM_TestHFlag(eed, BM_SELECT)) {
                                col = data->selCol;
                        } else {
                                col = data->baseCol;
                return 0;
        }
  }
 -static void draw_dm_edges_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditEdge *eed_act) 
 +static void draw_dm_edges_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, 
 +                            unsigned char *selCol, unsigned char *actCol, BMEdge *eed_act) 
  {
 -      struct { unsigned char *baseCol, *selCol, *actCol; EditEdge *eed_act; } data;
 +      struct { BMEditMesh *em; unsigned char *baseCol, *selCol, *actCol; BMEdge *eed_act; } data;
        
        data.baseCol = baseCol;
        data.selCol = selCol;
        data.actCol = actCol;
 +      data.em = em;
        data.eed_act = eed_act;
        dm->drawMappedEdges(dm, draw_dm_edges_sel__setDrawOptions, &data);
  }
  
        /* Draw edges */
 -static int draw_dm_edges__setDrawOptions(void *UNUSED(userData), int index)
 +static int draw_dm_edges__setDrawOptions(void *userData, int index)
  {
 -      return EM_get_edge_for_index(index)->h==0;
 +      return !BM_TestHFlag(EDBM_get_edge_for_index(userData, index), BM_HIDDEN);
  }
 -static void draw_dm_edges(DerivedMesh *dm) 
 +static void draw_dm_edges(BMEditMesh *em, DerivedMesh *dm) 
  {
 -      dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, NULL);
 +      dm->drawMappedEdges(dm, draw_dm_edges__setDrawOptions, em);
  }
  
        /* Draw edges with color interpolated based on selection */
 -static int draw_dm_edges_sel_interp__setDrawOptions(void *UNUSED(userData), int index)
 +static int draw_dm_edges_sel_interp__setDrawOptions(void *userData, int index)
  {
 -      return EM_get_edge_for_index(index)->h==0;
 +      return !BM_TestHFlag(EDBM_get_edge_for_index(((void**)userData)[0], index), BM_HIDDEN);
  }
  static void draw_dm_edges_sel_interp__setDrawInterpOptions(void *userData, int index, float t)
  {
 -      EditEdge *eed = EM_get_edge_for_index(index);
 +      BMEdge *eed = EDBM_get_edge_for_index(((void**)userData)[0], index);
        unsigned char **cols = userData;
 -      unsigned char *col0 = cols[(eed->v1->f&SELECT)?1:0];
 -      unsigned char *col1 = cols[(eed->v2->f&SELECT)?1:0];
 +      unsigned char *col0 = cols[(BM_TestHFlag(eed->v1, BM_SELECT))?2:1];
 +      unsigned char *col1 = cols[(BM_TestHFlag(eed->v2, BM_SELECT))?2:1];
  
        glColor4ub(     col0[0] + (col1[0]-col0[0])*t,
                                col0[1] + (col1[1]-col0[1])*t,
                                col0[3] + (col1[3]-col0[3])*t);
  }
  
 -static void draw_dm_edges_sel_interp(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
 +static void draw_dm_edges_sel_interp(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol)
  {
 -      unsigned char *cols[2];
 -      cols[0]= baseCol;
 -      cols[1]= selCol;
 +      void *cols[3] = {em, baseCol, selCol};
 +
        dm->drawMappedEdgesInterp(dm, draw_dm_edges_sel_interp__setDrawOptions, draw_dm_edges_sel_interp__setDrawInterpOptions, cols);
  }
  
        /* Draw only seam edges */
 -static int draw_dm_edges_seams__setDrawOptions(void *UNUSED(userData), int index)
 +static int draw_dm_edges_seams__setDrawOptions(void *userData, int index)
  {
 -      EditEdge *eed = EM_get_edge_for_index(index);
 +      BMEdge *eed = EDBM_get_edge_for_index(userData, index);
  
 -      return (eed->h==0 && eed->seam);
 +      return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SEAM);
  }
 -static void draw_dm_edges_seams(DerivedMesh *dm)
 +
 +static void draw_dm_edges_seams(BMEditMesh *em, DerivedMesh *dm)
  {
 -      dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, NULL);
 +      dm->drawMappedEdges(dm, draw_dm_edges_seams__setDrawOptions, em);
  }
  
        /* Draw only sharp edges */
 -static int draw_dm_edges_sharp__setDrawOptions(void *UNUSED(userData), int index)
 +static int draw_dm_edges_sharp__setDrawOptions(void *userData, int index)
  {
 -      EditEdge *eed = EM_get_edge_for_index(index);
 +      BMEdge *eed = EDBM_get_edge_for_index(userData, index);
  
 -      return (eed->h==0 && eed->sharp);
 +      return !BM_TestHFlag(eed, BM_HIDDEN) && BM_TestHFlag(eed, BM_SHARP);
  }
 -static void draw_dm_edges_sharp(DerivedMesh *dm)
 +static void draw_dm_edges_sharp(BMEditMesh *em, DerivedMesh *dm)
  {
 -      dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, NULL);
 +      dm->drawMappedEdges(dm, draw_dm_edges_sharp__setDrawOptions, em);
  }
  
  
         * return 2 for the active face so it renders with stipple enabled */
  static int draw_dm_faces_sel__setDrawOptions(void *userData, int index, int *UNUSED(drawSmooth_r))
  {
 -      struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
 -      EditFace *efa = EM_get_face_for_index(index);
 +      struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} *data = userData;
 +      BMFace *efa = EDBM_get_face_for_index(data->em, index);
        unsigned char *col;
        
 -      if (efa->h==0) {
 +      if (!efa)
 +              return 0;
 +      
 +      if (!BM_TestHFlag(efa, BM_HIDDEN)) {
                if (efa == data->efa_act) {
                        glColor4ubv(data->cols[2]);
 +
                        return 2; /* stipple */
                } else {
 -                      col = data->cols[(efa->f&SELECT)?1:0];
 +                      col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0];
                        if (col[3]==0) return 0;
 +
                        glColor4ubv(col);
 +
                        return 1;
                }
        }
        return 0;
  }
  
 -      struct { unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
 -      EditFace *efa = EM_get_face_for_index(index);
 -      EditFace *next_efa = EM_get_face_for_index(next_index);
+ static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_index)
+ {
 -      col = data->cols[(efa->f&SELECT)?1:0];
 -      next_col = data->cols[(next_efa->f&SELECT)?1:0];
++      struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} * data = userData;
++      BMFace *efa = EDBM_get_face_for_index(data->em, index);
++      BMFace *next_efa = EDBM_get_face_for_index(data->em, next_index);
+       unsigned char *col, *next_col;
+       if(efa == next_efa)
+               return 1;
+       if(efa == data->efa_act || next_efa == data->efa_act)
+               return 0;
++      col = data->cols[BM_TestHFlag(efa, BM_SELECT)?1:0];
++      next_col = data->cols[BM_TestHFlag(next_efa, BM_SELECT)?1:0];
+       if(col[3]==0 || next_col[3]==0)
+               return 0;
+       return col == next_col;
+ }
  /* also draws the active face */
 -static void draw_dm_faces_sel(DerivedMesh *dm, unsigned char *baseCol, unsigned char *selCol, unsigned char *actCol, EditFace *efa_act) 
 +static void draw_dm_faces_sel(BMEditMesh *em, DerivedMesh *dm, unsigned char *baseCol, 
 +                            unsigned char *selCol, unsigned char *actCol, BMFace *efa_act, Mesh *me) 
  {
 -      struct { unsigned char *cols[3]; EditFace *efa_act; } data;
 +      struct { unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} data;
 +
        data.cols[0] = baseCol;
 +      data.em = em;
        data.cols[1] = selCol;
        data.cols[2] = actCol;
        data.efa_act = efa_act;
 +      data.me = me;
  
-       dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material);
+       dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, &data, 0, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions);
  }
  
 -static int draw_dm_creases__setDrawOptions(void *UNUSED(userData), int index)
 +static int draw_dm_creases__setDrawOptions(void *userData, int index)
  {
 -      EditEdge *eed = EM_get_edge_for_index(index);
 -
 -      if (eed->h==0 && eed->crease != 0.0f) {
 -              UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, eed->crease);
 +      BMEditMesh *em = userData;
 +      BMEdge *eed = EDBM_get_edge_for_index(userData, index);
 +      float *crease = eed ? bm_get_cd_float(&em->bm->edata, eed->head.data, CD_CREASE) : NULL;
 +      
 +      if (!crease)
 +              return 0;
 +      
 +      if (!BM_TestHFlag(eed, BM_HIDDEN) && *crease!=0.0f) {
 +              UI_ThemeColorBlend(TH_WIRE, TH_EDGE_CREASE, *crease);
                return 1;
        } else {
                return 0;
        }
  }
 -static void draw_dm_creases(DerivedMesh *dm)
 +static void draw_dm_creases(BMEditMesh *em, DerivedMesh *dm)
  {
        glLineWidth(3.0);
 -      dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, NULL);
 +      dm->drawMappedEdges(dm, draw_dm_creases__setDrawOptions, em);
        glLineWidth(1.0);
  }
  
 -static int draw_dm_bweights__setDrawOptions(void *UNUSED(userData), int index)
 +static int draw_dm_bweights__setDrawOptions(void *userData, int index)
  {
 -      EditEdge *eed = EM_get_edge_for_index(index);
 +      BMEditMesh *em = userData;
 +      BMEdge *eed = EDBM_get_edge_for_index(userData, index);
 +      float *bweight = bm_get_cd_float(&em->bm->edata, eed->head.data, CD_BWEIGHT);
  
 -      if (eed->h==0 && eed->bweight != 0.0f) {
 -              UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, eed->bweight);
 +      if (!bweight)
 +              return 0;
 +      
 +      if (!BM_TestHFlag(eed, BM_HIDDEN) && *bweight!=0.0f) {
 +              UI_ThemeColorBlend(TH_WIRE, TH_EDGE_SELECT, *bweight);
                return 1;
        } else {
                return 0;
        }
  }
 -static void draw_dm_bweights__mapFunc(void *UNUSED(userData), int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
 +static void draw_dm_bweights__mapFunc(void *userData, int index, float *co, float *UNUSED(no_f), short *UNUSED(no_s))
  {
 -      EditVert *eve = EM_get_vert_for_index(index);
 -
 -      if (eve->h==0 && eve->bweight != 0.0f) {
 -              UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, eve->bweight);
 +      BMEditMesh *em = userData;
 +      BMVert *eve = EDBM_get_vert_for_index(userData, index);
 +      float *bweight = bm_get_cd_float(&em->bm->vdata, eve->head.data, CD_BWEIGHT);
 +      
 +      if (!bweight)
 +              return;
 +      
 +      if (!BM_TestHFlag(eve, BM_HIDDEN) && *bweight!=0.0f) {
 +              UI_ThemeColorBlend(TH_VERTEX, TH_VERTEX_SELECT, *bweight);
                bglVertex3fv(co);
        }
  }
 -static void draw_dm_bweights(Scene *scene, DerivedMesh *dm)
 +static void draw_dm_bweights(BMEditMesh *em, Scene *scene, DerivedMesh *dm)
  {
        ToolSettings *ts= scene->toolsettings;
  
        if (ts->selectmode & SCE_SELECT_VERTEX) {
                glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE) + 2);
                bglBegin(GL_POINTS);
 -              dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, NULL);
 +              dm->foreachMappedVert(dm, draw_dm_bweights__mapFunc, em);
                bglEnd();
        }
        else {
                glLineWidth(3.0);
 -              dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, NULL);
 +              dm->drawMappedEdges(dm, draw_dm_bweights__setDrawOptions, em);
                glLineWidth(1.0);
        }
  }
  
  /* EditMesh drawing routines*/
  
 -static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, DerivedMesh *cageDM, EditVert *eve_act)
 +static void draw_em_fancy_verts(Scene *scene, View3D *v3d, Object *obedit, 
 +                              BMEditMesh *em, DerivedMesh *cageDM, BMVert *eve_act)
  {
        ToolSettings *ts= scene->toolsettings;
        int sel;
                        if(ts->selectmode & SCE_SELECT_VERTEX) {
                                glPointSize(size);
                                glColor4ubv(col);
 -                              draw_dm_verts(cageDM, sel, eve_act);
 +                              draw_dm_verts(em, cageDM, sel, eve_act);
                        }
                        
                        if(check_ob_drawface_dot(scene, v3d, obedit->dt)) {
                                glPointSize(fsize);
                                glColor4ubv(fcol);
 -                              draw_dm_face_centers(cageDM, sel);
 +                              draw_dm_face_centers(em, cageDM, sel);
                        }
                        
                        if (pass==0) {
        glPointSize(1.0);
  }
  
 -static void draw_em_fancy_edges(Scene *scene, View3D *v3d, Mesh *me, DerivedMesh *cageDM, short sel_only, EditEdge *eed_act)
 +static void draw_em_fancy_edges(BMEditMesh *em, Scene *scene, View3D *v3d, 
 +                              Mesh *me, DerivedMesh *cageDM, short sel_only, 
 +                              BMEdge *eed_act)
  {
        ToolSettings *ts= scene->toolsettings;
        int pass;
                }
  
                if(ts->selectmode == SCE_SELECT_FACE) {
 -                      draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
 +                      draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
                }       
                else if( (me->drawflag & ME_DRAWEDGES) || (ts->selectmode & SCE_SELECT_EDGE) ) {        
                        if(cageDM->drawMappedEdgesInterp && (ts->selectmode & SCE_SELECT_VERTEX)) {
                                glShadeModel(GL_SMOOTH);
 -                              draw_dm_edges_sel_interp(cageDM, wireCol, selCol);
 +                              draw_dm_edges_sel_interp(em, cageDM, wireCol, selCol);
                                glShadeModel(GL_FLAT);
                        } else {
 -                              draw_dm_edges_sel(cageDM, wireCol, selCol, actCol, eed_act);
 +                              draw_dm_edges_sel(em, cageDM, wireCol, selCol, actCol, eed_act);
                        }
                }
                else {
                        if (!sel_only) {
                                glColor4ubv(wireCol);
 -                              draw_dm_edges(cageDM);
 +                              draw_dm_edges(em, cageDM);
                        }
                }
  
        }
  }     
  
 -static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, UnitSettings *unit)
 +static void draw_em_measure_stats(View3D *v3d, RegionView3D *rv3d, 
 +                                Object *ob, BMEditMesh *em, UnitSettings *unit)
  {
        Mesh *me= ob->data;
 -      EditEdge *eed;
 -      EditFace *efa;
 -      float v1[3], v2[3], v3[3], v4[3], vmid[3];
 -      float fvec[3];
 +      float v1[3], v2[3], v3[3], vmid[3], fvec[3];
        char val[32]; /* Stores the measurement display text here */
        const char *conv_float; /* Use a float conversion matching the grid size */
        unsigned char col[4]= {0, 0, 0, 255}; /* color of the text to draw */
        const int do_global= v3d->flag & V3D_GLOBAL_STATS;
        const int do_moving= G.moving;
  
 +      BMIter iter;
 +      int i;
 +
        /* make the precision of the pronted value proportionate to the gridsize */
  
        if (grid < 0.01f)               conv_float= "%.6g";
        if(v3d->zbuf) bglPolygonOffset(rv3d->dist, 5.0f);
        
        if(me->drawflag & ME_DRAWEXTRA_EDGELEN) {
 +              BMEdge *eed;
 +
                UI_GetThemeColor3ubv(TH_DRAWEXTRA_EDGELEN, col);
  
 -              for(eed= em->edges.first; eed; eed= eed->next) {
 -                      /* draw non fgon edges, or selected edges, or edges next to selected verts while draging */
 -                      if((eed->h != EM_FGON) && ((eed->f & SELECT) || (do_moving && ((eed->v1->f & SELECT) || (eed->v2->f & SELECT)) ))) {
 +              eed = BMIter_New(&iter, em->bm, BM_EDGES_OF_MESH, NULL);
 +              for(; eed; eed=BMIter_Step(&iter)) {
 +                      /* draw selected edges, or edges next to selected verts while draging */
 +                      if(BM_TestHFlag(eed, BM_SELECT) ||
 +                              (do_moving && (BM_TestHFlag(eed->v1, BM_SELECT) || BM_TestHFlag(eed->v2, BM_SELECT) ))) {
 +
                                copy_v3_v3(v1, eed->v1->co);
                                copy_v3_v3(v2, eed->v2->co);
  
        }
  
        if(me->drawflag & ME_DRAWEXTRA_FACEAREA) {
 -// XXX                extern int faceselectedOR(EditFace *efa, int flag);             // editmesh.h shouldn't be in this file... ok for now?
 +              /* would be nice to use BM_face_area, but that is for 2d faces
 +              so instead add up tessalation triangle areas */
 +              BMFace *f;
 +              int n;
 +
 +#define DRAW_EM_MEASURE_STATS_FACEAREA(void)\
 +              if (BM_TestHFlag(f, BM_SELECT)) {\
 +                      mul_v3_fl(vmid, 1.0/n);\
 +                      if(unit->system)\
 +                              bUnit_AsString(val, sizeof(val), area*unit->scale_length,\
 +                                      3, unit->system, B_UNIT_LENGTH, do_split, FALSE);\
 +                      else\
 +                              sprintf(val, conv_float, area);\
 +                      view3d_cached_text_draw_add(vmid, val, 0, V3D_CACHE_TEXT_ASCII, col);\
 +              }
 +
                UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEAREA, col);
                
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      if((efa->f & SELECT)) { // XXX || (do_moving && faceselectedOR(efa, SELECT)) ) {
 -                              copy_v3_v3(v1, efa->v1->co);
 -                              copy_v3_v3(v2, efa->v2->co);
 -                              copy_v3_v3(v3, efa->v3->co);
 -                              if (efa->v4) {
 -                                      copy_v3_v3(v4, efa->v4->co);
 -                              }
 -                              if(do_global) {
 -                                      mul_mat3_m4_v3(ob->obmat, v1);
 -                                      mul_mat3_m4_v3(ob->obmat, v2);
 -                                      mul_mat3_m4_v3(ob->obmat, v3);
 -                                      if (efa->v4) mul_mat3_m4_v3(ob->obmat, v4);
 -                              }
 -                              
 -                              if (efa->v4)
 -                                      area=  area_quad_v3(v1, v2, v3, v4);
 -                              else
 -                                      area = area_tri_v3(v1, v2, v3);
 -
 -                              if(unit->system)
 -                                      bUnit_AsString(val, sizeof(val), area*unit->scale_length, 3, unit->system, B_UNIT_LENGTH, do_split, FALSE); // XXX should be B_UNIT_AREA
 -                              else
 -                                      sprintf(val, conv_float, area);
 -
 -                              view3d_cached_text_draw_add(efa->cent, val, 0, V3D_CACHE_TEXT_ASCII, col);
 +              f = NULL;
 +              area = 0.0;
 +              zero_v3(vmid);
 +              n = 0;
 +              for(i = 0; i < em->tottri; i++) {
 +                      BMLoop **l = em->looptris[i];
 +                      if(f && l[0]->f != f) {
 +                              DRAW_EM_MEASURE_STATS_FACEAREA();
 +                              zero_v3(vmid);
 +                              area = 0.0;
 +                              n = 0;
                        }
 -              }
 -      }
  
 -      if(me->drawflag & ME_DRAWEXTRA_FACEANG) {
 -              EditEdge *e1, *e2, *e3, *e4;
 -              UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
 -              for(efa= em->faces.first; efa; efa= efa->next) {
 -                      copy_v3_v3(v1, efa->v1->co);
 -                      copy_v3_v3(v2, efa->v2->co);
 -                      copy_v3_v3(v3, efa->v3->co);
 -                      if(efa->v4) {
 -                              copy_v3_v3(v4, efa->v4->co); 
 -                      }
 -                      else {
 -                              copy_v3_v3(v4, v3);
 -                      }
 +                      f = l[0]->f;
 +                      copy_v3_v3(v1, l[0]->v->co);
 +                      copy_v3_v3(v2, l[1]->v->co);
 +                      copy_v3_v3(v3, l[2]->v->co);
                        if(do_global) {
                                mul_mat3_m4_v3(ob->obmat, v1);
                                mul_mat3_m4_v3(ob->obmat, v2);
                                mul_mat3_m4_v3(ob->obmat, v3);
 -                              mul_mat3_m4_v3(ob->obmat, v4); /* intentionally executed even for tri's */
 -                      }
 -                      
 -                      e1= efa->e1;
 -                      e2= efa->e2;
 -                      e3= efa->e3;
 -                      if(efa->e4) e4= efa->e4; else e4= e3;
 -                      
 -                      /* Calculate the angles */
 -                              
 -                      if( (e4->f & e1->f & SELECT) || (do_moving && (efa->v1->f & SELECT)) ) {
 -                              /* Vec 1 */
 -                              sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v4, v1, v2)));
 -                              interp_v3_v3v3(fvec, efa->cent, efa->v1->co, 0.8f);
 -                              view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
                        }
 -                      if( (e1->f & e2->f & SELECT) || (do_moving && (efa->v2->f & SELECT)) ) {
 -                              /* Vec 2 */
 -                              sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
 -                              interp_v3_v3v3(fvec, efa->cent, efa->v2->co, 0.8f);
 -                              view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
 -                      }
 -                      if( (e2->f & e3->f & SELECT) || (do_moving && (efa->v3->f & SELECT)) ) {
 -                              /* Vec 3 */
 -                              if(efa->v4) 
 -                                      sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v4)));
 -                              else
 -                                      sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v2, v3, v1)));
 -                              interp_v3_v3v3(fvec, efa->cent, efa->v3->co, 0.8f);
 -                              view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
 -                      }
 -                              /* Vec 4 */
 -                      if(efa->v4) {
 -                              if( (e3->f & e4->f & SELECT) || (do_moving && (efa->v4->f & SELECT)) ) {
 -                                      sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v3, v4, v1)));
 -                                      interp_v3_v3v3(fvec, efa->cent, efa->v4->co, 0.8f);
 +                      area += area_tri_v3(v1, v2, v3);
 +                      add_v3_v3(vmid, v1);
 +                      add_v3_v3(vmid, v2);
 +                      add_v3_v3(vmid, v3);
 +                      n += 3;
 +              }
 +
 +              if(f){
 +                      DRAW_EM_MEASURE_STATS_FACEAREA();
 +              }
 +#undef DRAW_EM_MEASURE_STATS_FACEAREA
 +      }
 +
 +      if(me->drawflag & ME_DRAWEXTRA_FACEANG) {
 +              BMFace *efa;
 +
 +              UI_GetThemeColor3ubv(TH_DRAWEXTRA_FACEANG, col);
 +
 +
 +              for(efa = BMIter_New(&iter, em->bm, BM_FACES_OF_MESH, NULL);
 +                  efa; efa=BMIter_Step(&iter)) {
 +                      BMIter liter;
 +                      BMLoop *loop;
 +
 +                      BM_Compute_Face_Center(em->bm, efa, vmid);
 +
 +                      for(loop = BMIter_New(&liter, em->bm, BM_LOOPS_OF_FACE, efa);
 +                          loop; loop = BMIter_Step(&liter)) {
 +
 +                              float v1[3], v2[3], v3[3];
 +
 +                              copy_v3_v3(v1, loop->prev->v->co);
 +                              copy_v3_v3(v2, loop->v->co);
 +                              copy_v3_v3(v3, loop->next->v->co);
 +
 +                              if(do_global){
 +                                      mul_mat3_m4_v3(ob->obmat, v1);
 +                                      mul_mat3_m4_v3(ob->obmat, v2);
 +                                      mul_mat3_m4_v3(ob->obmat, v3);
 +                              }
 +
 +                              if(BM_TestHFlag(efa, BM_SELECT) ||
 +                                      (do_moving && BM_TestHFlag(loop->v, BM_SELECT))){
 +                                      sprintf(val,"%.3g", RAD2DEGF(angle_v3v3v3(v1, v2, v3)));
 +                                      interp_v3_v3v3(fvec, vmid, v2, 0.8f);
                                        view3d_cached_text_draw_add(fvec, val, 0, V3D_CACHE_TEXT_ASCII, col);
                                }
                        }
        }
  }
  
 -static int draw_em_fancy__setFaceOpts(void *UNUSED(userData), int index, int *UNUSED(drawSmooth_r))
 +static int draw_em_fancy__setFaceOpts(void *userData, int index, int *UNUSED(drawSmooth_r))
  {
 -      EditFace *efa = EM_get_face_for_index(index);
 +      BMFace *efa = EDBM_get_face_for_index(userData, index);
  
 -      if (efa->h==0) {
 +      if (efa && !BM_TestHFlag(efa, BM_HIDDEN)) {
                GPU_enable_material(efa->mat_nr+1, NULL);
                return 1;
        }
                return 0;
  }
  
 -static int draw_em_fancy__setGLSLFaceOpts(void *UNUSED(userData), int index)
 +static int draw_em_fancy__setGLSLFaceOpts(void *userData, int index)
  {
 -      EditFace *efa = EM_get_face_for_index(index);
 +      BMFace *efa = EDBM_get_face_for_index(userData, index);
  
 -      return (efa->h==0);
 +      return !BM_TestHFlag(efa, BM_HIDDEN);
  }
  
 -static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, EditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
 +static void draw_em_fancy(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob,
 +                        BMEditMesh *em, DerivedMesh *cageDM, DerivedMesh *finalDM, int dt)
 +
  {
        Mesh *me = ob->data;
 -      EditFace *efa_act = EM_get_actFace(em, 0); /* annoying but active faces is stored differently */
 -      EditEdge *eed_act = NULL;
 -      EditVert *eve_act = NULL;
 +      BMFace *efa_act = EDBM_get_actFace(em, 0); /* annoying but active faces is stored differently */
 +      BMEdge *eed_act = NULL;
 +      BMVert *eve_act = NULL;
        
 -      if (em->selected.last) {
 -              EditSelection *ese = em->selected.last;
 +      if (em->bm->selected.last) {
 +              BMEditSelection *ese = em->bm->selected.last;
                /* face is handeled above */
                /*if (ese->type == EDITFACE ) {
                        efa_act = (EditFace *)ese->data;
                } else */ if ( ese->type == EDITEDGE ) {
 -                      eed_act = (EditEdge *)ese->data;
 +                      eed_act = (BMEdge *)ese->data;
                } else if ( ese->type == EDITVERT ) {
 -                      eve_act = (EditVert *)ese->data;
 +                      eve_act = (BMVert *)ese->data;
                }
        }
        
 -      EM_init_index_arrays(em, 1, 1, 1);
 +      EDBM_init_index_arrays(em, 1, 1, 1);
  
        if(dt>OB_WIRE) {
                if(CHECK_OB_DRAWTEXTURE(v3d, dt)) {
                                glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
  
                                finalDM->drawMappedFacesGLSL(finalDM, GPU_enable_material,
 -                                      draw_em_fancy__setGLSLFaceOpts, NULL);
 +                                      draw_em_fancy__setGLSLFaceOpts, em);
                                GPU_disable_material();
  
                                glFrontFace(GL_CCW);
  
                        glEnable(GL_LIGHTING);
                        glFrontFace((ob->transflag&OB_NEG_SCALE)?GL_CW:GL_CCW);
-                       finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, me->edit_btmesh, 0, GPU_enable_material);
 -
 -                      finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, NULL, 0, GPU_enable_material, NULL);
++                      finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, me->edit_btmesh, 0, GPU_enable_material, NULL);
  
                        glFrontFace(GL_CCW);
                        glDisable(GL_LIGHTING);
                if CHECK_OB_DRAWTEXTURE(v3d, dt)
                        col1[3] = 0;
                
 -              draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
 +              draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me);
  
                glDisable(GL_BLEND);
                glDepthMask(1);         // restore write in zbuffer
                glEnable(GL_BLEND);
                glDepthMask(0);         // disable write in zbuffer, needed for nice transp
                
 -              draw_dm_faces_sel(cageDM, col1, col2, col3, efa_act);
 +              draw_dm_faces_sel(em, cageDM, col1, col2, col3, efa_act, me);
  
                glDisable(GL_BLEND);
                glDepthMask(1);         // restore write in zbuffer