svn merge ^/trunk/blender -r43160:43183
authorCampbell Barton <ideasman42@gmail.com>
Thu, 5 Jan 2012 22:30:08 +0000 (22:30 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 5 Jan 2012 22:30:08 +0000 (22:30 +0000)
1  2 
source/blender/blenkernel/intern/mesh.c

index 4f5a42a50ce58e241f21cda3d13b314ba53fe6a1,ef2249409f0deb2825e9716267ad0f03438f5fd6..f07bd7903e9160fca79fb03cafb03e0f4b790be1
  #include "DNA_key_types.h"
  #include "DNA_meshdata_types.h"
  #include "DNA_ipo_types.h"
 +#include "DNA_customdata_types.h"
  
 +#include "BLI_utildefines.h"
  #include "BLI_blenlib.h"
  #include "BLI_bpath.h"
  #include "BLI_editVert.h"
  #include "BLI_math.h"
  #include "BLI_edgehash.h"
 -#include "BLI_utildefines.h"
 +#include "BLI_scanfill.h"
  
  #include "BKE_animsys.h"
  #include "BKE_main.h"
 +#include "BKE_customdata.h"
  #include "BKE_DerivedMesh.h"
  #include "BKE_global.h"
  #include "BKE_mesh.h"
  #include "BKE_curve.h"
  /* -- */
  #include "BKE_object.h"
 +#include "BKE_tessmesh.h"
 +#include "BLI_edgehash.h"
  
 -#ifdef USE_BMESH_FORWARD_COMPAT
 +#include "BLI_blenlib.h"
 +#include "BLI_editVert.h"
 +#include "BLI_math.h"
 +#include "BLI_cellalloc.h"
  #include "BLI_array.h"
 -#endif
 +#include "BLI_edgehash.h"
  
 +#include "bmesh.h"
 +
 +enum {
 +      MESHCMP_DVERT_WEIGHTMISMATCH = 1,
 +      MESHCMP_DVERT_GROUPMISMATCH,
 +      MESHCMP_DVERT_TOTGROUPMISMATCH,
 +      MESHCMP_LOOPCOLMISMATCH,
 +      MESHCMP_LOOPUVMISMATCH,
 +      MESHCMP_LOOPMISMATCH,
 +      MESHCMP_POLYVERTMISMATCH,
 +      MESHCMP_POLYMISMATCH,
 +      MESHCMP_EDGEUNKNOWN,
 +      MESHCMP_VERTCOMISMATCH,
 +      MESHCMP_CDLAYERS_MISMATCH,
 +};
  
 -EditMesh *BKE_mesh_get_editmesh(Mesh *me)
 +static const char *cmpcode_to_str(int code)
  {
 -      return me->edit_mesh;
 +      switch (code) {
 +              case MESHCMP_DVERT_WEIGHTMISMATCH:
 +                      return "Vertex Weight Mismatch";
 +              case MESHCMP_DVERT_GROUPMISMATCH:
 +                                      return "Vertex Group Mismatch";
 +              case MESHCMP_DVERT_TOTGROUPMISMATCH:
 +                                      return "Vertex Doesn't Belong To Same Number Of Groups";
 +              case MESHCMP_LOOPCOLMISMATCH:
 +                                      return "Vertex Color Mismatch";
 +              case MESHCMP_LOOPUVMISMATCH:
 +                                      return "UV Mismatch";
 +              case MESHCMP_LOOPMISMATCH:
 +                                      return "Loop Mismatch";
 +              case MESHCMP_POLYVERTMISMATCH:
 +                                      return "Loop Vert Mismatch In Poly Test";
 +              case MESHCMP_POLYMISMATCH:
 +                                      return "Loop Vert Mismatch";
 +              case MESHCMP_EDGEUNKNOWN:
 +                                      return "Edge Mismatch";
 +              case MESHCMP_VERTCOMISMATCH:
 +                                      return "Vertex Coordinate Mismatch";
 +              case MESHCMP_CDLAYERS_MISMATCH:
 +                                      return "CustomData Layer Count Mismatch";
 +              default:
 +                              return "Mesh Comparison Code Unknown";
 +              }
  }
  
 -void BKE_mesh_end_editmesh(Mesh *UNUSED(me), EditMesh *UNUSED(em))
 +/*thresh is threshold for comparing vertices, uvs, vertex colors,
 +  weights, etc.*/
 +static int customdata_compare(CustomData *c1, CustomData *c2, Mesh *m1, Mesh *m2, float thresh)
  {
 +      CustomDataLayer *l1, *l2;
 +      int i, i1=0, i2=0, tot, j;
 +      
 +      for (i=0; i<c1->totlayer; i++) {
 +              if (ELEM7(c1->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))                
 +                      i1++;
 +      }
 +      
 +      for (i=0; i<c2->totlayer; i++) {
 +              if (ELEM7(c2->layers[i].type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))                
 +                      i2++;
 +      }
 +      
 +      if (i1 != i2)
 +              return MESHCMP_CDLAYERS_MISMATCH;
 +      
 +      l1 = c1->layers; l2 = c2->layers;
 +      tot = i1;
 +      i1 = 0; i2 = 0; 
 +      for (i=0; i < tot; i++) {
 +              while (i1 < c1->totlayer && !ELEM7(l1->type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
 +                      i1++, l1++;
 +
 +              while (i2 < c2->totlayer && !ELEM7(l2->type, CD_MVERT, CD_MEDGE, CD_MPOLY, 
 +                                CD_MLOOPUV, CD_MLOOPCOL, CD_MTEXPOLY, CD_MDEFORMVERT))
 +                      i2++, l2++;
 +              
 +              if (l1->type == CD_MVERT) {
 +                      MVert *v1 = l1->data;
 +                      MVert *v2 = l2->data;
 +                      int vtot = m1->totvert;
 +                      
 +                      for (j=0; j<vtot; j++, v1++, v2++) {
 +                              if (len_v3v3(v1->co, v2->co) > thresh)
 +                                      return MESHCMP_VERTCOMISMATCH;
 +                              /*I don't care about normals, let's just do coodinates*/
 +                      }
 +              }
 +              
 +              /*we're order-agnostic for edges here*/
 +              if (l1->type == CD_MEDGE) {
 +                      MEdge *e1 = l1->data;
 +                      MEdge *e2 = l2->data;
 +                      EdgeHash *eh = BLI_edgehash_new();
 +                      int etot = m1->totedge;
 +              
 +                      for (j=0; j<etot; j++, e1++) {
 +                              BLI_edgehash_insert(eh, e1->v1, e1->v2, e1);
 +                      }
 +                      
 +                      for (j=0; j<etot; j++, e2++) {
 +                              if (!BLI_edgehash_lookup(eh, e2->v1, e2->v2))
 +                                      return MESHCMP_EDGEUNKNOWN;
 +                      }
 +                      BLI_edgehash_free(eh, NULL);
 +              }
 +              
 +              if (l1->type == CD_MPOLY) {
 +                      MPoly *p1 = l1->data;
 +                      MPoly *p2 = l2->data;
 +                      int ptot = m1->totpoly;
 +              
 +                      for (j=0; j<ptot; j++, p1++, p2++) {
 +                              MLoop *lp1, *lp2;
 +                              int k;
 +                              
 +                              if (p1->totloop != p2->totloop)
 +                                      return MESHCMP_POLYMISMATCH;
 +                              
 +                              lp1 = m1->mloop + p1->loopstart;
 +                              lp2 = m2->mloop + p2->loopstart;
 +                              
 +                              for (k=0; k<p1->totloop; k++, lp1++, lp2++) {
 +                                      if (lp1->v != lp2->v)
 +                                              return MESHCMP_POLYVERTMISMATCH;
 +                              }
 +                      }
 +              }
 +              if (l1->type == CD_MLOOP) {
 +                      MLoop *lp1 = l1->data;
 +                      MLoop *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (lp1->v != lp2->v)
 +                                      return MESHCMP_LOOPMISMATCH;
 +                      }
 +              }
 +              if (l1->type == CD_MLOOPUV) {
 +                      MLoopUV *lp1 = l1->data;
 +                      MLoopUV *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (len_v2v2(lp1->uv, lp2->uv) > thresh)
 +                                      return MESHCMP_LOOPUVMISMATCH;
 +                      }
 +              }
 +              
 +              if (l1->type == CD_MLOOPCOL) {
 +                      MLoopCol *lp1 = l1->data;
 +                      MLoopCol *lp2 = l2->data;
 +                      int ltot = m1->totloop;
 +              
 +                      for (j=0; j<ltot; j++, lp1++, lp2++) {
 +                              if (ABS(lp1->r - lp2->r) > thresh || 
 +                                  ABS(lp1->g - lp2->g) > thresh || 
 +                                  ABS(lp1->b - lp2->b) > thresh || 
 +                                  ABS(lp1->a - lp2->a) > thresh)
 +                              {
 +                                      return MESHCMP_LOOPCOLMISMATCH;
 +                              }
 +                      }
 +              }
 +
 +              if (l1->type == CD_MDEFORMVERT) {
 +                      MDeformVert *dv1 = l1->data;
 +                      MDeformVert *dv2 = l2->data;
 +                      int dvtot = m1->totvert;
 +              
 +                      for (j=0; j<dvtot; j++, dv1++, dv2++) {
 +                              int k;
 +                              MDeformWeight *dw1 = dv1->dw, *dw2=dv2->dw;
 +                              
 +                              if (dv1->totweight != dv2->totweight)
 +                                      return MESHCMP_DVERT_TOTGROUPMISMATCH;
 +                              
 +                              for (k=0; k<dv1->totweight; k++, dw1++, dw2++) {
 +                                      if (dw1->def_nr != dw2->def_nr)
 +                                              return MESHCMP_DVERT_GROUPMISMATCH;
 +                                      if (ABS(dw1->weight - dw2->weight) > thresh)
 +                                              return MESHCMP_DVERT_WEIGHTMISMATCH;
 +                              }
 +                      }
 +              }
 +      }
 +      
 +      return 0;
  }
  
 +/*used for testing.  returns an error string the two meshes don't match*/
 +const char *mesh_cmp(Mesh *me1, Mesh *me2, float thresh)
 +{
 +      int c;
 +      
 +      if (!me1 || !me2)
 +              return "Requires two input meshes";
 +      
 +      if (me1->totvert != me2->totvert) 
 +              return "Number of verts don't match";
 +      
 +      if (me1->totedge != me2->totedge)
 +              return "Number of edges don't match";
 +      
 +      if (me1->totpoly != me2->totpoly)
 +              return "Number of faces don't match";
 +                              
 +      if (me1->totloop !=me2->totloop)
 +              return "Number of loops don't match";
 +      
 +      if ((c = customdata_compare(&me1->vdata, &me2->vdata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->edata, &me2->edata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->ldata, &me2->ldata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +
 +      if ((c = customdata_compare(&me1->pdata, &me2->pdata, me1, me2, thresh)))
 +              return cmpcode_to_str(c);
 +      
 +      return NULL;
 +}
 +
 +static void mesh_ensure_tesselation_customdata(Mesh *me)
 +{
 +      const int tottex_original = CustomData_number_of_layers(&me->pdata, CD_MTEXPOLY);
 +      const int totcol_original = CustomData_number_of_layers(&me->ldata, CD_MLOOPCOL);
 +
 +      const int tottex_tessface = CustomData_number_of_layers(&me->fdata, CD_MTFACE);
 +      const int totcol_tessface = CustomData_number_of_layers(&me->fdata, CD_MCOL);
 +
 +      if (tottex_tessface != tottex_original ||
 +          totcol_tessface != totcol_original )
 +      {
 +              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);
  
 -void mesh_update_customdata_pointers(Mesh *me)
 +              /* note: this warning may be un-called for if we are inirializing the mesh for the
 +               * first time from bmesh, rather then giving a warning about this we could be smarter
 +               * and check if there was any data to begin with, for now just print the warning with
 +               * some info to help troubleshoot whats going on - campbell */
 +              printf("%s: warning! Tesselation uvs or vcol data got out of sync, "
 +                     "had to reset!\n    CD_MTFACE: %d != CD_MTEXPOLY: %d || CD_MCOL: %d != CD_MLOOPCOL: %d\n",
 +                     __func__, tottex_tessface, tottex_original, totcol_tessface, totcol_original);
 +      }
 +}
 +
 +/* this ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or
 + * mloopcol and mcol) have the same relative active/render/clone/mask indices.
 + *
 + * note that for undo mesh data we want to skip 'ensure_tess_cd' call since
 + * we dont want to store memory for tessface when its only used for older
 + * versions of the mesh. - campbell*/
 +static void mesh_update_linked_customdata(Mesh *me, const short do_ensure_tess_cd)
  {
 +      if (me->edit_btmesh)
 +              BMEdit_UpdateLinkedCustomData(me->edit_btmesh);
 +
 +      if (do_ensure_tess_cd) {
 +              mesh_ensure_tesselation_customdata(me);
 +      }
 +
 +      CustomData_bmesh_update_active_layers(&me->fdata, &me->pdata, &me->ldata);
 +}
 +
 +void mesh_update_customdata_pointers(Mesh *me, const short do_ensure_tess_cd)
 +{
 +      mesh_update_linked_customdata(me, do_ensure_tess_cd);
 +
        me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT);
        me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT);
        me->msticky = CustomData_get_layer(&me->vdata, CD_MSTICKY);
        me->mface = CustomData_get_layer(&me->fdata, CD_MFACE);
        me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL);
        me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE);
 +      
 +      me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY);
 +      me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP);
 +
 +      me->mtpoly = CustomData_get_layer(&me->pdata, CD_MTEXPOLY);
 +      me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL);
 +      me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV);
  }
  
  /* Note: unlinking is called when me->id.us is 0, question remains how
@@@ -402,17 -118,14 +402,17 @@@ void unlink_mesh(Mesh *me
  }
  
  /* do not free mesh itself */
 -void free_mesh(Mesh *me)
 +void free_mesh(Mesh *me, int unlink)
  {
 -      unlink_mesh(me);
 +      if (unlink)
 +              unlink_mesh(me);
  
        CustomData_free(&me->vdata, me->totvert);
        CustomData_free(&me->edata, me->totedge);
        CustomData_free(&me->fdata, me->totface);
 -      
 +      CustomData_free(&me->ldata, me->totloop);
 +      CustomData_free(&me->pdata, me->totpoly);
 +
        if(me->adt) {
                BKE_free_animdata(&me->id);
                me->adt= NULL;
        
        if(me->bb) MEM_freeN(me->bb);
        if(me->mselect) MEM_freeN(me->mselect);
 -      if(me->edit_mesh) MEM_freeN(me->edit_mesh);
 +      if(me->edit_btmesh) MEM_freeN(me->edit_btmesh);
  }
  
  void copy_dverts(MDeformVert *dst, MDeformVert *src, int copycount)
        
        for (i=0; i<copycount; i++){
                if (src[i].dw){
 -                      dst[i].dw = MEM_callocN (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight");
 +                      dst[i].dw = BLI_cellalloc_calloc (sizeof(MDeformWeight)*src[i].totweight, "copy_deformWeight");
                        memcpy (dst[i].dw, src[i].dw, sizeof (MDeformWeight)*src[i].totweight);
                }
        }
@@@ -456,7 -169,7 +456,7 @@@ void free_dverts(MDeformVert *dvert, in
  
        /* Free any special data from the verts */
        for (i=0; i<totvert; i++){
 -              if (dvert[i].dw) MEM_freeN (dvert[i].dw);
 +              if (dvert[i].dw) BLI_cellalloc_free (dvert[i].dw);
        }
        MEM_freeN (dvert);
  }
@@@ -481,7 -194,6 +481,7 @@@ Mesh *copy_mesh(Mesh *me
  {
        Mesh *men;
        MTFace *tface;
 +      MTexPoly *txface;
        int a, i;
        
        men= copy_libblock(&me->id);
        CustomData_copy(&me->vdata, &men->vdata, CD_MASK_MESH, CD_DUPLICATE, men->totvert);
        CustomData_copy(&me->edata, &men->edata, CD_MASK_MESH, CD_DUPLICATE, men->totedge);
        CustomData_copy(&me->fdata, &men->fdata, CD_MASK_MESH, CD_DUPLICATE, men->totface);
 -      mesh_update_customdata_pointers(men);
 +      CustomData_copy(&me->ldata, &men->ldata, CD_MASK_MESH, CD_DUPLICATE, men->totloop);
 +      CustomData_copy(&me->pdata, &men->pdata, CD_MASK_MESH, CD_DUPLICATE, men->totpoly);
 +      mesh_update_customdata_pointers(men, TRUE);
  
        /* ensure indirect linked data becomes lib-extern */
        for(i=0; i<me->fdata.totlayer; i++) {
                }
        }
        
 +      for(i=0; i<me->pdata.totlayer; i++) {
 +              if(me->pdata.layers[i].type == CD_MTEXPOLY) {
 +                      txface= (MTexPoly*)me->pdata.layers[i].data;
 +
 +                      for(a=0; a<me->totpoly; a++, txface++)
 +                              if(txface->tpage)
 +                                      id_lib_extern((ID*)txface->tpage);
 +              }
 +      }
 +
        men->mselect= NULL;
 -      men->edit_mesh= NULL;
 +      men->edit_btmesh= NULL;
  
        men->bb= MEM_dupallocN(men->bb);
        
        return men;
  }
  
 +BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob)
 +{
 +      BMesh *bm;
 +      int allocsize[4] = {512,512,2048,512};
 +
 +      bm = BM_Make_Mesh(ob, allocsize);
 +
 +      BMO_CallOpf(bm, "mesh_to_bmesh mesh=%p object=%p set_shapekey=%i", me, ob, 1);
 +
 +      return bm;
 +}
 +
  static void expand_local_mesh(Mesh *me)
  {
        id_lib_extern((ID *)me->texcomesh);
  
        if(me->mtface) {
 -              MTFace *tface;
                int a, i;
  
 +              for(i=0; i<me->pdata.totlayer; i++) {
 +                      if(me->pdata.layers[i].type == CD_MTEXPOLY) {
 +                              MTexPoly *txface= (MTexPoly*)me->fdata.layers[i].data;
 +
 +                              for(a=0; a<me->totpoly; a++, txface++) {
 +                                      /* special case: ima always local immediately */
 +                                      if(txface->tpage) {
 +                                              if(txface->tpage) {
 +                                                      id_lib_extern((ID *)txface->tpage);
 +                                              }
 +                                      }
 +                              }
 +                      }
 +              }
 +
                for(i=0; i<me->fdata.totlayer; i++) {
                        if(me->fdata.layers[i].type == CD_MTFACE) {
 -                              tface= (MTFace*)me->fdata.layers[i].data;
 +                              MTFace *tface= (MTFace*)me->fdata.layers[i].data;
  
                                for(a=0; a<me->totface; a++, tface++) {
 +                                      /* special case: ima always local immediately */
                                        if(tface->tpage) {
 -                                              id_lib_extern((ID *)tface->tpage);
 +                                              if(tface->tpage) {
 +                                                      id_lib_extern((ID *)tface->tpage);
 +                                              }
                                        }
                                }
                        }
@@@ -901,17 -572,13 +901,17 @@@ static void mfaces_strip_loose(MFace *m
  }
  
  /* Create edges based on known verts and faces */
 -static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, int UNUSED(totvert), int totface,
 +static void make_edges_mdata(MVert *UNUSED(allvert), MFace *allface, MLoop *allloop,
 +      MPoly *allpoly, int UNUSED(totvert), int totface, int UNUSED(totloop), int totpoly,
        int old, MEdge **alledge, int *_totedge)
  {
 +      MPoly *mpoly;
 +      MLoop *mloop;
        MFace *mface;
        MEdge *medge;
 +      EdgeHash *hash = BLI_edgehash_new();
        struct edgesort *edsort, *ed;
 -      int a, totedge=0, final=0;
 +      int a, b, totedge=0, final=0;
  
        /* we put all edges in array, sort them, and detect doubles that way */
  
        medge->flag |= ME_EDGERENDER;
  
        MEM_freeN(edsort);
 +      
 +      /*set edge members of mloops*/
 +      medge= *alledge;
 +      for (a=0; a<*_totedge; a++, medge++) {
 +              BLI_edgehash_insert(hash, medge->v1, medge->v2, SET_INT_IN_POINTER(a));
 +      }
 +      
 +      mpoly = allpoly;
 +      for (a=0; a<totpoly; a++, mpoly++) {
 +              mloop = allloop + mpoly->loopstart;
 +              for (b=0; b<mpoly->totloop; b++) {
 +                      int v1, v2;
 +                      
 +                      v1 = mloop[b].v;
 +                      v2 = ME_POLY_LOOP_NEXT(mloop, mpoly, b)->v;
 +                      mloop[b].e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(hash, v1, v2));
 +              }
 +      }
 +      
 +      BLI_edgehash_free(hash, NULL);
  }
  
  void make_edges(Mesh *me, int old)
        MEdge *medge;
        int totedge=0;
  
 -      make_edges_mdata(me->mvert, me->mface, me->totvert, me->totface, old, &medge, &totedge);
 +      make_edges_mdata(me->mvert, me->mface, me->mloop, me->mpoly, me->totvert, me->totface, me->totloop, me->totpoly, old, &medge, &totedge);
        if(totedge==0) {
                /* flag that mesh has edges */
                me->medge = medge;
@@@ -1106,43 -753,31 +1106,43 @@@ void mball_to_mesh(ListBase *lb, Mesh *
                }
  
                make_edges(me, 0);      // all edges
 -      }       
 +              convert_mfaces_to_mpolys(me);
 +
 +              me->totface = mesh_recalcTesselation(
 +                      &me->fdata, &me->ldata, &me->pdata,
 +                      me->mvert, me->totface, me->totloop, me->totpoly);
 +
 +              mesh_update_customdata_pointers(me, TRUE);
 +      }
  }
  
  /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
  /* return non-zero on error */
  int nurbs_to_mdata(Object *ob, MVert **allvert, int *totvert,
 -      MEdge **alledge, int *totedge, MFace **allface, int *totface)
 +      MEdge **alledge, int *totedge, MFace **allface, MLoop **allloop, MPoly **allpoly, 
 +      int *totface, int *totloop, int *totpoly)
  {
        return nurbs_to_mdata_customdb(ob, &ob->disp,
 -              allvert, totvert, alledge, totedge, allface, totface);
 +              allvert, totvert, alledge, totedge, allface, allloop, allpoly, totface, totloop, totpoly);
  }
  
  /* Initialize mverts, medges and, faces for converting nurbs to mesh and derived mesh */
  /* use specified dispbase  */
  int nurbs_to_mdata_customdb(Object *ob, ListBase *dispbase, MVert **allvert, int *_totvert,
 -      MEdge **alledge, int *_totedge, MFace **allface, int *_totface)
 +      MEdge **alledge, int *_totedge, MFace **allface, MLoop **allloop, MPoly **allpoly, 
 +      int *_totface, int *_totloop, int *_totpoly)
  {
        DispList *dl;
        Curve *cu;
        MVert *mvert;
        MFace *mface;
 +      MPoly *mpoly;
 +      MLoop *mloop;
        float *data;
        int a, b, ofs, vertcount, startvert, totvert=0, totvlak=0;
        int p1, p2, p3, p4, *index;
        int conv_polys= 0;
 +      int i, j;
  
        cu= ob->data;
  
  
        *allvert= mvert= MEM_callocN(sizeof (MVert) * totvert, "nurbs_init mvert");
        *allface= mface= MEM_callocN(sizeof (MFace) * totvlak, "nurbs_init mface");
 -
 +      *allloop = mloop = MEM_callocN(sizeof(MLoop) * totvlak * 4, "nurbs_init mloop");
 +      *allpoly = mpoly = MEM_callocN(sizeof(MPoly) * totvlak * 4, "nurbs_init mloop");
 +      
        /* verts and faces */
        vertcount= 0;
  
  
                dl= dl->next;
        }
 -
 +      
 +      mface= *allface;
 +      j = 0;
 +      for (i=0; i<totvert; i++, mpoly++, mface++) {
 +              int k;
 +              
 +              if (!mface->v3) {
 +                      mpoly--;
 +                      i--;
 +                      continue;
 +              }
 +              
 +              if (mface >= *allface + totvlak)
 +                      break;
 +
 +              mpoly->flag |= mface->flag & ME_SMOOTH;
 +              mpoly->loopstart= j;
 +              mpoly->totloop= mface->v4 ? 4 : 3;
 +              for (k=0; k<mpoly->totloop; k++, mloop++, j++) {
 +                      mloop->v = (&mface->v1)[k];
 +              }
 +      }
 +      
 +      *_totpoly= i;
 +      *_totloop= j;
        *_totvert= totvert;
        *_totface= totvlak;
  
 -      make_edges_mdata(*allvert, *allface, totvert, totvlak, 0, alledge, _totedge);
 +      make_edges_mdata(*allvert, *allface, *allloop, *allpoly, totvert, totvlak, *_totloop, *_totpoly, 0, alledge, _totedge);
        mfaces_strip_loose(*allface, _totface);
  
        return 0;
@@@ -1366,14 -975,12 +1366,14 @@@ void nurbs_to_mesh(Object *ob
        MVert *allvert= NULL;
        MEdge *alledge= NULL;
        MFace *allface= NULL;
 -      int totvert, totedge, totface;
 +      MLoop *allloop = NULL;
 +      MPoly *allpoly = NULL;
 +      int totvert, totedge, totface, totloop, totpoly;
  
        cu= ob->data;
  
        if (dm == NULL) {
 -              if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &totface) != 0) {
 +              if (nurbs_to_mdata (ob, &allvert, &totvert, &alledge, &totedge, &allface, &allloop, &allpoly, &totface, &totloop, &totpoly) != 0) {
                        /* Error initializing */
                        return;
                }
                me->totvert= totvert;
                me->totface= totface;
                me->totedge= totedge;
 +              me->totloop = totloop;
 +              me->totpoly = totpoly;
  
                me->mvert= CustomData_add_layer(&me->vdata, CD_MVERT, CD_ASSIGN, allvert, me->totvert);
                me->medge= CustomData_add_layer(&me->edata, CD_MEDGE, CD_ASSIGN, alledge, me->totedge);
                me->mface= CustomData_add_layer(&me->fdata, CD_MFACE, CD_ASSIGN, allface, me->totface);
 +              me->mloop= CustomData_add_layer(&me->ldata, CD_MLOOP, CD_ASSIGN, allloop, me->totloop);
 +              me->mpoly= CustomData_add_layer(&me->pdata, CD_MPOLY, CD_ASSIGN, allpoly, me->totpoly);
  
 -              mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
 +              mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, me->totpoly, NULL, NULL, 0, NULL, NULL);
        } else {
                me= add_mesh("Mesh");
 -              DM_to_mesh(dm, me);
 +              DM_to_mesh(dm, me, ob);
        }
  
        me->totcol= cu->totcol;
@@@ -1456,10 -1059,10 +1456,10 @@@ void mesh_to_curve(Scene *scene, Objec
  
        MVert *mverts= dm->getVertArray(dm);
        MEdge *med, *medge= dm->getEdgeArray(dm);
 -      MFace *mf,  *mface= dm->getFaceArray(dm);
 +      MFace *mf,  *mface= dm->getTessFaceArray(dm);
  
        int totedge = dm->getNumEdges(dm);
 -      int totface = dm->getNumFaces(dm);
 +      int totface = dm->getNumTessFaces(dm);
        int totedges = 0;
        int i, needsFree = 0;
  
  
  void mesh_delete_material_index(Mesh *me, short index)
  {
 -      MFace *mf;
        int i;
  
 -      for (i=0, mf=me->mface; i<me->totface; i++, mf++) {
 +      for (i=0; i<me->totpoly; i++) {
 +              MPoly *mp = &((MPoly*) me->mpoly)[i];
 +              if (mp->mat_nr && mp->mat_nr>=index) 
 +                      mp->mat_nr--;
 +      }
 +      
 +      for (i=0; i<me->totface; i++) {
 +              MFace *mf = &((MFace*) me->mface)[i];
                if (mf->mat_nr && mf->mat_nr>=index) 
                        mf->mat_nr--;
        }
@@@ -1642,16 -1239,6 +1642,16 @@@ void mesh_set_smooth_flag(Object *meshO
        Mesh *me = meshOb->data;
        int i;
  
 +      for (i=0; i<me->totpoly; i++) {
 +              MPoly *mp = &((MPoly*) me->mpoly)[i];
 +
 +              if (enableSmooth) {
 +                      mp->flag |= ME_SMOOTH;
 +              } else {
 +                      mp->flag &= ~ME_SMOOTH;
 +              }
 +      }
 +      
        for (i=0; i<me->totface; i++) {
                MFace *mf = &((MFace*) me->mface)[i];
  
                        mf->flag &= ~ME_SMOOTH;
                }
        }
-       mesh_calc_normals(me->mvert, me->totvert, me->mloop, me->mpoly, me->totloop, 
-                                         me->totpoly, NULL, NULL, 0, NULL, NULL);
  }
  
 -void mesh_calc_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) 
 +void mesh_calc_normals(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys,
 +              int numLoops, int numPolys, float (*polyNors_r)[3], MFace *mfaces, int numFaces,
 +              int *origIndexFace, float (*faceNors_r)[3])
 +{
 +      mesh_calc_normals_ex(mverts, numVerts, mloop, mpolys,
 +                        numLoops, numPolys, polyNors_r, mfaces, numFaces,
 +                        origIndexFace, faceNors_r, TRUE);
 +}
 +void mesh_calc_normals_ex(MVert *mverts, int numVerts, MLoop *mloop, MPoly *mpolys,
 +              int UNUSED(numLoops), int numPolys, float (*polyNors_r)[3], MFace *mfaces, int numFaces,
 +              int *origIndexFace, float (*faceNors_r)[3],
 +              const short only_face_normals)
 +{
 +      float (*pnors)[3] = polyNors_r, (*fnors)[3] = faceNors_r;
 +      int i, j;
 +      MFace *mf;
 +      MPoly *mp;
 +      MLoop *ml;
 +
 +      if (numPolys == 0) {
 +              return;
 +      }
 +
 +      /* if we are not calculating verts and no verts were passes thene we have nothign to do */
 +      if ((only_face_normals == TRUE) && (polyNors_r == NULL) && (faceNors_r == NULL)) {
 +              printf("%s: called with nothing to do\n", __func__);
 +              return;
 +      }
 +
 +      if (!pnors) pnors = MEM_callocN(sizeof(float) * 3 * numPolys, "poly_nors mesh.c");
 +      /* if (!fnors) fnors = MEM_callocN(sizeof(float) * 3 * numFaces, "face nors mesh.c"); */ /* NO NEED TO ALLOC YET */
 +
 +
 +      if (only_face_normals == FALSE) {
 +              /* vertex normals are optional, they require some extra calculations,
 +               * so make them optional */
 +
 +              float (*tnorms)[3], (*edgevecbuf)[3]= NULL;
 +              float **vertcos = NULL, **vertnos = NULL;
 +              BLI_array_declare(vertcos);
 +              BLI_array_declare(vertnos);
 +              BLI_array_declare(edgevecbuf);
 +
 +              /*first go through and calculate normals for all the polys*/
 +              tnorms = MEM_callocN(sizeof(float)*3*numVerts, "tnorms mesh.c");
 +
 +              mp = mpolys;
 +              for (i=0; i<numPolys; i++, mp++) {
 +                      mesh_calc_poly_normal(mp, mloop+mp->loopstart, mverts, pnors[i]);
 +                      ml = mloop + mp->loopstart;
 +
 +                      BLI_array_empty(vertcos);
 +                      BLI_array_empty(vertnos);
 +                      for (j=0; j<mp->totloop; j++) {
 +                              int vindex = ml[j].v;
 +                              BLI_array_append(vertcos, mverts[vindex].co);
 +                              BLI_array_append(vertnos, tnorms[vindex]);
 +                      }
 +
 +                      BLI_array_empty(edgevecbuf);
 +                      BLI_array_growitems(edgevecbuf, mp->totloop);
 +
 +                      accumulate_vertex_normals_poly(vertnos, pnors[i], vertcos, edgevecbuf, mp->totloop);
 +              }
 +
 +              BLI_array_free(vertcos);
 +              BLI_array_free(vertnos);
 +              BLI_array_free(edgevecbuf);
 +
 +              /* following Mesh convention; we use vertex coordinate itself for normal in this case */
 +              for(i=0; i<numVerts; i++) {
 +                      MVert *mv= &mverts[i];
 +                      float *no= tnorms[i];
 +
 +                      if(normalize_v3(no) == 0.0f)
 +                              normalize_v3_v3(no, mv->co);
 +
 +                      normal_float_to_short_v3(mv->no, no);
 +              }
 +
 +              MEM_freeN(tnorms);
 +      }
 +      else {
 +              /* only calc poly normals */
 +              mp = mpolys;
 +              for (i=0; i<numPolys; i++, mp++) {
 +                      mesh_calc_poly_normal(mp, mloop+mp->loopstart, mverts, pnors[i]);
 +              }
 +      }
 +
 +      if ( origIndexFace &&
 +           /* fnors==faceNors_r */ /* NO NEED TO ALLOC YET */
 +           fnors != NULL &&
 +           numFaces)
 +      {
 +              mf = mfaces;
 +              for (i=0; i<numFaces; i++, mf++, origIndexFace++) {
 +                      if (*origIndexFace < numPolys) {
 +                              copy_v3_v3(fnors[i], pnors[*origIndexFace]);
 +                      } else {
 +                              /*eek, we're not corrusponding to polys*/
 +                              printf("error in mesh_calc_normals; tesselation face indices are incorrect.  normals may look bad.\n");
 +                      }
 +              }
 +      }
 +
 +      if (pnors != polyNors_r) MEM_freeN(pnors);
 +      /* if (fnors != faceNors_r) MEM_freeN(fnors); */ /* NO NEED TO ALLOC YET */
 +
 +      fnors = pnors = NULL;
 +      
 +}
 +
 +void mesh_calc_tessface_normals(MVert *mverts, int numVerts, MFace *mfaces, int numFaces, float (*faceNors_r)[3]) 
  {
        float (*tnorms)[3]= MEM_callocN(numVerts*sizeof(*tnorms), "tnorms");
        float (*fnors)[3]= (faceNors_r)? faceNors_r: MEM_callocN(sizeof(*fnors)*numFaces, "meshnormals");
                MEM_freeN(fnors);
  }
  
 +
 +static void bmesh_corners_to_loops(Mesh *me, int findex, int loopstart, int numTex, int numCol)
 +{
 +      MTFace *texface;
 +      MTexPoly *texpoly;
 +      MCol *mcol;
 +      MLoopCol *mloopcol;
 +      MLoopUV *mloopuv;
 +      MFace *mf;
 +      int i;
 +
 +      mf = me->mface + findex;
 +
 +      for(i=0; i < numTex; i++){
 +              texface = CustomData_get_n(&me->fdata, CD_MTFACE, findex, i);
 +              texpoly = CustomData_get_n(&me->pdata, CD_MTEXPOLY, findex, i); 
 +              
 +              texpoly->tpage = texface->tpage;
 +              texpoly->flag = texface->flag;
 +              texpoly->transp = texface->transp;
 +              texpoly->mode = texface->mode;
 +              texpoly->tile = texface->tile;
 +              texpoly->unwrap = texface->unwrap;
 +      
 +              mloopuv = CustomData_get_n(&me->ldata, CD_MLOOPUV, loopstart, i);
 +              mloopuv->uv[0] = texface->uv[0][0]; mloopuv->uv[1] = texface->uv[0][1]; mloopuv++;
 +              mloopuv->uv[0] = texface->uv[1][0]; mloopuv->uv[1] = texface->uv[1][1]; mloopuv++;
 +              mloopuv->uv[0] = texface->uv[2][0]; mloopuv->uv[1] = texface->uv[2][1]; mloopuv++;
 +
 +              if (mf->v4) {
 +                      mloopuv->uv[0] = texface->uv[3][0]; mloopuv->uv[1] = texface->uv[3][1]; mloopuv++;
 +              }
 +      }
 +
 +      for(i=0; i < numCol; i++){
 +              mloopcol = CustomData_get_n(&me->ldata, CD_MLOOPCOL, loopstart, i);
 +              mcol = CustomData_get_n(&me->fdata, CD_MCOL, findex, i);
 +
 +              mloopcol->r = mcol[0].r; mloopcol->g = mcol[0].g; mloopcol->b = mcol[0].b; mloopcol->a = mcol[0].a; mloopcol++;
 +              mloopcol->r = mcol[1].r; mloopcol->g = mcol[1].g; mloopcol->b = mcol[1].b; mloopcol->a = mcol[1].a; mloopcol++;
 +              mloopcol->r = mcol[2].r; mloopcol->g = mcol[2].g; mloopcol->b = mcol[2].b; mloopcol->a = mcol[2].a; mloopcol++;
 +              if (mf->v4) {
 +                      mloopcol->r = mcol[3].r; mloopcol->g = mcol[3].g; mloopcol->b = mcol[3].b; mloopcol->a = mcol[3].a; mloopcol++;
 +              }
 +      }
 +      
 +      if (CustomData_has_layer(&me->fdata, CD_MDISPS)) {
 +              MDisps *ld = CustomData_get(&me->ldata, loopstart, CD_MDISPS);
 +              MDisps *fd = CustomData_get(&me->fdata, findex, CD_MDISPS);
 +              float (*disps)[3] = fd->disps;
 +              int i, tot = mf->v4 ? 4 : 3;
 +              int side, corners;
 +              
 +              corners = multires_mdisp_corners(fd);
 +              
 +              if (corners == 0) {
 +                      /* Empty MDisp layers appear in at least one of the sintel.blend files.
 +                         Not sure why this happens, but it seems fine to just ignore them here.
 +                         If corners==0 for a non-empty layer though, something went wrong. */
 +                      BLI_assert(fd->totdisp == 0);
 +              }
 +              else {
 +                      side = sqrt(fd->totdisp / corners);
 +              
 +                      for (i=0; i<tot; i++, disps += side*side, ld++) {
 +                              ld->totdisp = side*side;
 +                      
 +                              if (ld->disps)
 +                                      BLI_cellalloc_free(ld->disps);
 +                      
 +                              ld->disps = BLI_cellalloc_calloc(sizeof(float)*3*side*side, "converted loop mdisps");
 +                              if (fd->disps) {
 +                                      memcpy(ld->disps, disps, sizeof(float)*3*side*side);
 +                              }
 +                      }
 +              }
 +      }
 +}
 +
 +void convert_mfaces_to_mpolys(Mesh *mesh)
 +{
 +      MFace *mf;
 +      MLoop *ml;
 +      MPoly *mp;
 +      MEdge *me;
 +      EdgeHash *eh;
 +      int numTex, numCol;
 +      int i, j, totloop;
 +
 +      mesh->totpoly = mesh->totface;
 +      mesh->mpoly = MEM_callocN(sizeof(MPoly)*mesh->totpoly, "mpoly converted");
 +      CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_ASSIGN, mesh->mpoly, mesh->totpoly);
 +
 +      numTex = CustomData_number_of_layers(&mesh->fdata, CD_MTFACE);
 +      numCol = CustomData_number_of_layers(&mesh->fdata, CD_MCOL);
 +      
 +      totloop = 0;
 +      mf = mesh->mface;
 +      for (i=0; i<mesh->totface; i++, mf++) {
 +              totloop += mf->v4 ? 4 : 3;
 +      }
 +      
 +      mesh->totloop = totloop;
 +      mesh->mloop = MEM_callocN(sizeof(MLoop)*mesh->totloop, "mloop converted");
 +
 +      CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_ASSIGN, mesh->mloop, totloop);
 +      CustomData_to_bmeshpoly(&mesh->fdata, &mesh->pdata, &mesh->ldata,
 +              mesh->totloop, mesh->totpoly);
 +
 +      eh = BLI_edgehash_new();
 +
 +      /*build edge hash*/
 +      me = mesh->medge;
 +      for (i=0; i<mesh->totedge; i++, me++) {
 +              BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
 +      }
 +
 +      j = 0; /*current loop index*/
 +      ml = mesh->mloop;
 +      mf = mesh->mface;
 +      mp = mesh->mpoly;
 +      for (i=0; i<mesh->totface; i++, mf++, mp++) {
 +              mp->loopstart = j;
 +              
 +              mp->totloop = mf->v4 ? 4 : 3;
 +
 +              mp->mat_nr = mf->mat_nr;
 +              mp->flag = mf->flag;
 +              
 +              #define ML(v1, v2) {ml->v = mf->v1; ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); ml++; j++;}
 +              
 +              ML(v1, v2);
 +              ML(v2, v3);
 +              if (mf->v4) {
 +                      ML(v3, v4);
 +                      ML(v4, v1);
 +              } else {
 +                      ML(v3, v1);
 +              }
 +              
 +              #undef ML
 +
 +              bmesh_corners_to_loops(mesh, i, mp->loopstart, numTex, numCol);
 +      }
 +
 +      /* note, we dont convert FGons at all, these are not even real ngons,
 +       * they have their own UV's, colors etc - its more an editing feature. */
 +
 +      mesh_update_customdata_pointers(mesh, TRUE);
 +
 +      BLI_edgehash_free(eh, NULL);
 +}
 +
  float (*mesh_getVertexCos(Mesh *me, int *numVerts_r))[3]
  {
        int i, numVerts = me->totvert;
        
        if (numVerts_r) *numVerts_r = numVerts;
        for (i=0; i<numVerts; i++)
 -              VECCOPY(cos[i], me->mvert[i].co);
 +              copy_v3_v3(cos[i], me->mvert[i].co);
        
        return cos;
  }
  
 -UvVertMap *make_uv_vert_map(struct MFace *mface, struct MTFace *tface, unsigned int totface, unsigned int totvert, int selected, float *limit)
 +
 +/* ngon version wip, based on EDBM_make_uv_vert_map */
 +/* this replaces the non bmesh function (in trunk) which takes MTFace's, if we ever need it back we could
 + * but for now this replaces it because its unused. */
 +
 +UvVertMap *make_uv_vert_map(struct MPoly *mpoly, struct MLoop *mloop, struct MLoopUV *mloopuv, unsigned int totpoly, unsigned int totvert, int selected, float *limit)
  {
        UvVertMap *vmap;
        UvMapVert *buf;
 -      MFace *mf;
 +      MPoly *mp;
        unsigned int a;
        int     i, totuv, nverts;
  
        totuv = 0;
  
        /* generate UvMapVert array */
 -      mf= mface;
 -      for(a=0; a<totface; a++, mf++)
 -              if(!selected || (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL)))
 -                      totuv += (mf->v4)? 4: 3;
 -              
 +      mp= mpoly;
 +      for(a=0; a<totpoly; a++, mp++)
 +              if(!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL)))
 +                      totuv += mp->totloop;
 +
        if(totuv==0)
                return NULL;
        
                return NULL;
        }
  
 -      mf= mface;
 -      for(a=0; a<totface; a++, mf++) {
 -              if(!selected || (!(mf->flag & ME_HIDE) && (mf->flag & ME_FACE_SEL))) {
 -                      nverts= (mf->v4)? 4: 3;
 +      mp= mpoly;
 +      for(a=0; a<totpoly; a++, mp++) {
 +              if(!selected || (!(mp->flag & ME_HIDE) && (mp->flag & ME_FACE_SEL))) {
 +                      nverts= mp->totloop;
  
                        for(i=0; i<nverts; i++) {
                                buf->tfindex= i;
                                buf->f= a;
                                buf->separate = 0;
 -                              buf->next= vmap->vert[*(&mf->v1 + i)];
 -                              vmap->vert[*(&mf->v1 + i)]= buf;
 +                              buf->next= vmap->vert[mloop[mp->loopstart + i].v];
 +                              vmap->vert[mloop[mp->loopstart + i].v]= buf;
                                buf++;
                        }
                }
                        v->next= newvlist;
                        newvlist= v;
  
 -                      uv= tface[v->f].uv[v->tfindex];
 +                      uv= mloopuv[mpoly[v->f].loopstart + v->tfindex].uv;
                        lastv= NULL;
                        iterv= vlist;
  
                        while(iterv) {
                                next= iterv->next;
  
 -                              uv2= tface[iterv->f].uv[iterv->tfindex];
 +                              uv2= mloopuv[mpoly[iterv->f].loopstart + iterv->tfindex].uv;
                                sub_v2_v2v2(uvdiff, uv2, uv);
  
  
@@@ -2134,6 -1447,8 +2131,6 @@@ void create_vert_edge_map(ListBase **ma
        }
  }
  
 -#ifdef USE_BMESH_FORWARD_COMPAT
 -
  void mesh_loops_to_mface_corners(CustomData *fdata, CustomData *ldata,
                                   CustomData *pdata, int lindex[4], int findex,
                                   const int polyindex,
        }
  }
  
 +/*
 +  this function recreates a tesselation.
 +  returns number of tesselation faces.
 + */
 +int mesh_recalcTesselation(CustomData *fdata, 
 +                           CustomData *ldata, CustomData *pdata,
 +                           MVert *mvert, int totface, int UNUSED(totloop),
 +                           int totpoly)
 +{
 +
 +      /* use this to avoid locking pthread for _every_ polygon
 +       * and calling the fill function */
 +
 +#define USE_TESSFACE_SPEEDUP
 +
 +      MPoly *mp, *mpoly;
 +      MLoop *ml, *mloop;
 +      MFace *mface = NULL, *mf;
 +      BLI_array_declare(mface);
 +      EditVert *v, *lastv, *firstv;
 +      EditFace *f;
 +      int *origIndex = NULL;
 +      BLI_array_declare(origIndex);
 +      int *polyIndex = NULL;
 +      BLI_array_declare(polyIndex);
 +      int lindex[4]; /* only ever use 3 in this case */
 +      int *polyorigIndex;
 +      int i, j, k;
 +
 +      const int numTex = CustomData_number_of_layers(pdata, CD_MTEXPOLY);
 +      const int numCol = CustomData_number_of_layers(ldata, CD_MLOOPCOL);
 +      const int hasWCol = CustomData_has_layer(ldata, CD_WEIGHT_MLOOPCOL);
 +
 +      mpoly = CustomData_get_layer(pdata, CD_MPOLY);
 +      mloop = CustomData_get_layer(ldata, CD_MLOOP);
 +
 +      k = 0;
 +      mp = mpoly;
 +      polyorigIndex = CustomData_get_layer(pdata, CD_ORIGINDEX);
 +      for (i=0; i<totpoly; i++, mp++) {
 +              if (mp->totloop < 3) {
 +                      /* do nothing */
 +              }
 +
 +#ifdef USE_TESSFACE_SPEEDUP
 +
 +#define ML_TO_MF(i1, i2, i3)                                                  \
 +              BLI_array_growone(mface);                                             \
 +              BLI_array_append(polyIndex, i);                                       \
 +              mf= &mface[k];                                                        \
 +              /* set loop indices, transformed to vert indices later */             \
 +              mf->v1 = mp->loopstart + i1;                                          \
 +              mf->v2 = mp->loopstart + i2;                                          \
 +              mf->v3 = mp->loopstart + i3;                                          \
 +              mf->v4 = 0;                                                           \
 +              mf->mat_nr = mp->mat_nr;                                              \
 +              mf->flag = mp->flag;                                                  \
 +              if (polyorigIndex) {                                                  \
 +                      BLI_array_append(origIndex, polyorigIndex[polyIndex[k]]);         \
 +              }                                                                     \
 +
 +              else if (mp->totloop == 3) {
 +                      ml = mloop + mp->loopstart;
 +                      ML_TO_MF(0, 1, 2)
 +                      k++;
 +              }
 +              else if (mp->totloop == 4) {
 +                      ml = mloop + mp->loopstart;
 +                      ML_TO_MF(0, 1, 2)
 +                      k++;
 +                      ML_TO_MF(0, 2, 3)
 +                      k++;
 +              }
 +#endif /* USE_TESSFACE_SPEEDUP */
 +              else {
 +                      ml = mloop + mp->loopstart;
 +                      
 +                      BLI_begin_edgefill();
 +                      firstv = NULL;
 +                      lastv = NULL;
 +                      for (j=0; j<mp->totloop; j++, ml++) {
 +                              v = BLI_addfillvert(mvert[ml->v].co);
 +      
 +                              v->keyindex = mp->loopstart + j;
 +      
 +                              if (lastv)
 +                                      BLI_addfilledge(lastv, v);
 +      
 +                              if (!firstv)
 +                                      firstv = v;
 +                              lastv = v;
 +                      }
 +                      BLI_addfilledge(lastv, firstv);
 +                      
 +                      BLI_edgefill(2);
 +                      for (f=fillfacebase.first; f; f=f->next) {
 +                              BLI_array_growone(mface);
 +                              BLI_array_append(polyIndex, i);
 +                              mf= &mface[k];
 +
 +                              /* set loop indices, transformed to vert indices later */
 +                              mf->v1 = f->v1->keyindex;
 +                              mf->v2 = f->v2->keyindex;
 +                              mf->v3 = f->v3->keyindex;
 +                              mf->v4 = 0;
 +                              
 +                              mf->mat_nr = mp->mat_nr;
 +                              mf->flag = mp->flag;
 +
 +#ifdef USE_TESSFACE_SPEEDUP
 +                              mf->edcode = 1; /* tag for sorting loop indicies */
 +#endif
 +
 +                              if (polyorigIndex) {
 +                                      BLI_array_append(origIndex, polyorigIndex[polyIndex[k]]);
 +                              }
 +      
 +                              k++;
 +                      }
 +      
 +                      BLI_end_edgefill();
 +              }
 +      }
 +
 +      CustomData_free(fdata, totface);
 +      memset(fdata, 0, sizeof(CustomData));
 +      totface = k;
 +      
 +      CustomData_add_layer(fdata, CD_MFACE, CD_ASSIGN, mface, totface);
 +
 +      /* CD_POLYINDEX will contain an array of indices from tessfaces to the polygons
 +       * they are directly tesselated from */
 +      CustomData_add_layer(fdata, CD_POLYINDEX, CD_ASSIGN, polyIndex, totface);
 +      if (origIndex) {
 +              /* If polys had a CD_ORIGINDEX layer, then the tesselated faces will get this
 +               * layer as well, pointing to polys from the original mesh (not the polys
 +               * that just got tesselated) */
 +              CustomData_add_layer(fdata, CD_ORIGINDEX, CD_ASSIGN, origIndex, totface);
 +      }
 +
 +      CustomData_from_bmeshpoly(fdata, pdata, ldata, totface);
 +
 +      /* If polys have a normals layer, copying that to faces can help
 +       * avoid the need to recalculate normals later */
 +      if (CustomData_has_layer(pdata, CD_NORMAL)) {
 +              float *pnors = CustomData_get_layer(pdata, CD_NORMAL);
 +              float *fnors = CustomData_add_layer(fdata, CD_NORMAL, CD_CALLOC, NULL, totface);
 +              for (i=0; i<totface; i++, fnors++) {
 +                      copy_v3_v3(fnors, &pnors[polyIndex[i]]);
 +              }
 +      }
 +
 +      mf = mface;
 +      for (i=0; i < totface; i++, mf++) {
 +
 +#ifdef USE_TESSFACE_SPEEDUP
 +              /* skip sorting when not using ngons */
 +              if (UNLIKELY(mf->edcode == 1))
 +#endif
 +              {
 +                      /* sort loop indices to ensure winding is correct */
 +                      if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2);
 +                      if (mf->v2 > mf->v3) SWAP(int, mf->v2, mf->v3);
 +                      if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2);
 +
 +                      if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2);
 +                      if (mf->v2 > mf->v3) SWAP(int, mf->v2, mf->v3);
 +                      if (mf->v1 > mf->v2) SWAP(int, mf->v1, mf->v2);
 +
 +#ifdef USE_TESSFACE_SPEEDUP
 +                      mf->edcode = 0;
 +#endif
 +              }
 +
 +              lindex[0] = mf->v1;
 +              lindex[1] = mf->v2;
 +              lindex[2] = mf->v3;
 +
 +              /*transform loop indices to vert indices*/
 +              mf->v1 = mloop[mf->v1].v;
 +              mf->v2 = mloop[mf->v2].v;
 +              mf->v3 = mloop[mf->v3].v;
 +
 +              mesh_loops_to_mface_corners(fdata, ldata, pdata,
 +                                          lindex, i, polyIndex[i], 3,
 +                                          numTex, numCol, hasWCol);
 +      }
 +
 +      return totface;
 +
 +#undef USE_TESSFACE_SPEEDUP
 +
 +}
 +
 +
 +#ifdef USE_BMESH_SAVE_AS_COMPAT
  
  /*
   * this function recreates a tesselation.
@@@ -2501,261 -1620,10 +2498,261 @@@ int mesh_mpoly_to_mface(struct CustomDa
  
        return k;
  }
 +#endif /* USE_BMESH_SAVE_AS_COMPAT */
 +
 +/*
 + * COMPUTE POLY NORMAL
 + *
 + * Computes the normal of a planar 
 + * polygon See Graphics Gems for 
 + * computing newell normal.
 + *
 +*/
 +static void mesh_calc_ngon_normal(MPoly *mpoly, MLoop *loopstart, 
 +                                  MVert *mvert, float normal[3])
 +{
 +
 +      MVert *v1, *v2, *v3;
 +      double u[3], v[3], w[3];
 +      double n[3] = {0.0, 0.0, 0.0}, l;
 +      int i;
 +
 +      for(i = 0; i < mpoly->totloop; i++){
 +              v1 = mvert + loopstart[i].v;
 +              v2 = mvert + loopstart[(i+1)%mpoly->totloop].v;
 +              v3 = mvert + loopstart[(i+2)%mpoly->totloop].v;
 +              
 +              VECCOPY(u, v1->co);
 +              VECCOPY(v, v2->co);
 +              VECCOPY(w, v3->co);
 +
 +              /*this fixes some weird numerical error*/
 +              if (i==0) {
 +                      u[0] += 0.0001f;
 +                      u[1] += 0.0001f;
 +                      u[2] += 0.0001f;
 +              }
 +              
 +              /* newell's method
 +              
 +              so thats?:
 +              (a[1] - b[1]) * (a[2] + b[2]);
 +              a[1]*b[2] - b[1]*a[2] - b[1]*b[2] + a[1]*a[2]
 +
 +              odd.  half of that is the cross product. . .what's the
 +              other half?
 +
 +              also could be like a[1]*(b[2] + a[2]) - b[1]*(a[2] - b[2])
 +              */
 +
 +              n[0] += (u[1] - v[1]) * (u[2] + v[2]);
 +              n[1] += (u[2] - v[2]) * (u[0] + v[0]);
 +              n[2] += (u[0] - v[0]) * (u[1] + v[1]);
 +      }
 +      
 +      l = n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
 +      l = sqrt(l);
 +
 +      if (l == 0.0) {
 +              normal[0] = 0.0f;
 +              normal[1] = 0.0f;
 +              normal[2] = 1.0f;
 +
 +              return;
 +      } else l = 1.0f / l;
 +
 +      n[0] *= l;
 +      n[1] *= l;
 +      n[2] *= l;
 +      
 +      normal[0] = (float) n[0];
 +      normal[1] = (float) n[1];
 +      normal[2] = (float) n[2];
 +}
  
 -#endif /* USE_BMESH_FORWARD_COMPAT */
 +void mesh_calc_poly_normal(MPoly *mpoly, MLoop *loopstart, 
 +                           MVert *mvarray, float no[3])
 +{
 +      if (mpoly->totloop > 4) {
 +              mesh_calc_ngon_normal(mpoly, loopstart, mvarray, no);
 +      }
 +      else if (mpoly->totloop == 3){
 +              normal_tri_v3(no,
 +                            mvarray[loopstart[0].v].co,
 +                            mvarray[loopstart[1].v].co,
 +                            mvarray[loopstart[2].v].co
 +                            );
 +      }
 +      else if (mpoly->totloop == 4) {
 +              normal_quad_v3(no,
 +                             mvarray[loopstart[0].v].co,
 +                             mvarray[loopstart[1].v].co,
 +                             mvarray[loopstart[2].v].co,
 +                             mvarray[loopstart[3].v].co
 +                             );
 +      }
 +      else { /* horrible, two sided face! */
 +              no[0] = 0.0;
 +              no[1] = 0.0;
 +              no[2] = 1.0;
 +      }
 +}
 +/* duplicate of function above _but_ takes coords rather then mverts */
 +static void mesh_calc_ngon_normal_coords(MPoly *mpoly, MLoop *loopstart,
 +                                         const float (*vertex_coords)[3], float normal[3])
 +{
 +
 +      float *v1, *v2, *v3;
 +      double u[3], v[3], w[3];
 +      double n[3] = {0.0, 0.0, 0.0}, l;
 +      int i;
 +
 +      for(i = 0; i < mpoly->totloop; i++){
 +              v1 = vertex_coords + loopstart[i].v;
 +              v2 = vertex_coords + loopstart[(i+1)%mpoly->totloop].v;
 +              v3 = vertex_coords + loopstart[(i+2)%mpoly->totloop].v;
 +
 +              VECCOPY(u, v1);
 +              VECCOPY(v, v2);
 +              VECCOPY(w, v3);
 +
 +              /*this fixes some weird numerical error*/
 +              if (i==0) {
 +                      u[0] += 0.0001f;
 +                      u[1] += 0.0001f;
 +                      u[2] += 0.0001f;
 +              }
 +
 +              n[0] += (u[1] - v[1]) * (u[2] + v[2]);
 +              n[1] += (u[2] - v[2]) * (u[0] + v[0]);
 +              n[2] += (u[0] - v[0]) * (u[1] + v[1]);
 +      }
  
 +      l = n[0]*n[0]+n[1]*n[1]+n[2]*n[2];
 +      l = sqrt(l);
  
 +      if (l == 0.0) {
 +              normal[0] = 0.0f;
 +              normal[1] = 0.0f;
 +              normal[2] = 1.0f;
 +
 +              return;
 +      } else l = 1.0f / l;
 +
 +      n[0] *= l;
 +      n[1] *= l;
 +      n[2] *= l;
 +
 +      normal[0] = (float) n[0];
 +      normal[1] = (float) n[1];
 +      normal[2] = (float) n[2];
 +}
 +
 +void mesh_calc_poly_normal_coords(MPoly *mpoly, MLoop *loopstart,
 +                           const float (*vertex_coords)[3], float no[3])
 +{
 +      if (mpoly->totloop > 4) {
 +              mesh_calc_ngon_normal_coords(mpoly, loopstart, vertex_coords, no);
 +      }
 +      else if (mpoly->totloop == 3){
 +              normal_tri_v3(no,
 +                            vertex_coords[loopstart[0].v],
 +                            vertex_coords[loopstart[1].v],
 +                            vertex_coords[loopstart[2].v]
 +                            );
 +      }
 +      else if (mpoly->totloop == 4) {
 +              normal_quad_v3(no,
 +                             vertex_coords[loopstart[0].v],
 +                             vertex_coords[loopstart[1].v],
 +                             vertex_coords[loopstart[2].v],
 +                             vertex_coords[loopstart[3].v]
 +                             );
 +      }
 +      else { /* horrible, two sided face! */
 +              no[0] = 0.0;
 +              no[1] = 0.0;
 +              no[2] = 1.0;
 +      }
 +}
 +
 +static void mesh_calc_ngon_center(MPoly *mpoly, MLoop *loopstart,
 +                                  MVert *mvert, float cent[3])
 +{
 +      const float w= 1.0f / (float)mpoly->totloop;
 +      int i;
 +
 +      zero_v3(cent);
 +
 +      for (i = 0; i < mpoly->totloop; i++) {
 +              madd_v3_v3fl(cent, mvert[(loopstart++)->v].co, w);
 +      }
 +}
 +
 +void mesh_calc_poly_center(MPoly *mpoly, MLoop *loopstart,
 +                           MVert *mvarray, float cent[3])
 +{
 +      if (mpoly->totloop == 3) {
 +              cent_tri_v3(cent,
 +                          mvarray[loopstart[0].v].co,
 +                          mvarray[loopstart[1].v].co,
 +                          mvarray[loopstart[2].v].co
 +                          );
 +      }
 +      else if (mpoly->totloop == 4) {
 +              cent_quad_v3(cent,
 +                           mvarray[loopstart[0].v].co,
 +                           mvarray[loopstart[1].v].co,
 +                           mvarray[loopstart[2].v].co,
 +                           mvarray[loopstart[3].v].co
 +                           );
 +      }
 +      else {
 +              mesh_calc_ngon_center(mpoly, loopstart, mvarray, cent);
 +      }
 +}
 +
 +/* note, passing polynormal is only a speedup so we can skip calculating it */
 +float mesh_calc_poly_area(MPoly *mpoly, MLoop *loopstart,
 +                          MVert *mvarray, float polynormal[3])
 +{
 +      if (mpoly->totloop == 3) {
 +              return area_tri_v3(mvarray[loopstart[0].v].co,
 +                                 mvarray[loopstart[1].v].co,
 +                                 mvarray[loopstart[2].v].co
 +                                 );
 +      }
 +      else if (mpoly->totloop == 4) {
 +              return area_quad_v3(mvarray[loopstart[0].v].co,
 +                                  mvarray[loopstart[1].v].co,
 +                                  mvarray[loopstart[2].v].co,
 +                                  mvarray[loopstart[3].v].co
 +                                  );
 +      }
 +      else {
 +              int i;
 +              float area, polynorm_local[3], (*vertexcos)[3];
 +              float *no= polynormal ? polynormal : polynorm_local;
 +              BLI_array_fixedstack_declare(vertexcos, BM_NGON_STACK_SIZE, mpoly->totloop, __func__);
 +
 +              /* pack vertex cos into an array for area_poly_v3 */
 +              for (i = 0; i < mpoly->totloop; i++) {
 +                      copy_v3_v3(vertexcos[i], mvarray[(loopstart++)->v].co);
 +              }
 +
 +              /* need normal for area_poly_v3 as well */
 +              if (polynormal == NULL) {
 +                      mesh_calc_poly_normal(mpoly, loopstart, mvarray, no);
 +              }
 +
 +              /* finally calculate the area */
 +              area = area_poly_v3(mpoly->totloop, vertexcos, no);
 +
 +              BLI_array_fixedstack_free(vertexcos);
 +
 +              return area;
 +      }
 +}
  
  /* basic vertex data functions */
  int minmax_mesh(Mesh *me, float min[3], float max[3])