svn merge -r39765:39781 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / blenkernel / intern / cdderivedmesh.c
index 72ee9b55800ff13cc029f2d7d2982e16036fde3f..ad70e00a33ce1f350a47ace908c4b3ada52d3022 100644 (file)
@@ -1,4 +1,4 @@
-/*
+ /*
 * $Id$
 *
 * ***** BEGIN GPL LICENSE BLOCK *****
 #include <string.h>
 #include "BIF_gl.h"
 
+#include "BKE_cdderivedmesh.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_paint.h"
+#include "BKE_utildefines.h"
+#include "BKE_tessmesh.h"
+
+#include "BLI_editVert.h"
+#include "BLI_scanfill.h"
+#include "BLI_math.h"
 #include "BLI_blenlib.h"
 #include "BLI_edgehash.h"
 #include "BLI_editVert.h"
 #include "BLI_math.h"
 #include "BLI_pbvh.h"
+#include "BLI_array.h"
+#include "BLI_smallhash.h"
 #include "BLI_utildefines.h"
 
 #include "BKE_cdderivedmesh.h"
@@ -77,6 +89,8 @@ typedef struct {
        MVert *mvert;
        MEdge *medge;
        MFace *mface;
+       MLoop *mloop;
+       MPoly *mpoly;
 
        /* Cached */
        struct PBVH *pbvh;
@@ -98,11 +112,16 @@ static int cdDM_getNumEdges(DerivedMesh *dm)
        return dm->numEdgeData;
 }
 
-static int cdDM_getNumFaces(DerivedMesh *dm)
+static int cdDM_getNumTessFaces(DerivedMesh *dm)
 {
        return dm->numFaceData;
 }
 
+static int cdDM_getNumFaces(DerivedMesh *dm)
+{
+       return dm->numPolyData;
+}
+
 static void cdDM_getVert(DerivedMesh *dm, int index, MVert *vert_r)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
@@ -139,6 +158,18 @@ static void cdDM_copyFaceArray(DerivedMesh *dm, MFace *face_r)
        memcpy(face_r, cddm->mface, sizeof(*face_r) * dm->numFaceData);
 }
 
+static void cdDM_copyLoopArray(DerivedMesh *dm, MLoop *loop_r)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+       memcpy(loop_r, cddm->mloop, sizeof(*loop_r) * dm->numLoopData);
+}
+
+static void cdDM_copyPolyArray(DerivedMesh *dm, MPoly *poly_r)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh *)dm;
+       memcpy(poly_r, cddm->mpoly, sizeof(*poly_r) * dm->numPolyData);
+}
+
 static void cdDM_getMinMax(DerivedMesh *dm, float min_r[3], float max_r[3])
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@ -284,8 +315,10 @@ static void cdDM_drawVerts(DerivedMesh *dm)
        else {  /* use OpenGL VBOs or Vertex Arrays instead for better, faster rendering */
                GPU_vertex_setup(dm);
                if( !GPU_buffer_legacy(dm) ) {
-                       if(dm->drawObject->nelements)   glDrawArrays(GL_POINTS,0, dm->drawObject->nelements);
-                       else                                                    glDrawArrays(GL_POINTS,0, dm->drawObject->nlooseverts);
+                       if(dm->drawObject->tot_triangle_point)
+                               glDrawArrays(GL_POINTS,0, dm->drawObject->tot_triangle_point);
+                       else
+                               glDrawArrays(GL_POINTS,0, dm->drawObject->tot_loose_point);
                }
                GPU_buffer_unbind();
        }
@@ -295,7 +328,7 @@ static void cdDM_drawUVEdges(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MFace *mf = cddm->mface;
-       MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
+       MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
        int i;
 
        if(mf) {
@@ -466,7 +499,7 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mvert = cddm->mvert;
        MFace *mface = cddm->mface;
-       float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
+       float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
        int a, glmode = -1, shademodel = -1, matnr = -1, drawCurrentMat = 1;
 
 #define PASSVERT(index) {                                              \
@@ -547,9 +580,10 @@ static void cdDM_drawFacesSolid(DerivedMesh *dm,
                GPU_normal_setup( dm );
                if( !GPU_buffer_legacy(dm) ) {
                        glShadeModel(GL_SMOOTH);
-                       for( a = 0; a < dm->drawObject->nmaterials; a++ ) {
+                       for( a = 0; a < dm->drawObject->totmaterial; a++ ) {
                                if( setMaterial(dm->drawObject->materials[a].mat_nr+1, NULL) )
-                                       glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start, dm->drawObject->materials[a].end-dm->drawObject->materials[a].start);
+                                       glDrawArrays(GL_TRIANGLES, dm->drawObject->materials[a].start,
+                                                    dm->drawObject->materials[a].totpoint);
                        }
                }
                GPU_buffer_unbind( );
@@ -629,13 +663,13 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
                GPU_color_setup(dm);
                if( !GPU_buffer_legacy(dm) ) {
                        glShadeModel(GL_SMOOTH);
-                       glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->nelements);
+                       glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->tot_triangle_point);
 
                        if( useTwoSided ) {
                                GPU_color4_upload(dm,cp2);
                                GPU_color_setup(dm);
                                glCullFace(GL_FRONT);
-                               glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->nelements);
+                               glDrawArrays(GL_TRIANGLES, 0, dm->drawObject->tot_triangle_point);
                                glCullFace(GL_BACK);
                        }
                }
@@ -647,21 +681,21 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
 }
 
 static void cdDM_drawFacesTex_common(DerivedMesh *dm,
-                          int (*drawParams)(MTFace *tface, MCol *mcol, int matnr),
-                          int (*drawParamsMapped)(void *userData, int index),
-                          void *userData) 
+               int (*drawParams)(MTFace *tface, int has_vcol, int matnr),
+               int (*drawParamsMapped)(void *userData, int index),
+               void *userData) 
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mv = cddm->mvert;
-       MFace *mf = DM_get_face_data_layer(dm, CD_MFACE);
-       MCol *realcol = dm->getFaceDataArray(dm, CD_TEXTURE_MCOL);
-       float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
-       MTFace *tf = DM_get_face_data_layer(dm, CD_MTFACE);
-       int i, j, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+       MFace *mf = DM_get_tessface_data_layer(dm, CD_MFACE);
+       MCol *realcol = dm->getTessFaceDataArray(dm, CD_TEXTURE_MCOL);
+       float *nors= dm->getTessFaceDataArray(dm, CD_NORMAL);
+       MTFace *tf = DM_get_tessface_data_layer(dm, CD_MTFACE);
+       int i, j, orig, *index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
        int startFace = 0, lastFlag = 0xdeadbeef;
-       MCol *mcol = dm->getFaceDataArray(dm, CD_WEIGHT_MCOL);
+       MCol *mcol = dm->getTessFaceDataArray(dm, CD_WEIGHT_MCOL);
        if(!mcol)
-               mcol = dm->getFaceDataArray(dm, CD_MCOL);
+               mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
 
        cdDM_update_normals_from_pbvh(dm);
 
@@ -673,7 +707,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                        unsigned char *cp = NULL;
 
                        if(drawParams) {
-                               flag = drawParams(tf? &tf[i]: NULL, mcol? &mcol[i*4]: NULL, mf->mat_nr);
+                               flag = drawParams(tf? &tf[i]: NULL, mcol!=NULL, mf->mat_nr);
                        }
                        else {
                                if(index) {
@@ -753,8 +787,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                        }
                        
                        if( col != 0 ) {*/
-                               unsigned char *colors = MEM_mallocN(dm->getNumFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
-                               for( i=0; i < dm->getNumFaces(dm); i++ ) {
+                               unsigned char *colors = MEM_mallocN(dm->getNumTessFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
+                               for( i=0; i < dm->getNumTessFaces(dm); i++ ) {
                                        for( j=0; j < 4; j++ ) {
                                                colors[i*12+j*3] = col[i*4+j].r;
                                                colors[i*12+j*3+1] = col[i*4+j].g;
@@ -787,12 +821,12 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                        
                        glShadeModel( GL_SMOOTH );
                        lastFlag = 0;
-                       for(i = 0; i < dm->drawObject->nelements/3; i++) {
-                               int actualFace = dm->drawObject->faceRemap[i];
+                       for(i = 0; i < dm->drawObject->tot_triangle_point/3; i++) {
+                               int actualFace = dm->drawObject->triangle_to_mface[i];
                                int flag = 1;
 
                                if(drawParams) {
-                                       flag = drawParams(tf? &tf[actualFace]: NULL, mcol? &mcol[actualFace*4]: NULL, mf[actualFace].mat_nr);
+                                       flag = drawParams(tf? &tf[actualFace]: NULL, mcol!=NULL, mf[actualFace].mat_nr);
                                }
                                else {
                                        if(index) {
@@ -819,13 +853,13 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                        startFace = i;
                                }
                        }
-                       if( startFace < dm->drawObject->nelements/3 ) {
+                       if( startFace < dm->drawObject->tot_triangle_point/3 ) {
                                if( lastFlag != 0 ) { /* if the flag is 0 it means the face is hidden or invisible */
                                        if (lastFlag==1 && col)
                                                GPU_color_switch(1);
                                        else
                                                GPU_color_switch(0);
-                                       glDrawArrays(GL_TRIANGLES,startFace*3,dm->drawObject->nelements-startFace*3);
+                                       glDrawArrays(GL_TRIANGLES, startFace*3, dm->drawObject->tot_triangle_point - startFace*3);
                                }
                        }
                }
@@ -835,25 +869,26 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
        }
 }
 
-static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, MCol *mcol, int matnr))
+static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tface, int has_vcol, int matnr))
 {
        cdDM_drawFacesTex_common(dm, setDrawOptions, NULL, NULL);
 }
 
-static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs))
+static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index, int *drawSmooth_r), void *userData, int useColors, int (*setMaterial)(int, void *attribs),
+                       int (*compareDrawOptions)(void *userData, int cur_index, int next_index))
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mv = cddm->mvert;
        MFace *mf = cddm->mface;
        MCol *mc;
-       float *nors= dm->getFaceDataArray(dm, CD_NORMAL);
-       int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+       float *nors= DM_get_tessface_data_layer(dm, CD_NORMAL);
+       int i, orig, *index = DM_get_tessface_data_layer(dm, CD_ORIGINDEX);
 
-       mc = DM_get_face_data_layer(dm, CD_ID_MCOL);
+       mc = DM_get_tessface_data_layer(dm, CD_ID_MCOL);
        if(!mc)
-               mc = DM_get_face_data_layer(dm, CD_WEIGHT_MCOL);
+               mc = DM_get_tessface_data_layer(dm, CD_WEIGHT_MCOL);
        if(!mc)
-               mc = DM_get_face_data_layer(dm, CD_MCOL);
+               mc = DM_get_tessface_data_layer(dm, CD_MCOL);
 
        cdDM_update_normals_from_pbvh(dm);
 
@@ -923,7 +958,9 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                                }
 
                                glEnd();
-                       }
+                       } /*else {
+                               printf("eek in cddm draw mapped faces!\n");
+                       }*/
                        
                        if (nors) nors += 3;
                }
@@ -935,7 +972,7 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                if( useColors && mc )
                        GPU_color_setup(dm);
                if( !GPU_buffer_legacy(dm) ) {
-                       int tottri = dm->drawObject->nelements/3;
+                       int tottri = dm->drawObject->tot_triangle_point/3;
                        glShadeModel(GL_SMOOTH);
                        
                        if(tottri == 0) {
@@ -947,17 +984,18 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                        }
                        else {
                                /* we need to check if the next material changes */
-                               int next_actualFace= dm->drawObject->faceRemap[0];
+                               int next_actualFace= dm->drawObject->triangle_to_mface[0];
                                
                                for( i = 0; i < tottri; i++ ) {
-                                       //int actualFace = dm->drawObject->faceRemap[i];
+                                       //int actualFace = dm->drawObject->triangle_to_mface[i];
                                        int actualFace = next_actualFace;
                                        MFace *mface= mf + actualFace;
                                        int drawSmooth= (mface->flag & ME_SMOOTH);
                                        int draw = 1;
+                                       int flush = 0;
 
                                        if(i != tottri-1)
-                                               next_actualFace= dm->drawObject->faceRemap[i+1];
+                                               next_actualFace= dm->drawObject->triangle_to_mface[i+1];
 
                                        orig= (index==NULL) ? actualFace : index[actualFace];
 
@@ -969,11 +1007,28 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
                                        /* Goal is to draw as long of a contiguous triangle
                                           array as possible, so draw when we hit either an
                                           invisible triangle or at the end of the array */
-                                       if(!draw || i == tottri - 1 || mf[actualFace].mat_nr != mf[next_actualFace].mat_nr) {
-                                               if(prevstart != i)
-                                                       /* Add one to the length (via `draw')
-                                                          if we're drawing at the end of the array */
-                                                       glDrawArrays(GL_TRIANGLES,prevstart*3, (i-prevstart+draw)*3);
+
+                                       /* flush buffer if current triangle isn't drawable or it's last triangle... */
+                                       flush= !draw || i == tottri - 1;
+
+                                       /* ... or when material setting is dissferent  */
+                                       flush|= mf[actualFace].mat_nr != mf[next_actualFace].mat_nr;
+
+                                       if(!flush && compareDrawOptions) {
+                                               int next_orig= (index==NULL) ? next_actualFace : index[next_actualFace];
+
+                                               /* also compare draw options and flush buffer if they're different
+                                                  need for face selection highlight in edit mode */
+                                               flush|= compareDrawOptions(userData, orig, next_orig) == 0;
+                                       }
+
+                                       if(flush) {
+                                               int first= prevstart*3;
+                                               int count= (i-prevstart+(draw ? 1 : 0))*3; /* Add one to the length if we're drawing at the end of the array */
+
+                                               if(count)
+                                                       glDrawArrays(GL_TRIANGLES, first, count);
+
                                                prevstart = i + 1;
                                        }
                                }
@@ -990,6 +1045,52 @@ static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void
        cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 }
 
+
+static void cddm_draw_attrib_vertex(DMVertexAttribs *attribs, MVert *mvert, int a, int index, int vert, int smoothnormal)
+{
+       int b;
+
+       /* orco texture coordinates */
+       if(attribs->totorco) {
+               if(attribs->orco.glTexco)
+                       glTexCoord3fv(attribs->orco.array[index]);
+               else
+                       glVertexAttrib3fvARB(attribs->orco.glIndex, attribs->orco.array[index]);
+       }
+
+       /* uv texture coordinates */
+       for(b = 0; b < attribs->tottface; b++) {
+               MTFace *tf = &attribs->tface[b].array[a];
+
+               if(attribs->tface[b].glTexco)
+                       glTexCoord2fv(tf->uv[vert]);
+               else
+                       glVertexAttrib2fvARB(attribs->tface[b].glIndex, tf->uv[vert]);
+       }
+
+       /* vertex colors */
+       for(b = 0; b < attribs->totmcol; b++) {
+               MCol *cp = &attribs->mcol[b].array[a*4 + vert];
+               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);
+       }
+
+       /* tangent for normal mapping */
+       if(attribs->tottang) {
+               float *tang = attribs->tang.array[a*4 + vert];
+               glVertexAttrib4fvARB(attribs->tang.glIndex, tang);
+       }
+
+       /* vertex normal */
+       if(smoothnormal)
+               glNormal3sv(mvert[index].no);
+
+       /* vertex coordinate */
+       glVertex3fv(mvert[index].co);
+}
+
+
 static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *attribs), int (*setDrawOptions)(void *userData, int index), void *userData)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@ -997,11 +1098,11 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
        DMVertexAttribs attribs;
        MVert *mvert = cddm->mvert;
        MFace *mface = cddm->mface;
-       MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE);
-       float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
+       MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
+       float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
        int a, b, dodraw, matnr, new_matnr;
        int transp, new_transp, orig_transp;
-       int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+       int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
 
        cdDM_update_normals_from_pbvh(dm);
 
@@ -1080,37 +1181,14 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                }
                        }
 
-#define PASSVERT(index, vert) {                                                                                                        \
-               if(attribs.totorco)                                                                                                                     \
-                       glVertexAttrib3fvARB(attribs.orco.glIndex, attribs.orco.array[index]);  \
-               for(b = 0; b < attribs.tottface; b++) {                                                                         \
-                       MTFace *tf = &attribs.tface[b].array[a];                                                                \
-                       glVertexAttrib2fvARB(attribs.tface[b].glIndex, tf->uv[vert]);                   \
-               }                                                                                                                                                       \
-               for(b = 0; b < attribs.totmcol; b++) {                                                                          \
-                       MCol *cp = &attribs.mcol[b].array[a*4 + vert];                                                  \
-                       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[a*4 + vert];                                                   \
-                       glVertexAttrib4fvARB(attribs.tang.glIndex, tang);                                               \
-               }                                                                                                                                                       \
-               if(smoothnormal)                                                                                                                        \
-                       glNormal3sv(mvert[index].no);                                                                                   \
-               glVertex3fv(mvert[index].co);                                                                                           \
-       }
-
-                       PASSVERT(mface->v1, 0);
-                       PASSVERT(mface->v2, 1);
-                       PASSVERT(mface->v3, 2);
+                       cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v1, 0, smoothnormal);
+                       cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v2, 1, smoothnormal);
+                       cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v3, 2, smoothnormal);
                        if(mface->v4)
-                               PASSVERT(mface->v4, 3)
+                               cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v4, 3, smoothnormal);
                        else
-                               PASSVERT(mface->v3, 2)
+                               cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v3, 2, smoothnormal);
 
-#undef PASSVERT
                }
                glEnd();
        }
@@ -1129,9 +1207,9 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                GPU_normal_setup(dm);
 
                if( !GPU_buffer_legacy(dm) ) {
-                       for( i = 0; i < dm->drawObject->nelements/3; i++ ) {
+                       for( i = 0; i < dm->drawObject->tot_triangle_point/3; i++ ) {
 
-                               a = dm->drawObject->faceRemap[i];
+                               a = dm->drawObject->triangle_to_mface[i];
 
                                mface = mf + a;
                                new_matnr = mface->mat_nr + 1;
@@ -1153,7 +1231,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
 
                                                        if( numdata != 0 ) {
 
-                                                               GPU_buffer_free(buffer, NULL);
+                                                               GPU_buffer_free(buffer);
 
                                                                buffer = NULL;
                                                        }
@@ -1193,7 +1271,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                }
                                                if( numdata != 0 ) {
                                                        elementsize = GPU_attrib_element_size( datatypes, numdata );
-                                                       buffer = GPU_buffer_alloc( elementsize*dm->drawObject->nelements, NULL );
+                                                       buffer = GPU_buffer_alloc( elementsize*dm->drawObject->tot_triangle_point);
                                                        if( buffer == NULL ) {
                                                                GPU_buffer_unbind();
                                                                dm->drawObject->legacy = 1;
@@ -1202,7 +1280,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                        varray = GPU_buffer_lock_stream(buffer);
                                                        if( varray == NULL ) {
                                                                GPU_buffer_unbind();
-                                                               GPU_buffer_free(buffer, NULL);
+                                                               GPU_buffer_free(buffer);
                                                                dm->drawObject->legacy = 1;
                                                                return;
                                                        }
@@ -1284,6 +1362,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang);
                                                offset += sizeof(float)*4;
                                        }
+                                       (void)offset;
                                }
                                curface++;
                                if(mface->v4) {
@@ -1324,6 +1403,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                        QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang);
                                                        offset += sizeof(float)*4;
                                                }
+                                               (void)offset;
                                        }
                                        curface++;
                                        i++;
@@ -1341,7 +1421,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                        }
                        GPU_buffer_unbind();
                }
-               GPU_buffer_free( buffer, NULL );
+               GPU_buffer_free(buffer);
        }
 
        glShadeModel(GL_FLAT);
@@ -1426,35 +1506,72 @@ static void cdDM_foreachMappedFaceCenter(
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
        MVert *mv = cddm->mvert;
-       MFace *mf = cddm->mface;
-       int i, orig, *index = DM_get_face_data_layer(dm, CD_ORIGINDEX);
+       MPoly *mf = cddm->mpoly;
+       MLoop *ml = cddm->mloop;
+       int i, j, orig, *index;
 
-       for(i = 0; i < dm->numFaceData; i++, mf++) {
+       index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+       mf = cddm->mpoly;
+       for(i = 0; i < dm->numPolyData; i++, mf++) {
                float cent[3];
                float no[3];
 
                if (index) {
                        orig = *index++;
                        if(orig == ORIGINDEX_NONE) continue;
-               }
-               else
+               } else
                        orig = i;
+               
+               ml = &cddm->mloop[mf->loopstart];
+               cent[0] = cent[1] = cent[2] = 0.0f;
+               for (j=0; j<mf->totloop; j++, ml++) {
+                       add_v3_v3v3(cent, cent, mv[ml->v].co);
+               }
+               mul_v3_fl(cent, 1.0f / (float)j);
 
-               VECCOPY(cent, mv[mf->v1].co);
-               add_v3_v3(cent, mv[mf->v2].co);
-               add_v3_v3(cent, mv[mf->v3].co);
-
-               if (mf->v4) {
-                       normal_quad_v3( no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
-                       add_v3_v3(cent, mv[mf->v4].co);
-                       mul_v3_fl(cent, 0.25f);
+               ml = &cddm->mloop[mf->loopstart];
+               if (j > 3) {
+                       normal_quad_v3(no, mv[ml->v].co, mv[(ml+1)->v].co,
+                                      mv[(ml+2)->v].co, mv[(ml+3)->v].co);
                } else {
-                       normal_tri_v3( no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
-                       mul_v3_fl(cent, 0.33333333333f);
+                       normal_tri_v3(no, mv[ml->v].co, mv[(ml+1)->v].co,
+                                      mv[(ml+2)->v].co);
                }
 
                func(userData, orig, cent, no);
        }
+
+}
+
+static void cdDM_recalcTesselation(DerivedMesh *dm)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+       dm->numFaceData = mesh_recalcTesselation(&dm->faceData, &dm->loopData, 
+               &dm->polyData, cddm->mvert, dm->numFaceData, dm->numLoopData, 
+               dm->numPolyData, 1, 0);
+       
+       cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+}
+
+/*ignores original poly origindex layer*/
+static void cdDM_recalcTesselation2(DerivedMesh *dm)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+       dm->numFaceData = mesh_recalcTesselation(&dm->faceData, &dm->loopData, 
+               &dm->polyData, cddm->mvert, dm->numFaceData, dm->numLoopData, 
+               dm->numPolyData, 0, 0);
+       
+       cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+}
+
+void CDDM_recalc_tesselation(DerivedMesh *dm, int orig_use_polyorig)
+{
+       if (orig_use_polyorig)
+               cdDM_recalcTesselation(dm);
+       else
+               cdDM_recalcTesselation2(dm);
 }
 
 static void cdDM_free_internal(CDDerivedMesh *cddm)
@@ -1473,6 +1590,11 @@ static void cdDM_release(DerivedMesh *dm)
        }
 }
 
+int CDDM_Check(DerivedMesh *dm)
+{
+       return dm && dm->getMinMax == cdDM_getMinMax;
+}
+
 /**************** CDDM interface functions ****************/
 static CDDerivedMesh *cdDM_create(const char *desc)
 {
@@ -1485,21 +1607,27 @@ static CDDerivedMesh *cdDM_create(const char *desc)
        dm->getMinMax = cdDM_getMinMax;
 
        dm->getNumVerts = cdDM_getNumVerts;
-       dm->getNumFaces = cdDM_getNumFaces;
        dm->getNumEdges = cdDM_getNumEdges;
+       dm->getNumTessFaces = cdDM_getNumTessFaces;
+       dm->getNumFaces = cdDM_getNumFaces;
 
        dm->getVert = cdDM_getVert;
        dm->getEdge = cdDM_getEdge;
-       dm->getFace = cdDM_getFace;
+       dm->getTessFace = cdDM_getFace;
        dm->copyVertArray = cdDM_copyVertArray;
        dm->copyEdgeArray = cdDM_copyEdgeArray;
-       dm->copyFaceArray = cdDM_copyFaceArray;
+       dm->copyTessFaceArray = cdDM_copyFaceArray;
+       dm->copyLoopArray = cdDM_copyLoopArray;
+       dm->copyPolyArray = cdDM_copyPolyArray;
        dm->getVertData = DM_get_vert_data;
        dm->getEdgeData = DM_get_edge_data;
-       dm->getFaceData = DM_get_face_data;
+       dm->getTessFaceData = DM_get_face_data;
        dm->getVertDataArray = DM_get_vert_data_layer;
        dm->getEdgeDataArray = DM_get_edge_data_layer;
-       dm->getFaceDataArray = DM_get_face_data_layer;
+       dm->getTessFaceDataArray = DM_get_tessface_data_layer;
+       
+       //doesn't work yet for all cases
+       //dm->recalcTesselation = cdDM_recalcTesselation;
 
        dm->getVertCos = cdDM_getVertCos;
        dm->getVertCo = cdDM_getVertCo;
@@ -1532,24 +1660,29 @@ static CDDerivedMesh *cdDM_create(const char *desc)
        return cddm;
 }
 
-DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
+DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces, int numLoops, int numPolys)
 {
        CDDerivedMesh *cddm = cdDM_create("CDDM_new dm");
        DerivedMesh *dm = &cddm->dm;
 
-       DM_init(dm, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
+       DM_init(dm, DM_TYPE_CDDM, numVerts, numEdges, numFaces, numLoops, numPolys);
 
        CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, numFaces);
+       CustomData_add_layer(&dm->polyData, CD_ORIGINDEX, CD_CALLOC, NULL, numPolys);
 
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+       CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
+       CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
 
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+       cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+       cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
 
        return dm;
 }
@@ -1563,7 +1696,8 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *UNUSED(ob))
 
        /* this does a referenced copy, with an exception for fluidsim */
 
-       DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, mesh->totface);
+       DM_init(dm, DM_TYPE_CDDM, mesh->totvert, mesh->totedge, mesh->totface,
+                   mesh->totloop, mesh->totpoly);
 
        dm->deformedOnly = 1;
 
@@ -1573,21 +1707,30 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *UNUSED(ob))
                                         mesh->totvert);
        CustomData_merge(&mesh->edata, &dm->edgeData, mask, alloctype,
                                         mesh->totedge);
-       CustomData_merge(&mesh->fdata, &dm->faceData, mask, alloctype,
+       CustomData_merge(&mesh->fdata, &dm->faceData, mask|CD_MASK_ORIGINDEX, alloctype,
                                         mesh->totface);
+       CustomData_merge(&mesh->ldata, &dm->loopData, mask, alloctype,
+                        mesh->totloop);
+       CustomData_merge(&mesh->pdata, &dm->polyData, mask, alloctype,
+                        mesh->totpoly);
 
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+       cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+       cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
 
+       if (!CustomData_has_layer(&cddm->dm.faceData, CD_ORIGINDEX))
+               CustomData_add_layer(&dm->faceData, CD_ORIGINDEX, CD_CALLOC, NULL, mesh->totface);
+
        return dm;
 }
 
-DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
+static DerivedMesh *disabled__CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
 {
        DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
-                                                          BLI_countlist(&em->edges),
-                                                          BLI_countlist(&em->faces));
+                                  BLI_countlist(&em->edges),
+                                  BLI_countlist(&em->faces), 0, 0);
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
        EditVert *eve;
        EditEdge *eed;
@@ -1605,6 +1748,8 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
                                         CD_CALLOC, dm->numEdgeData); */
        CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
                                         CD_CALLOC, dm->numFaceData);
+       CustomData_merge(&em->fdata, &dm->faceData, CD_MASK_DERIVEDMESH,
+                        CD_CALLOC, dm->numFaceData);
 
        /* set eve->hash to vert index */
        for(i = 0, eve = em->verts.first; eve; eve = eve->next, ++i)
@@ -1658,7 +1803,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
                /* CustomData_from_em_block(&em->edata, &dm->edgeData, eed->data, i); */
        }
 
-       index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+       index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
        for(i = 0, efa = em->faces.first; i < dm->numFaceData;
                i++, efa = efa->next, index++) {
                MFace *mf = &mface[i];
@@ -1691,15 +1836,17 @@ DerivedMesh *CDDM_from_curve_customDB(Object *ob, ListBase *dispbase)
        MVert *allvert;
        MEdge *alledge;
        MFace *allface;
-       int totvert, totedge, totface;
+       MLoop *allloop;
+       MPoly *allpoly;
+       int totvert, totedge, totface, totloop, totpoly;
 
        if (nurbs_to_mdata_customdb(ob, dispbase, &allvert, &totvert, &alledge,
-               &totedge, &allface, &totface) != 0) {
+               &totedge, &allface, &allloop, &allpoly, &totface, &totloop, &totpoly) != 0) {
                /* Error initializing mdata. This often happens when curve is empty */
-               return CDDM_new(0, 0, 0);
+               return CDDM_new(0, 0, 0, 0, 0);
        }
 
-       dm = CDDM_new(totvert, totedge, totface);
+       dm = CDDM_new(totvert, totedge, totface, totloop, totpoly);
        dm->deformedOnly = 1;
 
        cddm = (CDDerivedMesh*)dm;
@@ -1707,29 +1854,246 @@ DerivedMesh *CDDM_from_curve_customDB(Object *ob, ListBase *dispbase)
        memcpy(cddm->mvert, allvert, totvert*sizeof(MVert));
        memcpy(cddm->medge, alledge, totedge*sizeof(MEdge));
        memcpy(cddm->mface, allface, totface*sizeof(MFace));
+       memcpy(cddm->mloop, allloop, totloop*sizeof(MLoop));
+       memcpy(cddm->mpoly, allpoly, totpoly*sizeof(MPoly));
 
        MEM_freeN(allvert);
        MEM_freeN(alledge);
        MEM_freeN(allface);
+       MEM_freeN(allloop);
+       MEM_freeN(allpoly);
+
+       return dm;
+}
+
+static void loops_to_customdata_corners(BMesh *bm, CustomData *facedata,
+                                         int cdindex, BMLoop *l3[3],
+                                         int numCol, int numTex)
+{
+       BMLoop *l;
+       BMFace *f = l3[0]->f;
+       MTFace *texface;
+       MTexPoly *texpoly;
+       MCol *mcol;
+       MLoopCol *mloopcol;
+       MLoopUV *mloopuv;
+       int i, j, hasWCol = CustomData_has_layer(&bm->ldata, CD_WEIGHT_MLOOPCOL);
+
+       for(i=0; i < numTex; i++){
+               texface = CustomData_get_n(facedata, CD_MTFACE, cdindex, i);
+               texpoly = CustomData_bmesh_get_n(&bm->pdata, f->head.data, CD_MTEXPOLY, i);
+               
+               texface->tpage = texpoly->tpage;
+               texface->flag = texpoly->flag;
+               texface->transp = texpoly->transp;
+               texface->mode = texpoly->mode;
+               texface->tile = texpoly->tile;
+               texface->unwrap = texpoly->unwrap;
+       
+               for (j=0; j<3; j++) {
+                       l = l3[j];
+                       mloopuv = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPUV, i);
+                       texface->uv[j][0] = mloopuv->uv[0];
+                       texface->uv[j][1] = mloopuv->uv[1];
+               }
+       }
+
+       for(i=0; i < numCol; i++){
+               mcol = CustomData_get_n(facedata, CD_MCOL, cdindex, i);
+               
+               for (j=0; j<3; j++) {
+                       l = l3[j];
+                       mloopcol = CustomData_bmesh_get_n(&bm->ldata, l->head.data, CD_MLOOPCOL, i);
+                       mcol[j].r = mloopcol->r;
+                       mcol[j].g = mloopcol->g;
+                       mcol[j].b = mloopcol->b;
+                       mcol[j].a = mloopcol->a;
+               }
+       }
+
+       if (hasWCol) {
+               mcol = CustomData_get(facedata, cdindex, CD_WEIGHT_MCOL);
+
+               for (j=0; j<3; j++) {
+                       l = l3[j];
+                       mloopcol = CustomData_bmesh_get(&bm->ldata, l->head.data, CD_WEIGHT_MLOOPCOL);
+                       mcol[j].r = mloopcol->r;
+                       mcol[j].g = mloopcol->g;
+                       mcol[j].b = mloopcol->b;
+                       mcol[j].a = mloopcol->a;
+               }
+       }
+}
+
+DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *UNUSED(me), int use_mdisps)
+{
+       DerivedMesh *dm = CDDM_new(em->bm->totvert, em->bm->totedge, 
+                              em->tottri, em->bm->totloop, em->bm->totface);
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+       BMesh *bm = em->bm;
+       BMIter iter, liter;
+       BMVert *eve;
+       BMEdge *eed;
+       BMFace *efa;
+       MVert *mvert = cddm->mvert;
+       MEdge *medge = cddm->medge;
+       MFace *mface = cddm->mface;
+       MLoop *mloop = cddm->mloop;
+       MPoly *mpoly = cddm->mpoly;
+       int numCol = CustomData_number_of_layers(&em->bm->ldata, CD_MLOOPCOL);
+       int numTex = CustomData_number_of_layers(&em->bm->pdata, CD_MTEXPOLY);
+       int i, j, *index, add_orig;
+       int has_crease, has_edge_bweight, has_vert_bweight;
+       int flag;
+       
+       has_edge_bweight = CustomData_has_layer(&em->bm->edata, CD_BWEIGHT);
+       has_vert_bweight = CustomData_has_layer(&em->bm->vdata, CD_BWEIGHT);
+       has_crease = CustomData_has_layer(&em->bm->edata, CD_CREASE);
+       
+       dm->deformedOnly = 1;
+       
+       /*don't add origindex layer if one already exists*/
+       add_orig = !CustomData_has_layer(&em->bm->pdata, CD_ORIGINDEX);
+
+       flag = use_mdisps ? CD_MASK_DERIVEDMESH|CD_MASK_MDISPS : CD_MASK_DERIVEDMESH;
+       
+       /*don't process shapekeys, we only feed them through the modifier stack as needed,
+      e.g. for applying modifiers or the like*/
+       flag &= ~CD_SHAPEKEY;
+       CustomData_merge(&em->bm->vdata, &dm->vertData, flag,
+                        CD_CALLOC, dm->numVertData);
+       CustomData_merge(&em->bm->edata, &dm->edgeData, flag,
+                        CD_CALLOC, dm->numEdgeData);
+       CustomData_merge(&em->bm->ldata, &dm->loopData, flag,
+                        CD_CALLOC, dm->numLoopData);
+       CustomData_merge(&em->bm->pdata, &dm->polyData, flag,
+                        CD_CALLOC, dm->numPolyData);
+       
+       /*add tesselation mface layers*/
+       CustomData_from_bmeshpoly(&dm->faceData, &dm->polyData, &dm->loopData, em->tottri);
+
+       /* set vert index */
+       eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+       for (i=0; eve; eve=BMIter_Step(&iter), i++)
+               BM_SetIndex(eve, i);
+
+       index = dm->getVertDataArray(dm, CD_ORIGINDEX);
+
+       eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
+       for (i=0; eve; eve=BMIter_Step(&iter), i++, index++) {
+               MVert *mv = &mvert[i];
+
+               VECCOPY(mv->co, eve->co);
+
+               BM_SetIndex(eve, i);
+
+               mv->no[0] = eve->no[0] * 32767.0;
+               mv->no[1] = eve->no[1] * 32767.0;
+               mv->no[2] = eve->no[2] * 32767.0;
+
+               mv->flag = BMFlags_To_MEFlags(eve);
+
+               if (has_vert_bweight)
+                       mv->bweight = (unsigned char)(BM_GetCDf(&bm->vdata, eve, CD_BWEIGHT)*255.0f);
+
+               if (add_orig) *index = i;
+
+               CustomData_from_bmesh_block(&bm->vdata, &dm->vertData, eve->head.data, i);
+       }
+
+       index = dm->getEdgeDataArray(dm, CD_ORIGINDEX);
+       eed = BMIter_New(&iter, bm, BM_EDGES_OF_MESH, NULL);
+       for (i=0; eed; eed=BMIter_Step(&iter), i++, index++) {
+               MEdge *med = &medge[i];
+
+               BM_SetIndex(eed, i);
+
+               med->v1 = BM_GetIndex(eed->v1);
+               med->v2 = BM_GetIndex(eed->v2);
+               med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+
+               if (has_crease)
+                       med->crease = (unsigned char)(BM_GetCDf(&bm->edata, eed, CD_CREASE)*255.0f);
+               if (has_edge_bweight)
+                       med->bweight = (unsigned char)(BM_GetCDf(&bm->edata, eed, CD_BWEIGHT)*255.0f);
+               
+               med->flag = BMFlags_To_MEFlags(eed);
+
+               CustomData_from_bmesh_block(&bm->edata, &dm->edgeData, eed->head.data, i);
+               if (add_orig) *index = i;
+       }
+
+       efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+       for (i=0; efa; i++, efa=BMIter_Step(&iter)) {
+               BM_SetIndex(efa, i);
+       }
+
+       index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
+       for(i = 0; i < dm->numFaceData; i++, index++) {
+               MFace *mf = &mface[i];
+               BMLoop **l = em->looptris[i];
+               efa = l[0]->f;
+
+               mf->v1 = BM_GetIndex(l[0]->v);
+               mf->v2 = BM_GetIndex(l[1]->v);
+               mf->v3 = BM_GetIndex(l[2]->v);
+               mf->v4 = 0;
+               mf->mat_nr = efa->mat_nr;
+               mf->flag = BMFlags_To_MEFlags(efa);
+               
+               *index = add_orig ? BM_GetIndex(efa) : *(int*)CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_ORIGINDEX);
+
+               loops_to_customdata_corners(bm, &dm->faceData, i, l, numCol, numTex);
+               test_index_face(mf, &dm->faceData, i, 3);
+       }
+       
+       index = CustomData_get_layer(&dm->polyData, CD_ORIGINDEX);
+       j = 0;
+       efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
+       for (i=0; efa; i++, efa=BMIter_Step(&iter), index++) {
+               BMLoop *l;
+               MPoly *mp = &mpoly[i];
+
+               mp->totloop = efa->len;
+               mp->flag = BMFlags_To_MEFlags(efa);
+               mp->loopstart = j;
+               mp->mat_nr = efa->mat_nr;
+               
+               BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
+                       mloop->v = BM_GetIndex(l->v);
+                       mloop->e = BM_GetIndex(l->e);
+                       CustomData_from_bmesh_block(&bm->ldata, &dm->loopData, l->head.data, j);
+
+                       j++;
+                       mloop++;
+               }
+
+               CustomData_from_bmesh_block(&bm->pdata, &dm->polyData, efa->head.data, i);
+
+               if (add_orig) *index = i;
+       }
 
        return dm;
 }
 
-DerivedMesh *CDDM_copy(DerivedMesh *source)
+DerivedMesh *CDDM_copy(DerivedMesh *source, int faces_from_tessfaces)
 {
        CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
        DerivedMesh *dm = &cddm->dm;
        int numVerts = source->numVertData;
        int numEdges = source->numEdgeData;
        int numFaces = source->numFaceData;
+       int numLoops = source->numLoopData;
+       int numPolys = source->numPolyData;
 
        /* ensure these are created if they are made on demand */
        source->getVertDataArray(source, CD_ORIGINDEX);
        source->getEdgeDataArray(source, CD_ORIGINDEX);
-       source->getFaceDataArray(source, CD_ORIGINDEX);
+       source->getTessFaceDataArray(source, CD_ORIGINDEX);
 
        /* this initializes dm, and copies all non mvert/medge/mface layers */
-       DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
+       DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces,
+               numLoops, numPolys);
        dm->deformedOnly = source->deformedOnly;
 
        CustomData_copy_data(&source->vertData, &dm->vertData, 0, 0, numVerts);
@@ -1739,19 +2103,30 @@ DerivedMesh *CDDM_copy(DerivedMesh *source)
        /* now add mvert/medge/mface layers */
        cddm->mvert = source->dupVertArray(source);
        cddm->medge = source->dupEdgeArray(source);
-       cddm->mface = source->dupFaceArray(source);
+       cddm->mface = source->dupTessFaceArray(source);
 
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, cddm->mvert, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, cddm->medge, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, cddm->mface, numFaces);
+       
+       if (!faces_from_tessfaces)
+               DM_DupPolys(source, dm);
+       else
+               CDDM_tessfaces_to_faces(dm);
 
+       cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+       cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
+       
+       cdDM_recalcTesselation((DerivedMesh *)cddm);
+       
        return dm;
 }
 
 /* note, the CD_ORIGINDEX layers are all 0, so if there is a direct
  * relationship betwen mesh data this needs to be set by the caller. */
 DerivedMesh *CDDM_from_template(DerivedMesh *source,
-                                                               int numVerts, int numEdges, int numFaces)
+                                int numVerts, int numEdges, int numFaces,
+                                                               int numLoops, int numPolys)
 {
        CDDerivedMesh *cddm = cdDM_create("CDDM_from_template dest");
        DerivedMesh *dm = &cddm->dm;
@@ -1759,15 +2134,17 @@ DerivedMesh *CDDM_from_template(DerivedMesh *source,
        /* ensure these are created if they are made on demand */
        source->getVertDataArray(source, CD_ORIGINDEX);
        source->getEdgeDataArray(source, CD_ORIGINDEX);
-       source->getFaceDataArray(source, CD_ORIGINDEX);
+       source->getTessFaceDataArray(source, CD_ORIGINDEX);
 
        /* this does a copy of all non mvert/medge/mface layers */
-       DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces);
+       DM_from_template(dm, source, DM_TYPE_CDDM, numVerts, numEdges, numFaces, numLoops, numPolys);
 
        /* now add mvert/medge/mface layers */
        CustomData_add_layer(&dm->vertData, CD_MVERT, CD_CALLOC, NULL, numVerts);
        CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
        CustomData_add_layer(&dm->faceData, CD_MFACE, CD_CALLOC, NULL, numFaces);
+       CustomData_add_layer(&dm->loopData, CD_MLOOP, CD_CALLOC, NULL, numLoops);
+       CustomData_add_layer(&dm->polyData, CD_MPOLY, CD_CALLOC, NULL, numPolys);
 
        if(!CustomData_get_layer(&dm->vertData, CD_ORIGINDEX))
                CustomData_add_layer(&dm->vertData, CD_ORIGINDEX, CD_CALLOC, NULL, numVerts);
@@ -1779,6 +2156,8 @@ DerivedMesh *CDDM_from_template(DerivedMesh *source,
        cddm->mvert = CustomData_get_layer(&dm->vertData, CD_MVERT);
        cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
        cddm->mface = CustomData_get_layer(&dm->faceData, CD_MFACE);
+       cddm->mloop = CustomData_get_layer(&dm->loopData, CD_MLOOP);
+       cddm->mpoly = CustomData_get_layer(&dm->polyData, CD_MPOLY);
 
        return dm;
 }
@@ -1814,22 +2193,228 @@ void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3])
 void CDDM_calc_normals(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
-       float (*face_nors)[3];
-
+       float (*face_nors)[3] = NULL;
+       
        if(dm->numVertData == 0) return;
 
        /* we don't want to overwrite any referenced layers */
        cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
+       
+       /*set tesselation origindex values to map to poly indices, rather then poly
+         poly origindex values*/
+       cdDM_recalcTesselation2(dm);
+       
+       face_nors = MEM_mallocN(sizeof(float)*3*dm->numFaceData, "face_nors");
+       
+       /* calculate face normals */
+       mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_loops(dm), CDDM_get_polys(dm), 
+                                         dm->numLoopData, dm->numPolyData, NULL, cddm->mface, dm->numFaceData, 
+                                         CustomData_get_layer(&dm->faceData, CD_ORIGINDEX), face_nors);
+       
+       /*restore tesselation origindex indices to poly origindex indices*/
+       cdDM_recalcTesselation(dm);
 
-       /* make a face normal layer if not present */
-       face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
-       if(!face_nors)
-               face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC,
-                                                                                NULL, dm->numFaceData);
+       CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN, 
+               face_nors, dm->numFaceData);
+}
 
-       /* calculate face normals */
-       mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_faces(dm), dm->numFaceData, face_nors);
+#if 1
+/*merge verts
+  vtargetmap is a table that maps vertices to target vertices.  a value of -1
+  indicates a vertex is a target, and is to be kept.
+  
+  this frees dm, and returns a new one.
+  
+  this is a really horribly written function.  ger. - joeedh
+
+ */
+DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+       CDDerivedMesh *cddm2 = NULL;
+       MVert *mv, *mvert = NULL;
+       BLI_array_declare(mvert);
+       MEdge *me, *medge = NULL;
+       BLI_array_declare(medge);
+       MPoly *mp, *mpoly = NULL;
+       BLI_array_declare(mpoly);
+       MLoop *ml, *mloop = NULL;
+       BLI_array_declare(mloop);
+       EdgeHash *ehash = BLI_edgehash_new();
+       int *newv = NULL, *newe = NULL, *newl = NULL;
+       int *oldv = NULL, *olde = NULL, *oldl = NULL, *oldp = NULL;
+       BLI_array_declare(oldv); BLI_array_declare(olde); BLI_array_declare(oldl); BLI_array_declare(oldp);
+       int i, j, c, totloop, totpoly;
+       
+       totloop = dm->numLoopData;
+       totpoly = dm->numPolyData;
+       
+       newv = MEM_callocN(sizeof(int)*dm->numVertData, "newv vtable CDDM_merge_verts");
+       newe = MEM_callocN(sizeof(int)*dm->numEdgeData, "newv etable CDDM_merge_verts");
+       newl = MEM_callocN(sizeof(int)*totloop, "newv ltable CDDM_merge_verts");
+       
+       /*fill newl with destination vertex indices*/
+       mv = cddm->mvert;
+       c = 0;
+       for (i=0; i<dm->numVertData; i++, mv++) {
+               if (vtargetmap[i] == -1) {
+                       BLI_array_append(oldv, i);
+                       newv[i] = c++;
+                       BLI_array_append(mvert, *mv);
+               }
+       }
+       
+       /*now link target vertices to destination indices*/
+       for (i=0; i<dm->numVertData; i++) {
+               if (vtargetmap[i] != -1) {
+                       newv[i] = newv[vtargetmap[i]];
+               }
+       }
+       
+       /*find-replace merged vertices with target vertices*/   
+       ml = cddm->mloop;
+       c = 0;
+       for (i=0; i<totloop; i++, ml++) {
+               if (ml->v == -1)
+                       continue;
+               
+               if (vtargetmap[ml->v] != -1)
+                       ml->v = vtargetmap[ml->v];
+       }
+       
+       /*now go through and fix edges and faces*/
+       me = cddm->medge;
+       c = 0;
+       for (i=0; i<dm->numEdgeData; i++, me++) {
+               int v1, v2;
+               
+               if (me->v1 == me->v2) {
+                       newe[i] = -1;
+                       continue;
+               }
+               
+               if (vtargetmap[me->v1] != -1)
+                       v1 = vtargetmap[me->v1];
+               else
+                       v1 = me->v1;
+               
+               if (vtargetmap[me->v2] != -1)
+                       v2 = vtargetmap[me->v2];
+               else
+                       v2 = me->v2;
+               
+               if (BLI_edgehash_haskey(ehash, v1, v2)) {
+                       newe[i] = GET_INT_FROM_POINTER(BLI_edgehash_lookup(ehash, v1, v2));
+               } else {
+                       BLI_array_append(olde, i);
+                       newe[i] = c;
+                       BLI_array_append(medge, *me);
+                       BLI_edgehash_insert(ehash, v1, v2, SET_INT_IN_POINTER(c));
+                       c++;
+               }
+       }
+       
+       mp = cddm->mpoly;
+       for (i=0; i<totpoly; i++, mp++) {
+               MPoly *mp2;
+               
+               ml = cddm->mloop + mp->loopstart;
+               
+               c = 0;
+               for (j=0; j<mp->totloop; j++, ml++) {
+                       if (ml->v == -1)
+                               continue;
+                       
+                       me = cddm->medge + ml->e;
+                       if (me->v1 != me->v2) {
+                               BLI_array_append(oldl, j+mp->loopstart);
+                               BLI_array_append(mloop, *ml);
+                               newl[j+mp->loopstart] = BLI_array_count(mloop)-1;
+                               c++;
+                       }
+               }
+               
+               if (!c)
+                       continue;
+               
+               mp2 = BLI_array_append(mpoly, *mp);
+               mp2->totloop = c;
+               mp2->loopstart = BLI_array_count(mloop) - c;
+               
+               BLI_array_append(oldp, i);
+       }
+       
+       /*create new cddm*/     
+       cddm2 = (CDDerivedMesh*) CDDM_from_template((DerivedMesh*)cddm, BLI_array_count(mvert), BLI_array_count(medge), 0, BLI_array_count(mloop), BLI_array_count(mpoly));
+       
+       /*update edge indices and copy customdata*/
+       me = medge;
+       for (i=0; i<cddm2->dm.numEdgeData; i++, me++) {
+               if (newv[me->v1] != -1)
+                       me->v1 = newv[me->v1];
+               if (newv[me->v2] != -1)
+                       me->v2 = newv[me->v2];
+               
+               CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
+       }
+       
+       /*update loop indices and copy customdata*/
+       ml = mloop;
+       for (i=0; i<cddm2->dm.numLoopData; i++, ml++) {
+               if (newe[ml->e] != -1)
+                       ml->e = newe[ml->e];
+               if (newv[ml->v] != -1)
+                       ml->v = newv[ml->v];
+                       
+               CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
+       }
+       
+       /*copy vertex customdata*/      
+       mv = mvert;
+       for (i=0; i<cddm2->dm.numVertData; i++, mv++) {
+               CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1);
+       }
+       
+       /*copy poly customdata*/
+       mp = mpoly;
+       for (i=0; i<cddm2->dm.numPolyData; i++, mp++) {
+               CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1);
+       }
+       
+       /*copy over data.  CustomData_add_layer can do this, need to look it up.*/
+       memcpy(cddm2->mvert, mvert, sizeof(MVert)*BLI_array_count(mvert));
+       memcpy(cddm2->medge, medge, sizeof(MEdge)*BLI_array_count(medge));
+       memcpy(cddm2->mloop, mloop, sizeof(MLoop)*BLI_array_count(mloop));
+       memcpy(cddm2->mpoly, mpoly, sizeof(MPoly)*BLI_array_count(mpoly));
+       BLI_array_free(mvert); BLI_array_free(medge); BLI_array_free(mloop); BLI_array_free(mpoly);
+
+       CDDM_recalc_tesselation((DerivedMesh*)cddm2, 1);
+       
+       if (newv) 
+               MEM_freeN(newv); 
+       if (newe)
+               MEM_freeN(newe); 
+       if (newl)
+               MEM_freeN(newl);
+       if (oldv) 
+               MEM_freeN(oldv); 
+       if (olde) 
+               MEM_freeN(olde); 
+       if (oldl) 
+               MEM_freeN(oldl); 
+       if (oldp) 
+               MEM_freeN(oldp);
+       if (ehash)
+               BLI_edgehash_free(ehash, NULL);
+
+       /*free old derivedmesh*/
+       dm->needsFree = 1;
+       dm->release(dm);
+       
+       return (DerivedMesh*)cddm2;
 }
+#endif
 
 void CDDM_calc_edges(DerivedMesh *dm)
 {
@@ -1887,6 +2472,83 @@ void CDDM_calc_edges(DerivedMesh *dm)
        BLI_edgehash_free(eh, NULL);
 }
 
+
+void CDDM_calc_edges_poly(DerivedMesh *dm)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+       CustomData edgeData;
+       EdgeHashIterator *ehi;
+       MPoly *mp = cddm->mpoly;
+       MLoop *ml;
+       MEdge *med;
+       EdgeHash *eh = BLI_edgehash_new();
+       int v1, v2;
+       int *eindex;
+       int i, j, k, *index, numEdges = cddm->dm.numEdgeData, maxFaces = dm->numPolyData;
+
+       eindex = DM_get_edge_data_layer(dm, CD_ORIGINDEX);
+
+       med = cddm->medge;
+       if (med) {
+               for (i=0; i < numEdges; i++, med++) {
+                       BLI_edgehash_insert(eh, med->v1, med->v2, SET_INT_IN_POINTER(i+1));
+               }
+       }
+
+       for (i=0; i < maxFaces; i++, mp++) {
+               ml = cddm->mloop + mp->loopstart;
+               for (j=0; j<mp->totloop; j++, ml++) {
+                       v1 = ml->v;
+                       v2 = (cddm->mloop + mp->loopstart + ((j+1)%mp->totloop))->v;
+                       if (!BLI_edgehash_haskey(eh, v1, v2)) {
+                               BLI_edgehash_insert(eh, v1, v2, NULL);
+                       }
+               }
+       }
+
+       k = numEdges;
+       numEdges = BLI_edgehash_size(eh);
+
+       /* write new edges into a temporary CustomData */
+       memset(&edgeData, 0, sizeof(edgeData));
+       CustomData_add_layer(&edgeData, CD_MEDGE, CD_CALLOC, NULL, numEdges);
+       CustomData_add_layer(&edgeData, CD_ORIGINDEX, CD_CALLOC, NULL, numEdges);
+
+       ehi = BLI_edgehashIterator_new(eh);
+       med = CustomData_get_layer(&edgeData, CD_MEDGE);
+       index = CustomData_get_layer(&edgeData, CD_ORIGINDEX);
+       for(i = 0; !BLI_edgehashIterator_isDone(ehi);
+           BLI_edgehashIterator_step(ehi), ++i, ++med, ++index) {
+               BLI_edgehashIterator_getKey(ehi, (int*)&med->v1, (int*)&med->v2);
+               j = GET_INT_FROM_POINTER(BLI_edgehashIterator_getValue(ehi));
+
+               med->flag = ME_EDGEDRAW|ME_EDGERENDER;
+               *index = j==0 ? ORIGINDEX_NONE : eindex[j-1];
+
+               BLI_edgehashIterator_setValue(ehi, SET_INT_IN_POINTER(i));
+       }
+       BLI_edgehashIterator_free(ehi);
+
+       /* free old CustomData and assign new one */
+       CustomData_free(&dm->edgeData, dm->numEdgeData);
+       dm->edgeData = edgeData;
+       dm->numEdgeData = numEdges;
+
+       cddm->medge = CustomData_get_layer(&dm->edgeData, CD_MEDGE);
+
+       mp = cddm->mpoly;
+       for (i=0; i < maxFaces; i++, mp++) {
+               ml = cddm->mloop + mp->loopstart;
+               for (j=0; j<mp->totloop; j++, ml++) {
+                       v1 = ml->v;
+                       v2 = (cddm->mloop + mp->loopstart + ((j+1)%mp->totloop))->v;
+                       ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, v1, v2));
+               }
+       }
+
+       BLI_edgehash_free(eh, NULL);
+}
+
 void CDDM_lower_num_verts(DerivedMesh *dm, int numVerts)
 {
        if (numVerts < dm->numVertData)
@@ -1921,7 +2583,7 @@ MEdge *CDDM_get_edge(DerivedMesh *dm, int index)
        return &((CDDerivedMesh*)dm)->medge[index];
 }
 
-MFace *CDDM_get_face(DerivedMesh *dm, int index)
+MFace *CDDM_get_tessface(DerivedMesh *dm, int index)
 {
        return &((CDDerivedMesh*)dm)->mface[index];
 }
@@ -1936,8 +2598,125 @@ MEdge *CDDM_get_edges(DerivedMesh *dm)
        return ((CDDerivedMesh*)dm)->medge;
 }
 
-MFace *CDDM_get_faces(DerivedMesh *dm)
+MFace *CDDM_get_tessfaces(DerivedMesh *dm)
 {
        return ((CDDerivedMesh*)dm)->mface;
 }
 
+MLoop *CDDM_get_loops(DerivedMesh *dm)
+{
+       return ((CDDerivedMesh*)dm)->mloop;
+}
+
+MPoly *CDDM_get_polys(DerivedMesh *dm)
+{
+       return ((CDDerivedMesh*)dm)->mpoly;
+}
+
+void CDDM_tessfaces_to_faces(DerivedMesh *dm)
+{
+       /*converts mfaces to mpolys/mloops*/
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+       MFace *mf;
+       MEdge *me;
+       MLoop *ml;
+       MPoly *mp;
+       EdgeHash *eh = BLI_edgehash_new();
+       int i, l, totloop, *index1, *index2;
+       
+       /*ensure we have all the edges we need*/
+       CDDM_calc_edges(dm);
+
+       /*build edge hash*/
+       me = cddm->medge;
+       for (i=0; i<cddm->dm.numEdgeData; i++, me++) {
+               BLI_edgehash_insert(eh, me->v1, me->v2, SET_INT_IN_POINTER(i));
+       }
+
+       mf = cddm->mface;
+       totloop = 0;
+       for (i=0; i<cddm->dm.numFaceData; i++, mf++) {
+               totloop += mf->v4 ? 4 : 3;
+       }
+
+       CustomData_free(&cddm->dm.polyData, cddm->dm.numPolyData);
+       CustomData_free(&cddm->dm.loopData, cddm->dm.numLoopData);
+       
+       cddm->dm.numLoopData = totloop;
+       cddm->dm.numPolyData = cddm->dm.numFaceData;
+
+       if (!totloop) return;
+
+       cddm->mloop = MEM_callocN(sizeof(MLoop)*totloop, "cddm->mloop in CDDM_tessfaces_to_faces");
+       cddm->mpoly = MEM_callocN(sizeof(MPoly)*cddm->dm.numFaceData, "cddm->mpoly in CDDM_tessfaces_to_faces");
+       
+       CustomData_add_layer(&cddm->dm.loopData, CD_MLOOP, CD_ASSIGN, cddm->mloop, totloop);
+       CustomData_add_layer(&cddm->dm.polyData, CD_MPOLY, CD_ASSIGN, cddm->mpoly, cddm->dm.numPolyData);
+       CustomData_merge(&cddm->dm.faceData, &cddm->dm.polyData, 
+               CD_MASK_ORIGINDEX, CD_DUPLICATE, cddm->dm.numFaceData);
+
+       index1 = CustomData_get_layer(&cddm->dm.faceData, CD_ORIGINDEX);
+       index2 = CustomData_get_layer(&cddm->dm.polyData, CD_ORIGINDEX);
+
+       mf = cddm->mface;
+       mp = cddm->mpoly;
+       ml = cddm->mloop;
+       l = 0;
+       for (i=0; i<cddm->dm.numFaceData; i++, mf++, mp++) {
+               mp->flag = mf->flag;
+               mp->loopstart = l;
+               mp->mat_nr = mf->mat_nr;
+               mp->totloop = mf->v4 ? 4 : 3;
+               
+               ml->v = mf->v1;
+               ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v1, mf->v2));
+               ml++, l++;
+
+               ml->v = mf->v2;
+               ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v2, mf->v3));
+               ml++, l++;
+
+               ml->v = mf->v3;
+               ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v3, mf->v4?mf->v4:mf->v1));
+               ml++, l++;
+
+               if (mf->v4) {
+                       ml->v = mf->v4;
+                       ml->e = GET_INT_FROM_POINTER(BLI_edgehash_lookup(eh, mf->v4, mf->v1));
+                       ml++, l++;
+               }
+
+       }
+
+       BLI_edgehash_free(eh, NULL);
+}
+
+void CDDM_set_mvert(DerivedMesh *dm, MVert *mvert)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+       
+       if (!CustomData_has_layer(&dm->vertData, CD_MVERT))
+               CustomData_add_layer(&dm->vertData, CD_MVERT, CD_ASSIGN, mvert, dm->numVertData);
+                               
+       cddm->mvert = mvert;
+}
+
+void CDDM_set_medge(DerivedMesh *dm, MEdge *medge)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+       if (!CustomData_has_layer(&dm->edgeData, CD_MEDGE))
+               CustomData_add_layer(&dm->edgeData, CD_MEDGE, CD_ASSIGN, medge, dm->numEdgeData);
+
+       cddm->medge = medge;
+}
+
+void CDDM_set_mface(DerivedMesh *dm, MFace *mface)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
+
+       if (!CustomData_has_layer(&dm->faceData, CD_MFACE))
+               CustomData_add_layer(&dm->faceData, CD_MFACE, CD_ASSIGN, mface, dm->numFaceData);
+
+       cddm->mface = mface;
+}