svn merge ^/trunk/blender -r42303:42329
authorCampbell Barton <ideasman42@gmail.com>
Fri, 2 Dec 2011 01:01:07 +0000 (01:01 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Fri, 2 Dec 2011 01:01:07 +0000 (01:01 +0000)
14 files changed:
1  2 
intern/cycles/blender/blender_mesh.cpp
source/blender/blenkernel/BKE_DerivedMesh.h
source/blender/blenkernel/intern/DerivedMesh.c
source/blender/blenkernel/intern/cdderivedmesh.c
source/blender/blenkernel/intern/dynamicpaint.c
source/blender/blenkernel/intern/editderivedbmesh.c
source/blender/blenkernel/intern/mesh.c
source/blender/blenkernel/intern/mesh_validate.c
source/blender/blenkernel/intern/subsurf_ccg.c
source/blender/editors/space_view3d/drawmesh.c
source/blender/editors/space_view3d/drawobject.c
source/blender/makesdna/DNA_meshdata_types.h
source/blender/makesdna/intern/dna_genfile.c
source/blender/makesrna/RNA_access.h

@@@ -313,8 -254,12 +313,12 @@@ struct DerivedMesh 
         *  o Drawing options too complicated to enumerate, look at code.
         */
        void (*drawFacesTex)(DerivedMesh *dm,
 -                                               int (*setDrawOptions)(struct MTFace *tface,
 -                                                       int has_mcol, int matnr),
 +                           int (*setDrawOptions)(struct MTFace *tface,
-                            int has_vcol, int matnr));
++                           int has_vcol, int matnr),
+                                               int (*compareDrawOptions)(void *userData,
+                                                        int cur_index,
+                                                        int next_index),
+                                               void *userData);
  
        /* Draw all faces with GLSL materials
         *  o setMaterial is called for every different material nr
index df28ab9,0000000..888ebb8
mode 100644,000000..100644
--- /dev/null
@@@ -1,1719 -1,0 +1,1729 @@@
-       void *userData, int UNUSED(useColors),
 +/*
 + * ***** BEGIN GPL LICENSE BLOCK *****
 + *
 + * This program is free software; you can redistribute it and/or
 + * modify it under the terms of the GNU General Public License
 + * as published by the Free Software Foundation; either version 2
 + * of the License, or (at your option) any later version.
 + *
 + * This program is distributed in the hope that it will be useful,
 + * but WITHOUT ANY WARRANTY; without even the implied warranty of
 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 + * GNU General Public License for more details.
 + *
 + * You should have received a copy of the GNU General Public License
 + * along with this program; if not, write to the Free Software Foundation,
 + * Inc., 59 Tbmple Place - Suite 330, Boston, MA  02111-1307, USA.
 + *
 + * The Original Code is Copyright (C) 2005 Blender Foundation.
 + * All rights reserved.
 + *
 + * The Original Code is: all of this file.
 + *
 + * Contributor(s): none yet.
 + *
 + * ***** END GPL LICENSE BLOCK *****
 + */
 +
 +#include <string.h>
 +
 +#ifdef HAVE_CONFIG_H
 +#include <config.h>
 +#endif
 +
 +#include "PIL_time.h"
 +
 +#include "MEM_guardedalloc.h"
 +
 +#include "DNA_effect_types.h"
 +#include "DNA_mesh_types.h"
 +#include "DNA_key_types.h"
 +#include "DNA_meshdata_types.h"
 +#include "DNA_modifier_types.h"
 +#include "DNA_object_types.h"
 +#include "DNA_object_force.h"
 +#include "DNA_object_fluidsim.h" // N_T
 +#include "DNA_scene_types.h" // N_T
 +#include "DNA_texture_types.h"
 +#include "DNA_view3d_types.h"
 +#include "DNA_screen_types.h"
 +#include "DNA_space_types.h"
 +#include "DNA_particle_types.h"
 +
 +#include "BLI_utildefines.h"
 +#include "BLI_math.h"
 +#include "BLI_blenlib.h"
 +#include "BLI_editVert.h"
 +#include "BLI_edgehash.h"
 +#include "BLI_linklist.h"
 +#include "BLI_memarena.h"
 +#include "BLI_scanfill.h"
 +#include "BLI_ghash.h"
 +#include "BLI_array.h"
 +
 +#include "BKE_cdderivedmesh.h"
 +#include "BKE_customdata.h"
 +#include "BKE_DerivedMesh.h"
 +#include "BKE_deform.h"
 +#include "BKE_displist.h"
 +#include "BKE_effect.h"
 +#include "BKE_fluidsim.h"
 +#include "BKE_global.h"
 +#include "BKE_key.h"
 +#include "BKE_material.h"
 +#include "BKE_modifier.h"
 +#include "BKE_mesh.h"
 +#include "BKE_object.h"
 +#include "BKE_subsurf.h"
 +#include "BKE_texture.h"
 +#include "BKE_particle.h"
 +#include "BKE_tessmesh.h"
 +
 +#include "BLO_sys_types.h" // for intptr_t support
 +
 +#include "GL/glew.h"
 +
 +#include "GPU_draw.h"
 +#include "GPU_extensions.h"
 +#include "GPU_material.h"
 +
 +#include "bmesh.h"
 +
 +extern GLubyte stipple_quarttone[128]; /* glutil.c, bad level data */
 +
 +
 +BMEditMesh *BMEdit_Create(BMesh *bm)
 +{
 +      BMEditMesh *tm = MEM_callocN(sizeof(BMEditMesh), __func__);
 +      
 +      tm->bm = bm;
 +
 +      BMEdit_RecalcTesselation(tm);
 +
 +      return tm;
 +}
 +
 +BMEditMesh *BMEdit_Copy(BMEditMesh *tm)
 +{
 +      BMEditMesh *tm2 = MEM_callocN(sizeof(BMEditMesh), __func__);
 +      *tm2 = *tm;
 +      
 +      tm2->derivedCage = tm2->derivedFinal = NULL;
 +
 +      tm2->bm = BM_Copy_Mesh(tm->bm);
 +
 +      /*The tesselation is NOT calculated on the copy here,
 +        because currently all the callers of this function use
 +        it to make a backup copy of the BMEditMesh to restore
 +        it in the case of errors in an operation. For perf
 +        reasons, in that case it makes more sense to do the
 +        tesselation only when/if that copy ends up getting
 +        used.*/
 +      tm2->looptris = NULL;
 +
 +      tm2->vert_index = NULL;
 +      tm2->edge_index = NULL;
 +      tm2->face_index = NULL;
 +
 +      return tm2;
 +}
 +
 +static void BMEdit_RecalcTesselation_intern(BMEditMesh *tm)
 +{
 +      /* use this to avoid locking pthread for _every_ polygon
 +       * and calling the fill function */
 +#define USE_TESSFACE_SPEEDUP
 +
 +      BMesh *bm = tm->bm;
 +      BMLoop *(*looptris)[3]= 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)) {
 +              /*don't consider two-edged faces*/
 +              if (f->len < 3) {
 +                      /* do nothing */
 +              }
 +
 +#ifdef USE_TESSFACE_SPEEDUP
 +
 +              /* no need to ensure the loop order, we know its ok */
 +
 +              else if (f->len == 3) {
 +                      BLI_array_growone(looptris);
 +                      l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +                      for (j=0; l; l=BMIter_Step(&liter), j++) {
 +                              looptris[i][j] = l;
 +                      }
 +                      i += 1;
 +              }
 +              else if (f->len == 4) {
 +                      BMLoop *ltmp[4];
 +                      BLI_array_growitems(looptris, 2);
 +
 +                      l = BMIter_New(&liter, bm, BM_LOOPS_OF_FACE, f);
 +                      for (j=0; l; l=BMIter_Step(&liter), j++) {
 +                              ltmp[j] = l;
 +                      }
 +
 +                      looptris[i][0] = ltmp[0];
 +                      looptris[i][1] = ltmp[1];
 +                      looptris[i][2] = ltmp[2];
 +                      i += 1;
 +
 +                      looptris[i][0] = ltmp[0];
 +                      looptris[i][1] = ltmp[2];
 +                      looptris[i][2] = ltmp[3];
 +                      i += 1;
 +              }
 +
 +#endif /* USE_TESSFACE_SPEEDUP */
 +
 +              else {
 +                      EditVert *v, *lastv=NULL, *firstv=NULL;
 +                      EditEdge *e;
 +                      EditFace *efa;
 +
 +                      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= efa->v1->tmp.p;
 +                              BMLoop *l2= efa->v2->tmp.p;
 +                              BMLoop *l3= efa->v3->tmp.p;
 +
 +                              BLI_array_growone(looptris);
 +
 +                              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][0] = l1;
 +                              looptris[i][1] = l2;
 +                              looptris[i][2] = l3;
 +                              i += 1;
 +                      }
 +
 +                      BLI_end_edgefill();
 +              }
 +      }
 +
 +      tm->tottri = i;
 +      tm->looptris = looptris;
 +
 +#undef USE_TESSFACE_SPEEDUP
 +
 +}
 +
 +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_calcNormals(DerivedMesh *UNUSED(dm))
 +{
 +      /* Nothing to do: normals are already calculated and stored on the
 +         BMVerts and BMFaces */
 +}
 +
 +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) {
 +
 +              BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT);
 +
 +              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) {
 +
 +              BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT);
 +
 +              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) {
 +
 +              BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT);
 +
 +              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;
 +
 +      zero_v3(cent);
 +
 +      /*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)) {
 +                      add_v3_v3(cent, vertexCos[BM_GetIndex(l->v)]);
 +                      tot++;
 +              }
 +      } else {
 +              l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, efa);
 +              for (; l; l=BMIter_Step(&iter)) {
 +                      add_v3_v3(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;
 +      BMFace *efa;
 +      BMIter iter;
 +      float cent[3];
 +      int i;
 +
 +      if (bmdm->vertexCos) {
 +              BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT);
 +      }
 +
 +      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), 
-       int (*compareDrawOptions)(void *userData, int cur_index, int next_index))
 +      int (*setMaterial)(int, void *attribs),
-                void *userData) 
++      int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
++      void *userData, int UNUSED(useColors))
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMFace *efa;
 +      int i, draw;
 +
 +      const int skip_normals= !glIsEnabled(GL_LIGHTING); /* could be passed as an arg */
 +
 +      /* GL_ZERO is used to detect if drawing has started or not */
 +      GLenum poly_prev= GL_ZERO;
 +      GLenum shade_prev= GL_ZERO;
 +
 +      (void)setMaterial; /* UNUSED */
 +
 +      /* currently unused -- each original face is handled separately */
 +      (void)compareDrawOptions;
 +
 +      if (bmdm->vertexCos) {
 +              /* add direct access */
 +              float (*vertexCos)[3]= bmdm->vertexCos;
 +              float (*vertexNos)[3]= bmdm->vertexNos;
 +              float (*faceNos)[3]=   bmdm->faceNos;
 +              
 +              BM_ElemIndex_Ensure(bmdm->tc->bm, BM_VERT | BM_FACE);
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      int drawSmooth;
 +                      
 +                      efa = l[0]->f;
 +                      drawSmooth= BM_TestHFlag(efa, BM_SMOOTH);
 +
 +                      draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BM_GetIndex(efa), &drawSmooth);
 +                      if(draw) {
 +                              const GLenum poly_type= GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
 +                              if (draw==2) { /* enabled with stipple */
 +
 +                                      if(poly_prev != GL_ZERO) glEnd();
 +                                      poly_prev= GL_ZERO; /* force glBegin */
 +
 +                                      glEnable(GL_POLYGON_STIPPLE);
 +                                      glPolygonStipple(stipple_quarttone);
 +                              }
 +                              
 +                              if(skip_normals) {
 +                                      if(poly_type != poly_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +                                      glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
 +                                      glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
 +                                      glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
 +                              }
 +                              else {
 +                                      const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
 +                                      if (shade_type != shade_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +                                      if(poly_type != poly_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +
 +                                      if (!drawSmooth) {
 +                                              glNormal3fv(faceNos[i]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
 +                                      } else {
 +                                              glNormal3fv(vertexNos[(int) BM_GetIndex(l[0]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[0]->v)]);
 +                                              glNormal3fv(vertexNos[(int) BM_GetIndex(l[1]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[1]->v)]);
 +                                              glNormal3fv(vertexNos[(int) BM_GetIndex(l[2]->v)]);
 +                                              glVertex3fv(vertexCos[(int) BM_GetIndex(l[2]->v)]);
 +                                      }
 +                              }
 +
 +                              if (draw==2) {
 +                                      glEnd();
 +                                      poly_prev= GL_ZERO; /* force glBegin */
 +
 +                                      glDisable(GL_POLYGON_STIPPLE);
 +                              }
 +                      }
 +              }
 +      } else {
 +              BM_ElemIndex_Ensure(bmdm->tc->bm, BM_FACE);
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      int drawSmooth;
 +
 +                      efa = l[0]->f;
 +                      drawSmooth= BM_TestHFlag(efa, BM_SMOOTH);
 +                      
 +                      draw = setDrawOptions==NULL ? 1 : setDrawOptions(userData, BM_GetIndex(efa), &drawSmooth);
 +                      if(draw) {
 +                              const GLenum poly_type= GL_TRIANGLES; /* BMESH NOTE, this is odd but keep it for now to match trunk */
 +                              if (draw==2) { /* enabled with stipple */
 +
 +                                      if(poly_prev != GL_ZERO) glEnd();
 +                                      poly_prev= GL_ZERO; /* force glBegin */
 +
 +                                      glEnable(GL_POLYGON_STIPPLE);
 +                                      glPolygonStipple(stipple_quarttone);
 +                              }
 +                              
 +                              if(skip_normals) {
 +                                      if(poly_type != poly_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +                                      glVertex3fv(l[0]->v->co);
 +                                      glVertex3fv(l[1]->v->co);
 +                                      glVertex3fv(l[2]->v->co);
 +                              }
 +                              else {
 +                                      const GLenum shade_type= drawSmooth ? GL_SMOOTH : GL_FLAT;
 +                                      if (shade_type != shade_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glShadeModel((shade_prev= shade_type)); /* same as below but switch shading */
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +                                      if(poly_type != poly_prev) {
 +                                              if(poly_prev != GL_ZERO) glEnd();
 +                                              glBegin((poly_prev= poly_type)); /* BMesh: will always be GL_TRIANGLES */
 +                                      }
 +
 +                                      if (!drawSmooth) {
 +                                              glNormal3fv(efa->no);
 +                                              glVertex3fv(l[0]->v->co);
 +                                              glVertex3fv(l[1]->v->co);
 +                                              glVertex3fv(l[2]->v->co);
 +                                      } else {
 +                                              glNormal3fv(l[0]->v->no);
 +                                              glVertex3fv(l[0]->v->co);
 +                                              glNormal3fv(l[1]->v->no);
 +                                              glVertex3fv(l[1]->v->co);
 +                                              glNormal3fv(l[2]->v->no);
 +                                              glVertex3fv(l[2]->v->co);
 +                                      }
 +                              }
 +                              if (draw==2) {
 +                                      glEnd();
 +                                      poly_prev= GL_ZERO; /* force glBegin */
 +
 +                                      glDisable(GL_POLYGON_STIPPLE);
 +                              }
 +                      }
 +              }
 +      }
 +
 +      /* if non zero we know a face was rendered */
 +      if(poly_prev != GL_ZERO) glEnd();
 +}
 +
 +static void bmdm_get_tri_tex(BMesh *bm, BMLoop **ls, MLoopUV *luv[3], MLoopCol *lcol[3], 
 +                           int has_uv, int has_col)
 +{
 +      if (has_uv) { 
 +              luv[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPUV);
 +              luv[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPUV);
 +              luv[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPUV);
 +      }
 +
 +      if (has_col) {
 +              lcol[0] = CustomData_bmesh_get(&bm->ldata, ls[0]->head.data, CD_MLOOPCOL);
 +              lcol[1] = CustomData_bmesh_get(&bm->ldata, ls[1]->head.data, CD_MLOOPCOL);
 +              lcol[2] = CustomData_bmesh_get(&bm->ldata, ls[2]->head.data, CD_MLOOPCOL);
 +      }
 +
 +
 +}
 +
 +static void bmDM_drawFacesTex_common(DerivedMesh *dm,
 +               int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
 +               int (*drawParamsMapped)(void *userData, int index),
- static void bmDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
++               int (*compareDrawOptions)(void *userData, int cur_index, int next_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;
 +      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);
 +      
++      (void) compareDrawOptions;
++
 +      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);
 +
 +      BM_ElemIndex_Ensure(bm, BM_FACE);
 +
 +      if (vertexCos) {
 +              BM_ElemIndex_Ensure(bm, BM_VERT);
 +
 +              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 {
 +              BM_ElemIndex_Ensure(bm, BM_VERT);
 +
 +              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();
 +                      }
 +              }
 +      }
 +}
 +
-       bmDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
++static void bmDM_drawFacesTex(DerivedMesh *dm,
++                              int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr),
++                              int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
++                              void *userData)
 +{
- static void bmDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
++      bmDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
 +}
 +
-       bmDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
++static void bmDM_drawMappedFacesTex(DerivedMesh *dm,
++                                    int (*setDrawOptions)(void *userData, int index),
++                                    int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
++                                    void *userData)
 +{
-                int (*setMaterial)(int, void *attribs),
-                int (*setDrawOptions)(void *userData, int index), void *userData)
++      bmDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
 +}
 +
 +static void bmDM_drawMappedFacesGLSL(DerivedMesh *dm,
++                                     int (*setMaterial)(int, void *attribs),
++                                     int (*setDrawOptions)(void *userData, int index),
++                                     void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      BMEditMesh *em = bmdm->tc;
 +      float (*vertexCos)[3]= bmdm->vertexCos;
 +      float (*vertexNos)[3]= bmdm->vertexNos;
 +      BMFace *efa;
 +      BMLoop **ltri;
 +      DMVertexAttribs attribs;
 +      GPUVertexAttribs gattribs;
 +
 +      int i, b, matnr, new_matnr, dodraw;
 +
 +      dodraw = 0;
 +      matnr = -1;
 +
 +      memset(&attribs, 0, sizeof(attribs));
 +
 +      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 +      glShadeModel(GL_SMOOTH);
 +      BM_ElemIndex_Ensure(bm, BM_VERT | BM_FACE);
 +
 +#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);                                               \
 +      }                                                                                                                                                       \
 +      }
 +      
 +      
 +      for (i=0, ltri=em->looptris[0]; i<em->tottri; i++, ltri += 3) {
 +              int drawSmooth;
 +
 +              efa = ltri[0]->f;
 +              drawSmooth= BM_TestHFlag(efa, BM_SMOOTH);
 +              
 +              if(setDrawOptions && !setDrawOptions(userData, BM_GetIndex(efa)))
 +                      continue;
 +
 +              new_matnr = efa->mat_nr + 1;
 +              if(new_matnr != matnr) {
 +                      dodraw = setMaterial(matnr = new_matnr, &gattribs);
 +                      if(dodraw)
 +                              DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
 +              }
 +
 +              if(dodraw) {
 +                      glBegin(GL_TRIANGLES);
 +                      if (!drawSmooth) {
 +                              if(vertexCos) glNormal3fv(bmdm->faceNos[i]);
 +                              else glNormal3fv(efa->no);
 +
 +                              PASSATTRIB(ltri[0], ltri[0]->v, 0);
 +                              if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[0]->v)]);
 +                              else glVertex3fv(ltri[0]->v->co);
 +
 +                              PASSATTRIB(ltri[1], ltri[1]->v, 1);
 +                              if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[1]->v)]);
 +                              else glVertex3fv(ltri[1]->v->co);
 +
 +                              PASSATTRIB(ltri[2], ltri[2]->v, 2);
 +                              if(vertexCos) glVertex3fv(vertexCos[BM_GetIndex(ltri[2]->v)]);
 +                              else glVertex3fv(ltri[2]->v->co);
 +                      } else {
 +                              PASSATTRIB(ltri[0], ltri[0]->v, 0);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ltri[0]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ltri[0]->v)]);
 +                              }
 +                              else {
 +                                      glNormal3fv(ltri[0]->v->no);
 +                                      glVertex3fv(ltri[0]->v->co);
 +                              }
 +
 +                              PASSATTRIB(ltri[1], ltri[1]->v, 1);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ltri[1]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ltri[1]->v)]);
 +                              }
 +                              else {
 +                                      glNormal3fv(ltri[1]->v->no);
 +                                      glVertex3fv(ltri[1]->v->co);
 +                              }
 +
 +                              PASSATTRIB(ltri[2], ltri[2]->v, 2);
 +                              if(vertexCos) {
 +                                      glNormal3fv(vertexNos[BM_GetIndex(ltri[2]->v)]);
 +                                      glVertex3fv(vertexCos[BM_GetIndex(ltri[2]->v)]);
 +                              }
 +                              else {
 +                                      glNormal3fv(ltri[2]->v->no);
 +                                      glVertex3fv(ltri[2]->v->co);
 +                              }
 +                      }
 +                      glEnd();
 +              }
 +      }
 +#undef PASSATTRIB
 +}
 +
 +static void bmDM_drawFacesGLSL(DerivedMesh *dm,
 +               int (*setMaterial)(int, void *attribs))
 +{
 +      dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
 +}
 +
 +
 +static void bmDM_drawMappedFacesMat(DerivedMesh *dm,
 +                         void (*setMaterial)(void *userData, int, void *attribs),
 +                         int (*setFace)(void *userData, int index), void *userData)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      BMEditMesh *em = bmdm->tc;
 +      float (*vertexCos)[3]= bmdm->vertexCos;
 +      float (*vertexNos)[3]= bmdm->vertexNos;
 +      BMFace *efa;
 +      BMLoop **ltri;
 +      DMVertexAttribs attribs= {{{0}}};
 +      GPUVertexAttribs gattribs;
 +      int i, b, matnr, new_matnr;
 +
 +      matnr = -1;
 +
 +      /* always use smooth shading even for flat faces, else vertex colors wont interpolate */
 +      glShadeModel(GL_SMOOTH);
 +
 +      BM_ElemIndex_Ensure(bm, BM_VERT);
 +
 +#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];                                                   \
 +              glVertexAttrib4fvARB(attribs.tang.glIndex, tang);                                               \
 +      }                                                                                                                                                       \
 +}
 +
 +      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);
 +
 +              /* face hiding */
 +              if(setFace && !setFace(userData, BM_GetIndex(efa)))
 +                      continue;
 +
 +              /* material */
 +              new_matnr = efa->mat_nr + 1;
 +              if(new_matnr != matnr) {
 +                      setMaterial(userData, matnr = new_matnr, &gattribs);
 +                      DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
 +              }
 +
 +              /* face */
 +              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();
 +      }
 +#undef PASSATTRIB
 +}
 +
 +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_getNumLoops(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      
 +      return bmdm->tc->bm->totloop;
 +}
 +
 +static int bmDM_getNumPolys(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      
 +      return bmdm->tc->bm->totface;
 +}
 +
 +static int bmvert_to_mvert(BMesh *bm, BMVert *ev, MVert *vert_r)
 +{
 +      copy_v3_v3(vert_r->co, ev->co);
 +
 +      normal_float_to_short_v3(vert_r->no, ev->no);
 +
 +      vert_r->flag = BM_Vert_Flag_To_MEFlag(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 = BM_Edge_Flag_To_MEFlag(e);
 +      
 +      edge_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v1));
 +      edge_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, e->v2));
 +}
 +
 +static void bmDM_getTessFace(DerivedMesh *dm, int index, MFace *face_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMFace *ef;
 +      BMLoop **l;
 +      
 +      if (index < 0 || index >= ((EditDerivedBMesh *)dm)->tf) {
 +              printf("error in bmDM_getTessFace.\n");
 +              return;
 +      }
 +
 +      l = ((EditDerivedBMesh *)dm)->tc->looptris[index];
 +
 +      ef = l[0]->f;
 +
 +      face_r->mat_nr = (unsigned char) ef->mat_nr;
 +      face_r->flag = BM_Face_Flag_To_MEFlag(ef);
 +
 +      face_r->v1 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[0]->v));
 +      face_r->v2 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[1]->v));
 +      face_r->v3 = GET_INT_FROM_POINTER(BLI_ghash_lookup(bmdm->vhash, l[2]->v));
 +      face_r->v4 = 0;
 +
 +      test_index_face(face_r, NULL, 0, 3);
 +}
 +
 +static void bmDM_copyVertArray(DerivedMesh *dm, MVert *vert_r)
 +{
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMVert *ev;
 +      BMIter iter;
 +
 +      ev = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +      for( ; ev; ev = BMIter_Step(&iter), ++vert_r) {
 +              copy_v3_v3(vert_r->co, ev->co);
 +
 +              normal_float_to_short_v3(vert_r->no, ev->no);
 +
 +              vert_r->flag = BM_Vert_Flag_To_MEFlag(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;
 +      int has_bweight = CustomData_has_layer(&bm->edata, CD_BWEIGHT);
 +      int has_crease = CustomData_has_layer(&bm->edata, CD_CREASE);
 +
 +      BM_ElemIndex_Ensure(bm, BM_VERT);
 +
 +      ee = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
 +      for( ; ee; ee=BMIter_Step(&iter), edge_r++) {
 +              if (has_bweight) {
 +                      edge_r->bweight = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_BWEIGHT)*255.0f);
 +              }
 +
 +              if (has_crease) {
 +                      edge_r->crease = (unsigned char) (BM_GetCDf(&bm->edata, ee, CD_CREASE)*255.0f);
 +              }
 +
 +              edge_r->flag = BM_Edge_Flag_To_MEFlag(ee);
 +
 +              edge_r->v1 = (int)BM_GetIndex(ee->v1);
 +              edge_r->v2 = (int)BM_GetIndex(ee->v2);
 +      }
 +}
 +
 +static void bmDM_copyTessFaceArray(DerivedMesh *dm, MFace *face_r)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm;
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMFace *ef;
 +      BMLoop **l;
 +      int i;
 +
 +      BM_ElemIndex_Ensure(bm, BM_VERT);
 +
 +      for (i=0; i<bmdm->tc->tottri; i++, face_r++) {
 +              l = bmdm->tc->looptris[i];
 +              ef = l[0]->f;
 +
 +              face_r->mat_nr = (unsigned char) ef->mat_nr;
 +
 +              face_r->flag = BM_Face_Flag_To_MEFlag(ef);
 +
 +              face_r->v1 = BM_GetIndex(l[0]->v);
 +              face_r->v2 = BM_GetIndex(l[1]->v);
 +              face_r->v3 = BM_GetIndex(l[2]->v);
 +              face_r->v4 = 0;
 +
 +              test_index_face(face_r, NULL, 0, 3);
 +      }
 +}
 +
 +
 +static void bmDM_copyLoopArray(DerivedMesh *dm, MLoop *loop_r)
 +{
 +      /* EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; */ /* UNUSED */
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMIter iter, liter;
 +      BMFace *f;
 +      BMLoop *l;
 +
 +      BM_ElemIndex_Ensure(bm, BM_VERT | BM_EDGE);
 +
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
 +                      loop_r->v = BM_GetIndex(l->v);
 +                      loop_r->e = BM_GetIndex(l->e);
 +                      loop_r++;
 +              }
 +      }
 +}
 +
 +static void bmDM_copyPolyArray(DerivedMesh *dm, MPoly *poly_r)
 +{
 +      /* EditDerivedBMesh *bmdm = (EditDerivedBMesh *)dm; */ /* UNUSED */
 +      BMesh *bm = ((EditDerivedBMesh *)dm)->tc->bm;
 +      BMIter iter;
 +      BMFace *f;
 +      int i;
 +
 +      i = 0;
 +      BM_ITER(f, &iter, bm, BM_FACES_OF_MESH, NULL) {
 +              poly_r->flag = BM_Face_Flag_To_MEFlag(f);
 +              poly_r->loopstart = i;
 +              poly_r->totloop = f->len;
 +              poly_r->mat_nr = f->mat_nr;
 +
 +              poly_r++;
 +              i += f->len;
 +      }
 +}
 +
 +static void *bmDM_getTessFaceDataArray(DerivedMesh *dm, int type)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh*) dm;
 +      BMesh *bm= bmdm->tc->bm;
 +      BMFace *efa;
 +      char *data, *bmdata;
 +      void *datalayer;
 +      int index /*, offset*/ /*UNUSED */, size, i;
 +
 +      datalayer = DM_get_tessface_data_layer(dm, type);
 +      if(datalayer)
 +              return datalayer;
 +
 +      /* layers are store per face for editmesh, we convert to a tbmporary
 +       * data layer array in the derivedmesh when these are requested */
 +      if(type == CD_MTFACE || type == CD_MCOL) {
 +              index = CustomData_get_layer_index(&bm->pdata, type);
 +
 +              if(index != -1) {
 +                      /* offset = bm->pdata.layers[index].offset; */ /* UNUSED */
 +                      size = CustomData_sizeof(type);
 +
 +                      DM_add_tessface_layer(dm, type, CD_CALLOC, NULL);
 +                      index = CustomData_get_layer_index(&dm->faceData, type);
 +                      dm->faceData.layers[index].flag |= CD_FLAG_TEMPORARY;
 +
 +                      data = datalayer = DM_get_tessface_data_layer(dm, type);
 +                      for (i=0; i<bmdm->tc->tottri; i++, data+=size) {
 +                              efa = bmdm->tc->looptris[i][0]->f;
 +                              /*BMESH_TODO: need to still add tface data,
 +                                derived from the loops.*/
 +                              bmdata = CustomData_bmesh_get(&bm->pdata, efa->head.data, type);
 +                              memcpy(data, bmdata, size);
 +                      }
 +              }
 +      }
 +
 +      return datalayer;
 +}
 +
 +static void bmDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
 +{
 +      EditDerivedBMesh *emdm= (EditDerivedBMesh*) dm;
 +      BMVert *eve;
 +      BMIter iter;
 +      int i;
 +
 +      i= 0;
 +      BM_ITER(eve, &iter, emdm->tc->bm, BM_VERTS_OF_MESH, NULL) {
 +              if (emdm->vertexCos) {
 +                      copy_v3_v3(cos_r[i], emdm->vertexCos[i]);
 +              } else {
 +                      copy_v3_v3(cos_r[i], eve->co);
 +              }
 +              
 +              i++;
 +      }
 +}
 +
 +static void bmDM_release(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm= (EditDerivedBMesh *)dm;
 +
 +      if (DM_release(dm)) {
 +              if (bmdm->vertexCos) {
 +                      MEM_freeN(bmdm->vertexCos);
 +                      MEM_freeN(bmdm->vertexNos);
 +                      MEM_freeN(bmdm->faceNos);
 +              }
 +              
 +              if (bmdm->fhash) BLI_ghash_free(bmdm->fhash, NULL, NULL);
 +              if (bmdm->ehash) BLI_ghash_free(bmdm->ehash, NULL, NULL);
 +              if (bmdm->vhash) BLI_ghash_free(bmdm->vhash, NULL, NULL);
 +
 +              if (bmdm->vtable) MEM_freeN(bmdm->vtable);
 +              if (bmdm->etable) MEM_freeN(bmdm->etable);
 +              if (bmdm->ftable) MEM_freeN(bmdm->ftable);
 +              
 +              MEM_freeN(bmdm);
 +      }
 +}
 +
 +static CustomData *bmDm_getVertDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->vdata;
 +}
 +
 +static CustomData *bmDm_getEdgeDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->edata;
 +}
 +
 +static CustomData *bmDm_getTessFaceDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->dm.faceData;
 +}
 +
 +static CustomData *bmDm_getLoopDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->ldata;
 +}
 +
 +static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm)
 +{
 +      EditDerivedBMesh *bmdm = (EditDerivedBMesh*)dm;
 +
 +      return &bmdm->tc->bm->pdata;
 +}
 +
 +
 +DerivedMesh *getEditDerivedBMesh(BMEditMesh *em, Object *UNUSED(ob),
 +                                           float (*vertexCos)[3])
 +{
 +      EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__);
 +      BMesh *bm = em->bm;
 +      
 +      bmdm->tc = em;
 +
 +      DM_init((DerivedMesh*)bmdm, DM_TYPE_EDITBMESH, em->bm->totvert, 
 +               em->bm->totedge, em->tottri, em->bm->totloop, em->bm->totface);
 +      
 +      CustomData_from_bmeshpoly(&bmdm->dm.faceData, &em->bm->pdata, &em->bm->ldata, 0);
 +      
 +      bmdm->dm.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.getPolyDataLayout = bmDm_getPolyDataLayout;
 +
 +      bmdm->dm.getNumVerts = bmDM_getNumVerts;
 +      bmdm->dm.getNumEdges = bmDM_getNumEdges;
 +      bmdm->dm.getNumTessFaces = bmDM_getNumTessFaces;
 +      bmdm->dm.getNumLoops = bmDM_getNumLoops;
 +      bmdm->dm.getNumPolys = bmDM_getNumPolys;
 +
 +      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_copyTessFaceArray;
 +      bmdm->dm.copyLoopArray = bmDM_copyLoopArray;
 +      bmdm->dm.copyPolyArray = bmDM_copyPolyArray;
 +
 +      bmdm->dm.getTessFaceDataArray = bmDM_getTessFaceDataArray;
 +
 +      bmdm->dm.calcNormals = bmDM_calcNormals;
 +      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.drawMappedFacesMat = bmDM_drawMappedFacesMat;
 +      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;
 +
 +              BM_ElemIndex_Ensure(bm, BM_VERT);
 +
 +              bmdm->vertexNos = MEM_callocN(sizeof(*bmdm->vertexNos) * bm->totvert, "bmdm_vno");
 +              bmdm->faceNos = MEM_mallocN(sizeof(*bmdm->faceNos)*totface, "bmdm_vno");
 +
 +              for (i=0; i<bmdm->tc->tottri; i++) {
 +                      BMLoop **l = bmdm->tc->looptris[i];
 +                      float *v1 = vertexCos[(int) BM_GetIndex(l[0]->v)];
 +                      float *v2 = vertexCos[(int) BM_GetIndex(l[1]->v)];
 +                      float *v3 = vertexCos[(int) BM_GetIndex(l[2]->v)];
 +                      float *no = bmdm->faceNos[i];
 +                      
 +                      normal_tri_v3( no,v1, v2, v3);
 +                      add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[0]->v)], bmdm->vertexNos[BM_GetIndex(l[0]->v)], no);
 +                      add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[1]->v)], bmdm->vertexNos[BM_GetIndex(l[1]->v)], no);
 +                      add_v3_v3v3(bmdm->vertexNos[BM_GetIndex(l[2]->v)], bmdm->vertexNos[BM_GetIndex(l[2]->v)], no);
 +              }
 +
 +              eve=BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
 +              for (i=0; eve; eve=BMIter_Step(&iter), i++) {
 +                      float *no = bmdm->vertexNos[i];
 +                      /* following Mesh convention; we use vertex coordinate itself
 +                       * for normal in this case */
 +                      if (normalize_v3(no)==0.0) {
 +                              copy_v3_v3(no, vertexCos[i]);
 +                              normalize_v3(no);
 +                      }
 +              }
 +      }
 +
 +      //bmdm_recalc_lookups(bmdm);
 +
 +      return (DerivedMesh*) bmdm;
 +}
  #include "BKE_curve.h"
  /* -- */
  #include "BKE_object.h"
 +#include "BKE_tessmesh.h"
 +#include "BLI_edgehash.h"
 +
 +#include "BLI_blenlib.h"
 +#include "BLI_editVert.h"
 +#include "BLI_math.h"
 +#include "BLI_cellalloc.h"
 +#include "BLI_array.h"
 +#include "BLI_edgehash.h"
 +
 +#include "bmesh.h"
 +
 +enum {
 +      MESHCMP_DVERT_WEIGHTMISMATCH = 1,
 +      MESHCMP_DVERT_GROUPMISMATCH,
 +      MESHCMP_DVERT_TOTGROUPMISMATCH,
 +      MESHCMP_LOOPCOLMISMATCH,
 +      MESHCMP_LOOPUVMISMATCH,
 +      MESHCMP_LOOPMISMATCH,
 +      MESHCMP_POLYVERTMISMATCH,
 +      MESHCMP_POLYMISMATCH,
 +      MESHCMP_EDGEUNKNOWN,
 +      MESHCMP_VERTCOMISMATCH,
 +      MESHCMP_CDLAYERS_MISMATCH,
 +};
 +
 +static const char *cmpcode_to_str(int code)
 +{
 +      switch (code) {
 +              case MESHCMP_DVERT_WEIGHTMISMATCH:
 +                      return "Vertex Weight Mismatch";
 +              case MESHCMP_DVERT_GROUPMISMATCH:
 +                                      return "Vertex Group Mismatch";
 +              case MESHCMP_DVERT_TOTGROUPMISMATCH:
 +                                      return "Vertex Doesn't Belong To Same Number Of Groups";
 +              case MESHCMP_LOOPCOLMISMATCH:
 +                                      return "Vertex Color Mismatch";
 +              case MESHCMP_LOOPUVMISMATCH:
 +                                      return "UV Mismatch";
 +              case MESHCMP_LOOPMISMATCH:
 +                                      return "Loop Mismatch";
 +              case MESHCMP_POLYVERTMISMATCH:
 +                                      return "Loop Vert Mismatch In Poly Test";
 +              case MESHCMP_POLYMISMATCH:
 +                                      return "Loop Vert Mismatch";
 +              case MESHCMP_EDGEUNKNOWN:
 +                                      return "Edge Mismatch";
 +              case MESHCMP_VERTCOMISMATCH:
 +                                      return "Vertex Coordinate Mismatch";
 +              case MESHCMP_CDLAYERS_MISMATCH:
 +                                      return "CustomData Layer Count Mismatch";
 +              default:
 +                              return "Mesh Comparison Code Unknown";
 +              }
 +}
 +
 +/*thresh is threshold for comparing vertices, uvs, vertex colors,
 +  weights, etc.*/
 +static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, float thresh)
 +{
 +      CustomDataLayer *l1, *l2;
 +      int i, i1=0, i2=0, tot, j;
 +      
 +      for (i=0; i<c1->totlayer; i++) {
 +              if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))                
 +                      i1++;
 +      }
 +      
 +      for (i=0; i<c2->totlayer; i++) {
 +              if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))                
 +                      i2++;
 +      }
 +      
 +      if (i1 != i2)
 +              return MESHCMP_CDLAYERS_MISMATCH;
 +      
 +      l1 = c1->layers; l2 = c2->layers;
 +      tot = i1;
 +      i1 = 0; i2 = 0; 
 +      for (i=0; i < tot; i++) {
 +              while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
 +                      i1++, l1++;
 +
 +              while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
 +                      i2++, l2++;
 +              
 +              if (l1->type == CD_MVERT) {
 +                      MVert *v1 = l1->data;
 +                      MVert *v2 = l2->data;
 +                      int vtot = m1->totvert;
 +                      
 +                      for (j=0; j<vtot; j++, v1++, v2++) {
 +                              if (len_v3v3(v1->co, v2->co) > thresh)
 +                                      return MESHCMP_VERTCOMISMATCH;
 +                              /*I don't care about normals, let's just do coodinates*/
 +                      }
 +              }
 +              
 +              /*we're order-agnostic for edges here*/
 +              if (l1->type == CD_MEDGE) {
 +                      MEdge *e1 = l1->data;
 +                      MEdge *e2 = l2->data;
 +                      EdgeHash *eh = BLI_edgehash_new();
 +                      int etot = m1->totedge;
 +              
 +                      for (j=0; j<etot; j++, e1++) {
 +                              BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
 +                      }
 +                      
 +                      for (j=0; j<etot; j++, e2++) {
 +                              if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2))
 +                                      return MESHCMP_EDGEUNKNOWN;
 +                      }
 +                      BLI_edgehash_free(eh, NULL);
 +              }
 +              
 +              if (l1->type == CD_MPOLY) {
 +                      MPoly *p1 = l1->data;
 +                      MPoly *p2 = l2->data;
 +                      int ptot = m1->totpoly;
 +              
 +                      for (j=0; j<ptot; j++, p1++, p2++) {
 +                              MLoop *lp1, *lp2;
 +                              int k;
 +                              
 +                              if (p1->totloop != p2->totloop)
 +                                      return MESHCMP_POLYMISMATCH;
 +                              
 +                              lp1 = m1->mloop + p1->loopstart;
 +                              lp2 = m2->mloop + p2->loopstart;
 +                              
 +                              for (k=0; k<p1->totloop; k++, lp1++, lp2++) {
 +                                      if (lp1->v != lp2->v)
 +                                              return MESHCMP_POLYVERTMISMATCH;
 +                              }
 +                      }
 +              }
 +              if (l1->type == CD_MLOOP) {
 +                      MLoop *lp1 = l1->data;
 +                      MLoop *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (lp1->v != lp2->v)
 +                                      return MESHCMP_LOOPMISMATCH;
 +                      }
 +              }
 +              if (l1->type == CD_MLOOPUV) {
 +                      MLoopUV *lp1 = l1->data;
 +                      MLoopUV *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (len_v2v2(lp1->uv, lp2->uv) > thresh)
 +                                      return MESHCMP_LOOPUVMISMATCH;
 +                      }
 +              }
 +              
 +              if (l1->type == CD_MLOOPCOL) {
 +                      MLoopCol *lp1 = l1->data;
 +                      MLoopCol *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (ABS(lp1->r - lp2->r) > thresh || 
 +                                  ABS(lp1->g - lp2->g) > thresh || 
 +                                  ABS(lp1->b - lp2->b) > thresh || 
 +                                  ABS(lp1->a - lp2->a) > thresh)
 +                              {
 +                                      return MESHCMP_LOOPCOLMISMATCH;
 +                              }
 +                      }
 +              }
  
 +              if (l1->type == CD_MDEFORMVERT) {
 +                      MDeformVert *dv1 = l1->data;
 +                      MDeformVert *dv2 = l2->data;
 +                      int dvtot = m1->totvert;
 +              
 +                      for (j=0; j<dvtot; j++, dv1++, dv2++) {
 +                              int k;
 +                              MDeformWeight *dw1 = dv1->dw, *dw2=dv2->dw;
 +                              
 +                              if (dv1->totweight != dv2->totweight)
 +                                      return MESHCMP_DVERT_TOTGROUPMISMATCH;
 +                              
 +                              for (k=0; k<dv1->totweight; k++, dw1++, dw2++) {
 +                                      if (dw1->def_nr != dw2->def_nr)
 +                                              return MESHCMP_DVERT_GROUPMISMATCH;
 +                                      if (ABS(dw1->weight - dw2->weight) > thresh)
 +                                              return MESHCMP_DVERT_WEIGHTMISMATCH;
 +                              }
 +                      }
 +              }
 +      }
 +      
 +      return 0;
 +}
  
 -EditMesh *BKE_mesh_get_editmesh(Mesh *me)
 +/*used for testing.  returns an error string the two meshes don't match*/
 +const char *mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
  {
 -      return me->edit_mesh;
 +      int c;
 +      
 +      if (!me1 || !me2)
 +              return "Requires two input meshes";
 +      
 +      if (me1->totvert != me2->totvert) 
 +              return "Number of verts don't match";
 +      
 +      if (me1->totedge != me2->totedge)
 +              return "Number of edges don't match";
 +      
 +      if (me1->totpoly != me2->totpoly)
 +              return "Number of faces don't match";
 +                              
 +      if (me1->totloop !=me2->totloop)
 +              return "Number of loops don't match";
 +      
 +      if ((c = customdata_compare(&me1->vdata, &me2->vdata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->edata, &me2->edata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +      
 +      return NULL;
  }
  
 -void BKE_mesh_end_editmesh(Mesh *UNUSED(me), EditMesh *UNUSED(em))
 +static void mesh_ensure_tesselation_customdata(Mesh *me)
  {
 +      int tottex, totcol;
 +
 +      tottex = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
 +      totcol = CustomData_number_of_layers(&me->fdata, CD_MCOL);
 +      
 +      if (tottex != CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY) ||
 +          totcol != CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL))
 +      {
 +              CustomData_free(&me->fdata, me->totface);
 +              
 +              me->mface = NULL;
 +              me->mtface = NULL;
 +              me->mcol = NULL;
 +              me->totface = 0;
 +
 +              memset(&me->fdata, 0, sizeof(&me->fdata));
 +
 +              CustomData_from_bmeshpoly(&me->fdata, &me->pdata, &me->ldata, me->totface);
 +              printf("Warning! Tesselation uvs or vcol data got out of sync, had to reset!\n");
 +      }
  }
  
-       int act;
 +/*this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
 +  mloopcol and mcol) have the same relative active/render/clone/mask indices.*/
 +static void mesh_update_linked_customdata(Mesh *me)
 +{
 +      if (me->edit_btmesh)
 +              BMEdit_UpdateLinkedCustomData(me->edit_btmesh);
 +
 +      mesh_ensure_tesselation_customdata(me);
 +
 +      CustomData_bmesh_update_active_layers(&me->fdata, &me->pdata, &me->ldata);
 +}
  
  void mesh_update_customdata_pointers(Mesh *me)
  {
@@@ -1613,12 -1368,16 +1613,16 @@@ static void ccgDM_drawFacesSolid(Derive
  }
  
        /* Only used by non-editmesh types */
- static void cgdm_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData) {
 -static void ccgDM_drawMappedFacesGLSL(DerivedMesh *dm,
++static void cgdm_drawMappedFacesGLSL(DerivedMesh *dm,
+                       int (*setMaterial)(int, void *attribs),
+                       int (*setDrawOptions)(void *userData, int index),
+                       void *userData)
+ {
 -      CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
 -      CCGSubSurf *ss = ccgdm->ss;
 +      CCGDerivedMesh *cgdm = (CCGDerivedMesh*) dm;
 +      CCGSubSurf *ss = cgdm->ss;
        GPUVertexAttribs gattribs;
        DMVertexAttribs attribs= {{{NULL}}};
 -      /* MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
 +      /* MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
        int gridSize = ccgSubSurf_getGridSize(ss);
        int gridFaces = gridSize - 1;
        int edgeSize = ccgSubSurf_getEdgeSize(ss);
@@@ -1967,26 -1726,29 +1971,29 @@@ static void cgdm_drawFacesColored(Deriv
        glEnd();
  }
  
 -static void ccgDM_drawFacesTex_common(DerivedMesh *dm,
 +static void cgdm_drawFacesTex_common(DerivedMesh *dm,
        int (*drawParams)(MTFace *tface, int has_mcol, int matnr),
        int (*drawParamsMapped)(void *userData, int index),
+       int (*compareDrawOptions)(void *userData, int cur_index, int next_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);
+       (void) compareDrawOptions;
 +      ccgdm_pbvh_update(cgdm);
  
        if(!mcol)
 -              mcol = dm->getFaceDataArray(dm, CD_MCOL);
 +              mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
  
        if(!mcol)
 -              mcol = dm->getFaceDataArray(dm, CD_TEXTURE_MCOL);
 +              mcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL);
  
        totface = ccgSubSurf_getNumFaces(ss);
        for(i = 0; i < totface; i++) {
        }
  }
  
- static void cgdm_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
 -static void ccgDM_drawFacesTex(DerivedMesh *dm,
 -                         int (*setDrawOptions)(MTFace *tface, int has_mcol, int matnr),
++static void cgdm_drawFacesTex(DerivedMesh *dm,
++                         int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr),
+                          int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
+                          void *userData)
  {
-       cgdm_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
 -      ccgDM_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
++      cgdm_drawFacesTex_common(dm, setDrawOptions, NULL, compareDrawOptions, userData);
  }
  
- static void cgdm_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
 -static void ccgDM_drawMappedFacesTex(DerivedMesh *dm,
 -    int (*setDrawOptions)(void *userData, int index),
 -    int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
 -    void *userData)
++static void cgdm_drawMappedFacesTex(DerivedMesh *dm,
++      int (*setDrawOptions)(void *userData, int index),
++      int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
++      void *userData)
  {
-       cgdm_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 -      ccgDM_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, userData);
++      cgdm_drawFacesTex_common(dm, NULL, setDrawOptions, compareDrawOptions, 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),
-                       int (*compareDrawOptions)(void *userData, int cur_index, int next_index)) {
+ static void ccgDM_drawMappedFaces(DerivedMesh *dm,
+                       int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r),
+                       int (*setMaterial)(int, void *attribs),
+                       int (*compareDrawOptions)(void *userData, int cur_index, int next_index),
+                       void *userData, int useColors)
+ {
 -      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 */
@@@ -531,30 -513,19 +531,30 @@@ static int draw_tface_mapped__set_draw(
  
  static int draw_em_tf_mapped__set_draw(void *userData, int index)
  {
-       struct {BMEditMesh *em; short has_mcol; short has_mtface;} *data = userData;
 -      struct {DerivedMesh *dm; EditMesh *em; short has_mcol; short has_mtface;} *data = userData;
 -      EditMesh *em = data->em;
 -      EditFace *efa= EM_get_face_for_index(index);
 -      MTFace *tface;
 -      int matnr;
++      struct {DerivedMesh *dm; BMEditMesh *em; short has_mcol; short has_mtface;} *data = userData;
 +      BMEditMesh *em = data->em;
 +      BMFace *efa= EDBM_get_face_for_index(em, index);
  
 -      if (efa->h)
 +      if (efa==NULL || BM_TestHFlag(efa, BM_HIDDEN)) {
                return 0;
 +      }
 +      else {
 +              MTFace mtf= {{{0}}};
 +              int matnr = efa->mat_nr;
 +
 +              if (data->has_mtface) {
 +                      MTexPoly *tpoly = CustomData_bmesh_get(&em->bm->pdata, efa->head.data, CD_MTEXPOLY);
 +                      mtf.flag = tpoly->flag;
 +                      mtf.tpage = tpoly->tpage;
 +                      mtf.transp = tpoly->transp;
 +                      mtf.mode = tpoly->mode;
 +                      mtf.tile = tpoly->tile;
 +                      mtf.unwrap = tpoly->unwrap;
  
 -      tface = data->has_mtface ? CustomData_em_get(&em->fdata, efa->data, CD_MTFACE) : NULL;
 -      matnr = efa->mat_nr;
 +              }
  
 -      return draw_tface__set_draw_legacy(tface, data->has_mcol, matnr);
 +              return draw_tface__set_draw_legacy(&mtf, data->has_mcol, matnr);
 +      }
  }
  
  static int wpaint__setSolidDrawOptions(void *userData, int index, int *drawSmooth_r)
@@@ -658,6 -629,36 +658,36 @@@ static void draw_mesh_text(Scene *scene
        ddm->release(ddm);
  }
  
 -      MFace *mf = DM_get_face_data_layer(dm, CD_MFACE);
 -      MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+ static int compareDrawOptions(void *userData, int cur_index, int next_index)
+ {
+       DerivedMesh *dm= (DerivedMesh*) userData;
 -      MFace *mf = DM_get_face_data_layer(data->dm, CD_MFACE);
 -      MTFace *tf = DM_get_face_data_layer(data->dm, CD_MTFACE);
++      MFace *mf = DM_get_tessface_data_layer(dm, CD_MFACE);
++      MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+       if(mf && mf[cur_index].mat_nr != mf[next_index].mat_nr)
+               return 0;
+       if(tf && tf[cur_index].tpage != tf[next_index].tpage)
+               return 0;
+       return 1;
+ }
+ static int compareDrawOptionsEm(void *userData, int cur_index, int next_index)
+ {
+       struct {DerivedMesh *dm; EditMesh *em; short has_mcol; short has_mtface;} *data= userData;
++      MFace *mf = DM_get_tessface_data_layer(data->dm, CD_MFACE);
++      MTFace *tf = DM_get_tessface_data_layer(data->dm, CD_MTFACE);
+       if(mf && mf[cur_index].mat_nr != mf[next_index].mat_nr)
+               return 0;
+       if(tf && tf[cur_index].tpage != tf[next_index].tpage)
+               return 0;
+       return 1;
+ }
  void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d, Object *ob, DerivedMesh *dm, int draw_flags)
  {
        Mesh *me= ob->data;
        glColor4f(1.0f,1.0f,1.0f,1.0f);
  
        if(ob->mode & OB_MODE_EDIT) {
-               struct {BMEditMesh *em; short has_mcol; short has_mtface;} data;
 -              struct {DerivedMesh *dm; EditMesh *em; short has_mcol; short has_mtface;} data;
++              struct {DerivedMesh *dm; BMEditMesh *em; short has_mcol; short has_mtface;} data;
  
 -              data.em= me->edit_mesh;
 -              data.has_mcol= CustomData_has_layer(&me->edit_mesh->fdata, CD_MCOL);
 -              data.has_mtface= CustomData_has_layer(&me->edit_mesh->fdata, CD_MTFACE);
+               data.dm = dm;
 +              data.em= me->edit_btmesh;
 +              data.has_mcol= CustomData_has_layer(&me->edit_btmesh->bm->ldata, CD_MLOOPCOL);
 +              data.has_mtface= CustomData_has_layer(&me->edit_btmesh->bm->pdata, CD_MTEXPOLY);
  
-               dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, &data);
+               dm->drawMappedFacesTex(dm, draw_em_tf_mapped__set_draw, compareDrawOptionsEm, &data);
        }
        else if(draw_flags & DRAW_FACE_SELECT) {
                if(ob->mode & OB_MODE_WEIGHT_PAINT)
-                       dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, me, 1, GPU_enable_material, NULL);
+                       dm->drawMappedFaces(dm, wpaint__setSolidDrawOptions, GPU_enable_material, NULL, me, 1);
                else
-                       dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, me);
 -                      dm->drawMappedFacesTex(dm, me->mface ? draw_tface_mapped__set_draw : NULL, NULL, me);
++                      dm->drawMappedFacesTex(dm, me->mpoly ? draw_tface_mapped__set_draw : NULL, NULL, me);
        }
        else {
                if(GPU_buffer_legacy(dm)) {
@@@ -2353,14 -2323,11 +2353,14 @@@ static void draw_dm_edges_sharp(BMEditM
         * 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]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} *data = userData;
 -      struct { DerivedMesh *dm; unsigned char *cols[3]; EditFace *efa_act; } * data = userData;
 -      EditFace *efa = EM_get_face_for_index(index);
++      struct { DerivedMesh *dm; 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 */
  
  static int draw_dm_faces_sel__compareDrawOptions(void *userData, int index, int next_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);
-       BMFace *next_efa = EDBM_get_face_for_index(data->em, next_index);
 -      struct { DerivedMesh *dm; unsigned char *cols[3]; EditFace *efa_act; } *data = userData;
 -      int *orig_index= DM_get_face_data_layer(data->dm, CD_ORIGINDEX);
 -      EditFace *efa;
 -      EditFace *next_efa;
++      struct { DerivedMesh *dm; unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} * data = userData;
++      int *orig_index= DM_get_tessface_data_layer(data->dm, CD_ORIGINDEX);
++      BMFace *efa;
++      BMFace *next_efa;
++
        unsigned char *col, *next_col;
  
 -      efa= EM_get_face_for_index(orig_index[index]);
 -      next_efa= EM_get_face_for_index(orig_index[next_index]);
+       if(!orig_index)
+               return 0;
++      efa= EDBM_get_face_for_index(data->em, orig_index[index]);
++      next_efa= EDBM_get_face_for_index(data->em, orig_index[next_index]);
        if(efa == next_efa)
                return 1;
  
  }
  
  /* 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]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} data;
 -      struct { DerivedMesh *dm; unsigned char *cols[3]; EditFace *efa_act; } data;
++      struct { DerivedMesh *dm; unsigned char *cols[3]; BMEditMesh *em; BMFace *efa_act; Mesh *me;} data;
+       data.dm= dm;
        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, draw_dm_faces_sel__compareDrawOptions);
+       dm->drawMappedFaces(dm, draw_dm_faces_sel__setDrawOptions, GPU_enable_material, draw_dm_faces_sel__compareDrawOptions, &data, 0);
  }
  
 -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;
@@@ -2860,11 -2786,12 +2868,11 @@@ static void draw_em_fancy(Scene *scene
                else {
                        /* 3 floats for position, 3 for normal and times two because the faces may actually be quads instead of triangles */
                        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, me->flag & ME_TWOSIDED);
 -                      
 +
                        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, NULL);
 -                      
 -                      finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, NULL, 0);
 -                      
++                      finalDM->drawMappedFaces(finalDM, draw_em_fancy__setFaceOpts, GPU_enable_material, NULL, me->edit_btmesh, 0);
 +
                        glFrontFace(GL_CCW);
                        glDisable(GL_LIGHTING);
                }
@@@ -6949,8 -6867,7 +6957,8 @@@ static void bbs_mesh_solid_EM(BMEditMes
        cpack(0);
  
        if (facecol) {
 -              dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, (void*)(intptr_t) 1, 0);
 +              ptrs[1] = (void*)(intptr_t) 1;
-               dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0, GPU_enable_material, NULL);
++              dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, ptrs, 0);
  
                if(check_ob_drawface_dot(scene, v3d, ob->dt)) {
                        glPointSize(UI_GetThemeValuef(TH_FACEDOT_SIZE));
                }
  
        } else {
-               dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, ptrs, 0, GPU_enable_material, NULL);
 -              dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, (void*) 0, 0);
++              dm->drawMappedFaces(dm, bbs_mesh_solid__setSolidDrawOptions, GPU_enable_material, NULL, ptrs, 0);
        }
  }
  
Simple merge