svn merge -r39765:39781 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[blender.git] / source / blender / blenkernel / intern / cdderivedmesh.c
index 0374f4856cadbc356b3289f0d562a37f9782c1f6..ad70e00a33ce1f350a47ace908c4b3ada52d3022 100644 (file)
 *
 * BKE_cdderivedmesh.h contains the function prototypes for this file.
 *
-*/ 
+*/
+
+/** \file blender/blenkernel/intern/cdderivedmesh.c
+ *  \ingroup bke
+ */
 
 /* TODO maybe BIF_gl.h should include string.h? */
 #include <string.h>
 #include "BLI_pbvh.h"
 #include "BLI_array.h"
 #include "BLI_smallhash.h"
+#include "BLI_utildefines.h"
+
+#include "BKE_cdderivedmesh.h"
+#include "BKE_global.h"
+#include "BKE_mesh.h"
+#include "BKE_paint.h"
+
 
 #include "DNA_meshdata_types.h"
 #include "DNA_object_types.h"
@@ -83,13 +95,12 @@ typedef struct {
        /* Cached */
        struct PBVH *pbvh;
        int pbvh_draw;
+
        /* Mesh connectivity */
        struct ListBase *fmap;
        struct IndexNode *fmap_mem;
 } CDDerivedMesh;
 
-DMFaceIter *cdDM_newFaceIter(DerivedMesh *source);
-
 /**************** DerivedMesh interface functions ****************/
 static int cdDM_getNumVerts(DerivedMesh *dm)
 {
@@ -147,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;
@@ -180,11 +203,7 @@ static void cdDM_getVertCos(DerivedMesh *dm, float (*cos_r)[3])
 static void cdDM_getVertNo(DerivedMesh *dm, int index, float no_r[3])
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
-       short *no = cddm->mvert[index].no;
-
-       no_r[0] = no[0]/32767.f;
-       no_r[1] = no[1]/32767.f;
-       no_r[2] = no[2]/32767.f;
+       normal_short_to_float_v3(no_r, cddm->mvert[index].no);
 }
 
 static ListBase *cdDM_getFaceMap(Object *ob, DerivedMesh *dm)
@@ -204,9 +223,21 @@ static ListBase *cdDM_getFaceMap(Object *ob, DerivedMesh *dm)
 static int can_pbvh_draw(Object *ob, DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
-       Mesh *me= (ob)? ob->data: NULL;
+       Mesh *me= ob->data;
+       int deformed= 0;
+
+       /* active modifiers means extra deformation, which can't be handled correct
+          on bith of PBVH and sculpt "layer" levels, so use PBVH only for internal brush
+          stuff and show final DerivedMesh so user would see actual object shape */
+       deformed|= ob->sculpt->modifiers_active;
 
-       if(ob->sculpt->modifiers_active) return 0;
+       /* as in case with modifiers, we can't synchronize deformation made against
+          PBVH and non-locked keyblock, so also use PBVH only for brushes and
+          final DM to give final result to user */
+       deformed|= ob->sculpt->kb && (ob->shapeflag&OB_SHAPE_LOCK) == 0;
+
+       if(deformed)
+               return 0;
 
        return (cddm->mvert == me->mvert) || ob->sculpt->kb;
 }
@@ -214,7 +245,6 @@ static int can_pbvh_draw(Object *ob, DerivedMesh *dm)
 static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
-       Mesh *me= (ob)? ob->data: NULL;
 
        if(!ob) {
                cddm->pbvh= NULL;
@@ -232,15 +262,44 @@ static struct PBVH *cdDM_getPBVH(Object *ob, DerivedMesh *dm)
           this derivedmesh is just original mesh. it's the multires subsurf dm
           that this is actually for, to support a pbvh on a modified mesh */
        if(!cddm->pbvh && ob->type == OB_MESH) {
+               SculptSession *ss= ob->sculpt;
+               Mesh *me= ob->data;
                cddm->pbvh = BLI_pbvh_new();
                cddm->pbvh_draw = can_pbvh_draw(ob, dm);
                BLI_pbvh_build_mesh(cddm->pbvh, me->mface, me->mvert,
                                   me->totface, me->totvert);
+
+               if(ss->modifiers_active && ob->derivedDeform) {
+                       DerivedMesh *deformdm= ob->derivedDeform;
+                       float (*vertCos)[3];
+                       int totvert;
+
+                       totvert= deformdm->getNumVerts(deformdm);
+                       vertCos= MEM_callocN(3*totvert*sizeof(float), "cdDM_getPBVH vertCos");
+                       deformdm->getVertCos(deformdm, vertCos);
+                       BLI_pbvh_apply_vertCos(cddm->pbvh, vertCos);
+                       MEM_freeN(vertCos);
+               }
        }
 
        return cddm->pbvh;
 }
 
+/* update vertex normals so that drawing smooth faces works during sculpt
+   TODO: proper fix is to support the pbvh in all drawing modes */
+static void cdDM_update_normals_from_pbvh(DerivedMesh *dm)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+       float (*face_nors)[3];
+
+       if(!cddm->pbvh || !cddm->pbvh_draw || !dm->numFaceData)
+               return;
+
+       face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
+
+       BLI_pbvh_update(cddm->pbvh, PBVH_UpdateNormals, face_nors);
+}
+
 static void cdDM_drawVerts(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@ -256,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();
        }
@@ -304,7 +365,7 @@ static void cdDM_drawUVEdges(DerivedMesh *dm)
                        GPU_uvedge_setup(dm);
                        if( !GPU_buffer_legacy(dm) ) {
                                for(i = 0; i < dm->numFaceData; i++, mf++) {
-                                       if(mf->flag&ME_LOOSEEDGE) {
+                                       if(!(mf->flag&ME_HIDE)) {
                                                draw = 1;
                                        } 
                                        else {
@@ -433,7 +494,7 @@ static void cdDM_drawLooseEdges(DerivedMesh *dm)
 
 static void cdDM_drawFacesSolid(DerivedMesh *dm,
                                float (*partial_redraw_planes)[4],
-                               int fast, int (*setMaterial)(int, void *attribs))
+                               int UNUSED(fast), int (*setMaterial)(int, void *attribs))
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
        MVert *mvert = cddm->mvert;
@@ -519,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( );
@@ -550,8 +612,11 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
        /* there's a conflict here... twosided colors versus culling...? */
        /* defined by history, only texture faces have culling option */
        /* we need that as mesh option builtin, next to double sided lighting */
-       if(col1 && col2)
+       if(col2) {
                glEnable(GL_CULL_FACE);
+       }
+
+       cdDM_update_normals_from_pbvh(dm);
 
        if( GPU_buffer_legacy(dm) ) {
                DEBUG_VBO( "Using legacy code. cdDM_drawFacesColored\n" );
@@ -565,26 +630,26 @@ static void cdDM_drawFacesColored(DerivedMesh *dm, int useTwoSided, unsigned cha
                                glBegin(glmode = new_glmode);
                        }
                                
-                       glColor3ub(cp1[0], cp1[1], cp1[2]);
+                       glColor3ubv(cp1+0);
                        glVertex3fv(mvert[mface->v1].co);
-                       glColor3ub(cp1[4], cp1[5], cp1[6]);
+                       glColor3ubv(cp1+4);
                        glVertex3fv(mvert[mface->v2].co);
-                       glColor3ub(cp1[8], cp1[9], cp1[10]);
+                       glColor3ubv(cp1+8);
                        glVertex3fv(mvert[mface->v3].co);
                        if(mface->v4) {
-                               glColor3ub(cp1[12], cp1[13], cp1[14]);
+                               glColor3ubv(cp1+12);
                                glVertex3fv(mvert[mface->v4].co);
                        }
                                
                        if(useTwoSided) {
-                               glColor3ub(cp2[8], cp2[9], cp2[10]);
+                               glColor3ubv(cp2+8);
                                glVertex3fv(mvert[mface->v3].co );
-                               glColor3ub(cp2[4], cp2[5], cp2[6]);
+                               glColor3ubv(cp2+4);
                                glVertex3fv(mvert[mface->v2].co );
-                               glColor3ub(cp2[0], cp2[1], cp2[2]);
+                               glColor3ubv(cp2+0);
                                glVertex3fv(mvert[mface->v1].co );
                                if(mface->v4) {
-                                       glColor3ub(cp2[12], cp2[13], cp2[14]);
+                                       glColor3ubv(cp2+12);
                                        glVertex3fv(mvert[mface->v4].co );
                                }
                        }
@@ -598,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);
                        }
                }
@@ -632,6 +697,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
        if(!mcol)
                mcol = dm->getTessFaceDataArray(dm, CD_MCOL);
 
+       cdDM_update_normals_from_pbvh(dm);
+
        if( GPU_buffer_legacy(dm) ) {
                DEBUG_VBO( "Using legacy code. cdDM_drawFacesTex_common\n" );
                for(i = 0; i < dm->numFaceData; i++, mf++) {
@@ -712,7 +779,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                GPU_vertex_setup( dm );
                GPU_normal_setup( dm );
                GPU_uv_setup( dm );
-               if( col != 0 ) {
+               if( col != NULL ) {
                        /*if( realcol && dm->drawObject->colType == CD_TEXTURE_MCOL )  {
                                col = 0;
                        } else if( mcol && dm->drawObject->colType == CD_MCOL ) {
@@ -739,9 +806,23 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                }
 
                if( !GPU_buffer_legacy(dm) ) {
+                       /* warning!, this logic is incorrect, see bug [#27175]
+                        * firstly, there are no checks for changes in context, such as texface image.
+                        * secondly, drawParams() sets the GL context, so checking if there is a change
+                        * from lastFlag is too late once glDrawArrays() runs, since drawing the arrays
+                        * will use the modified, OpenGL settings.
+                        * 
+                        * However its tricky to fix this without duplicating the internal logic
+                        * of drawParams(), perhaps we need an argument like...
+                        * drawParams(..., keep_gl_state_but_return_when_changed) ?.
+                        *
+                        * We could also just disable VBO's here, since texface may be deprecated - campbell.
+                        */
+                       
                        glShadeModel( GL_SMOOTH );
-                       for(i = 0; i < dm->drawObject->nelements/3; i++) {
-                               int actualFace = dm->drawObject->faceRemap[i];
+                       lastFlag = 0;
+                       for(i = 0; i < dm->drawObject->tot_triangle_point/3; i++) {
+                               int actualFace = dm->drawObject->triangle_to_mface[i];
                                int flag = 1;
 
                                if(drawParams) {
@@ -750,6 +831,7 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                else {
                                        if(index) {
                                                orig = index[actualFace];
+                                               if(orig == ORIGINDEX_NONE) continue;
                                                if(drawParamsMapped)
                                                        flag = drawParamsMapped(userData, orig);
                                        }
@@ -771,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);
                                }
                        }
                }
@@ -792,13 +874,14 @@ static void cdDM_drawFacesTex(DerivedMesh *dm, int (*setDrawOptions)(MTFace *tfa
        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)
+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->getTessFaceDataArray(dm, CD_NORMAL);
+       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_tessface_data_layer(dm, CD_ID_MCOL);
@@ -807,22 +890,24 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
        if(!mc)
                mc = DM_get_tessface_data_layer(dm, CD_MCOL);
 
+       cdDM_update_normals_from_pbvh(dm);
+
        /* back-buffer always uses legacy since VBO's would need the
         * color array temporarily overwritten for drawing, then reset. */
        if( GPU_buffer_legacy(dm) || G.f & G_BACKBUFSEL) {
                DEBUG_VBO( "Using legacy code. cdDM_drawMappedFaces\n" );
                for(i = 0; i < dm->numFaceData; i++, mf++) {
                        int drawSmooth = (mf->flag & ME_SMOOTH);
+                       int draw= 1;
 
-                       if(index) {
-                               orig = *index++;
-                               if(setDrawOptions && orig == ORIGINDEX_NONE)
-                                       { if(nors) nors += 3; continue; }
-                       }
-                       else
-                               orig = i;
+                       orig= (index==NULL) ? i : *index++;
+                       
+                       if(orig == ORIGINDEX_NONE)
+                               draw= setMaterial(mf->mat_nr + 1, NULL);
+                       else if (setDrawOptions != NULL)
+                               draw= setDrawOptions(userData, orig, &drawSmooth);
 
-                       if(!setDrawOptions || setDrawOptions(userData, orig, &drawSmooth)) {
+                       if(draw) {
                                unsigned char *cp = NULL;
 
                                if(useColors && mc)
@@ -873,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;
                }
@@ -885,36 +972,68 @@ 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) {
+                               /* avoid buffer problems in following code */
+                       }
+                       if(setDrawOptions == NULL) {
+                               /* just draw the entire face array */
+                               glDrawArrays(GL_TRIANGLES, 0, (tottri-1) * 3);
+                       }
+                       else {
+                               /* we need to check if the next material changes */
+                               int next_actualFace= dm->drawObject->triangle_to_mface[0];
+                               
+                               for( i = 0; i < tottri; 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->triangle_to_mface[i+1];
+
+                                       orig= (index==NULL) ? actualFace : index[actualFace];
+
+                                       if(orig == ORIGINDEX_NONE)
+                                               draw= setMaterial(mface->mat_nr + 1, NULL);
+                                       else if (setDrawOptions != NULL)
+                                               draw= setDrawOptions(userData, orig, &drawSmooth);
+       
+                                       /* 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 */
 
-                       for( i = 0; i < tottri; i++ ) {
-                               int actualFace = dm->drawObject->faceRemap[i];
-                               int drawSmooth = (mf[actualFace].flag & ME_SMOOTH);
-                               int draw = 1;
+                                       /* flush buffer if current triangle isn't drawable or it's last triangle... */
+                                       flush= !draw || i == tottri - 1;
 
-                               if(index) {
-                                       orig = index[actualFace];
-                                       if(setDrawOptions && orig == ORIGINDEX_NONE)
-                                               draw = 0;
-                               }
-                               else
-                                       orig = actualFace;
+                                       /* ... or when material setting is dissferent  */
+                                       flush|= mf[actualFace].mat_nr != mf[next_actualFace].mat_nr;
 
-                               if(draw && setDrawOptions && !setDrawOptions(userData, orig, &drawSmooth))
-                                       draw = 0;
+                                       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 */
 
-                               /* 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) {
-                                       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);
-                                       prevstart = i + 1;
+                                               if(count)
+                                                       glDrawArrays(GL_TRIANGLES, first, count);
+
+                                               prevstart = i + 1;
+                                       }
                                }
                        }
+
                        glShadeModel(GL_FLAT);
                }
                GPU_buffer_unbind();
@@ -926,28 +1045,52 @@ static void cdDM_drawMappedFacesTex(DerivedMesh *dm, int (*setDrawOptions)(void
        cdDM_drawFacesTex_common(dm, NULL, setDrawOptions, userData);
 }
 
-#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];                                                   \
-                       glVertexAttrib3fvARB(attribs.tang.glIndex, tang);                                               \
-               }                                                                                                                                                       \
-               if(smoothnormal)                                                                                                                        \
-                       glNormal3sv(mvert[index].no);                                                                                   \
-               glVertex3fv(mvert[index].co);                                                                                           \
+
+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;
@@ -957,25 +1100,27 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
        MFace *mface = cddm->mface;
        MTFace *tf = dm->getTessFaceDataArray(dm, CD_MTFACE);
        float (*nors)[3] = dm->getTessFaceDataArray(dm, CD_NORMAL);
-       int a, b, dodraw, smoothnormal, matnr, new_matnr;
+       int a, b, dodraw, matnr, new_matnr;
        int transp, new_transp, orig_transp;
        int orig, *index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
 
+       cdDM_update_normals_from_pbvh(dm);
+
        matnr = -1;
-       smoothnormal = 0;
        dodraw = 0;
        transp = GPU_get_material_blend_mode();
        orig_transp = transp;
 
        glShadeModel(GL_SMOOTH);
 
-       if( GPU_buffer_legacy(dm) || setDrawOptions != 0 ) {
+       if( GPU_buffer_legacy(dm) || setDrawOptions != NULL ) {
                DEBUG_VBO( "Using legacy code. cdDM_drawMappedFacesGLSL\n" );
                memset(&attribs, 0, sizeof(attribs));
 
                glBegin(GL_QUADS);
 
                for(a = 0; a < dm->numFaceData; a++, mface++) {
+                       const int smoothnormal = (mface->flag & ME_SMOOTH);
                        new_matnr = mface->mat_nr + 1;
 
                        if(new_matnr != matnr) {
@@ -994,8 +1139,12 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                        else if(setDrawOptions) {
                                orig = (index)? index[a]: a;
 
-                               if(orig == ORIGINDEX_NONE)
-                                       continue;
+                               if(orig == ORIGINDEX_NONE) {
+                                       /* since the material is set by setMaterial(), faces with no
+                                        * origin can be assumed to be generated by a modifier */ 
+                                       
+                                       /* continue */
+                               }
                                else if(!setDrawOptions(userData, orig))
                                        continue;
                        }
@@ -1016,8 +1165,6 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                }
                        }
 
-                       smoothnormal = (mface->flag & ME_SMOOTH);
-
                        if(!smoothnormal) {
                                if(nors) {
                                        glNormal3fv(nors[a]);
@@ -1034,21 +1181,20 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                }
                        }
 
-                       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();
        }
        else {
-               GPUBuffer *buffer = 0;
-               char *varray = 0;
+               GPUBuffer *buffer = NULL;
+               char *varray = NULL;
                int numdata = 0, elementsize = 0, offset;
                int start = 0, numfaces = 0, prevdraw = 0, curface = 0;
                int i;
@@ -1061,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;
@@ -1085,9 +1231,9 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
 
                                                        if( numdata != 0 ) {
 
-                                                               GPU_buffer_free(buffer,0);
+                                                               GPU_buffer_free(buffer);
 
-                                                               buffer = 0;
+                                                               buffer = NULL;
                                                        }
 
                                                }
@@ -1119,22 +1265,22 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                }       
                                                if(attribs.tottang) {
                                                        datatypes[numdata].index = attribs.tang.glIndex;
-                                                       datatypes[numdata].size = 3;
+                                                       datatypes[numdata].size = 4;
                                                        datatypes[numdata].type = GL_FLOAT;
                                                        numdata++;
                                                }
                                                if( numdata != 0 ) {
                                                        elementsize = GPU_attrib_element_size( datatypes, numdata );
-                                                       buffer = GPU_buffer_alloc( elementsize*dm->drawObject->nelements, 0 );
-                                                       if( buffer == 0 ) {
+                                                       buffer = GPU_buffer_alloc( elementsize*dm->drawObject->tot_triangle_point);
+                                                       if( buffer == NULL ) {
                                                                GPU_buffer_unbind();
                                                                dm->drawObject->legacy = 1;
                                                                return;
                                                        }
                                                        varray = GPU_buffer_lock_stream(buffer);
-                                                       if( varray == 0 ) {
+                                                       if( varray == NULL ) {
                                                                GPU_buffer_unbind();
-                                                               GPU_buffer_free(buffer, 0);
+                                                               GPU_buffer_free(buffer);
                                                                dm->drawObject->legacy = 1;
                                                                return;
                                                        }
@@ -1209,13 +1355,14 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                        }       
                                        if(attribs.tottang) {
                                                float *tang = attribs.tang.array[a*4 + 0];
-                                               VECCOPY((float *)&varray[elementsize*curface*3+offset], tang);
+                                               QUATCOPY((float *)&varray[elementsize*curface*3+offset], tang);
                                                tang = attribs.tang.array[a*4 + 1];
-                                               VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize], tang);
+                                               QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize], tang);
                                                tang = attribs.tang.array[a*4 + 2];
-                                               VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang);
-                                               offset += sizeof(float)*3;
+                                               QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang);
+                                               offset += sizeof(float)*4;
                                        }
+                                       (void)offset;
                                }
                                curface++;
                                if(mface->v4) {
@@ -1249,13 +1396,14 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                }       
                                                if(attribs.tottang) {
                                                        float *tang = attribs.tang.array[a*4 + 2];
-                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset], tang);
+                                                       QUATCOPY((float *)&varray[elementsize*curface*3+offset], tang);
                                                        tang = attribs.tang.array[a*4 + 3];
-                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize], tang);
+                                                       QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize], tang);
                                                        tang = attribs.tang.array[a*4 + 0];
-                                                       VECCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang);
-                                                       offset += sizeof(float)*3;
+                                                       QUATCOPY((float *)&varray[elementsize*curface*3+offset+elementsize*2], tang);
+                                                       offset += sizeof(float)*4;
                                                }
+                                               (void)offset;
                                        }
                                        curface++;
                                        i++;
@@ -1273,7 +1421,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                        }
                        GPU_buffer_unbind();
                }
-               GPU_buffer_free( buffer, 0 );
+               GPU_buffer_free(buffer);
        }
 
        glShadeModel(GL_FLAT);
@@ -1418,6 +1566,14 @@ static void cdDM_recalcTesselation2(DerivedMesh *dm)
        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)
 {
        if(cddm->fmap) MEM_freeN(cddm->fmap);
@@ -1455,14 +1611,14 @@ static CDDerivedMesh *cdDM_create(const char *desc)
        dm->getNumTessFaces = cdDM_getNumTessFaces;
        dm->getNumFaces = cdDM_getNumFaces;
 
-       dm->newFaceIter = cdDM_newFaceIter;
-
        dm->getVert = cdDM_getVert;
        dm->getEdge = cdDM_getEdge;
        dm->getTessFace = cdDM_getFace;
        dm->copyVertArray = cdDM_copyVertArray;
        dm->copyEdgeArray = cdDM_copyEdgeArray;
        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->getTessFaceData = DM_get_face_data;
@@ -1531,7 +1687,7 @@ DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces, int numLoops, in
        return dm;
 }
 
-DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
+DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *UNUSED(ob))
 {
        CDDerivedMesh *cddm = cdDM_create("CDDM_from_mesh dm");
        DerivedMesh *dm = &cddm->dm;
@@ -1570,7 +1726,7 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
        return dm;
 }
 
-DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
+static DerivedMesh *disabled__CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
 {
        DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
                                   BLI_countlist(&em->edges),
@@ -1617,12 +1773,9 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
 
                VECCOPY(mv->co, eve->co);
 
-               mv->no[0] = eve->no[0] * 32767.0;
-               mv->no[1] = eve->no[1] * 32767.0;
-               mv->no[2] = eve->no[2] * 32767.0;
+               normal_float_to_short_v3(mv->no, eve->no);
                mv->bweight = (unsigned char) (eve->bweight * 255.0f);
 
-               mv->mat_nr = 0;
                mv->flag = 0;
 
                *index = i;
@@ -1673,7 +1826,7 @@ DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
 
 DerivedMesh *CDDM_from_curve(Object *ob)
 {
-       return CDDM_from_curve_customDB(ob, &((Curve *)ob->data)->disp);
+       return CDDM_from_curve_customDB(ob, &ob->disp);
 }
 
 DerivedMesh *CDDM_from_curve_customDB(Object *ob, ListBase *dispbase)
@@ -1683,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, 0, 0);
        }
 
-       dm = CDDM_new(totvert, totedge, totface, totface*4, totface);
+       dm = CDDM_new(totvert, totedge, totface, totloop, totpoly);
        dm->deformedOnly = 1;
 
        cddm = (CDDerivedMesh*)dm;
@@ -1699,10 +1854,14 @@ 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;
 }
@@ -1766,7 +1925,7 @@ static void loops_to_customdata_corners(BMesh *bm, CustomData *facedata,
        }
 }
 
-DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
+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);
@@ -1784,19 +1943,30 @@ DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
        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);
 
-       CustomData_merge(&em->bm->vdata, &dm->vertData, CD_MASK_DERIVEDMESH,
+       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, CD_MASK_DERIVEDMESH,
+       CustomData_merge(&em->bm->edata, &dm->edgeData, flag,
                         CD_CALLOC, dm->numEdgeData);
-       CustomData_merge(&em->bm->ldata, &dm->loopData, CD_MASK_DERIVEDMESH,
+       CustomData_merge(&em->bm->ldata, &dm->loopData, flag,
                         CD_CALLOC, dm->numLoopData);
-       CustomData_merge(&em->bm->pdata, &dm->polyData, CD_MASK_DERIVEDMESH,
+       CustomData_merge(&em->bm->pdata, &dm->polyData, flag,
                         CD_CALLOC, dm->numPolyData);
        
        /*add tesselation mface layers*/
@@ -1805,7 +1975,7 @@ DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
        /* set vert index */
        eve = BMIter_New(&iter, bm, BM_VERTS_OF_MESH, NULL);
        for (i=0; eve; eve=BMIter_Step(&iter), i++)
-               BMINDEX_SET(eve, i);
+               BM_SetIndex(eve, i);
 
        index = dm->getVertDataArray(dm, CD_ORIGINDEX);
 
@@ -1815,15 +1985,17 @@ DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
 
                VECCOPY(mv->co, eve->co);
 
-               BMINDEX_SET(eve, i);
+               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->mat_nr = 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);
@@ -1834,11 +2006,16 @@ DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
        for (i=0; eed; eed=BMIter_Step(&iter), i++, index++) {
                MEdge *med = &medge[i];
 
-               BMINDEX_SET(eed, i);
+               BM_SetIndex(eed, i);
 
-               med->v1 = BMINDEX_GET(eed->v1);
-               med->v2 = BMINDEX_GET(eed->v2);
+               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);
 
@@ -1848,7 +2025,7 @@ DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
 
        efa = BMIter_New(&iter, bm, BM_FACES_OF_MESH, NULL);
        for (i=0; efa; i++, efa=BMIter_Step(&iter)) {
-               BMINDEX_SET(efa, i);
+               BM_SetIndex(efa, i);
        }
 
        index = dm->getTessFaceDataArray(dm, CD_ORIGINDEX);
@@ -1857,14 +2034,14 @@ DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
                BMLoop **l = em->looptris[i];
                efa = l[0]->f;
 
-               mf->v1 = BMINDEX_GET(l[0]->v);
-               mf->v2 = BMINDEX_GET(l[1]->v);
-               mf->v3 = BMINDEX_GET(l[2]->v);
+               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 ? BMINDEX_GET(efa) : *(int*)CustomData_bmesh_get(&bm->pdata, efa->head.data, CD_ORIGINDEX);
+               *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);
@@ -1883,8 +2060,8 @@ DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
                mp->mat_nr = efa->mat_nr;
                
                BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, efa) {
-                       mloop->v = BMINDEX_GET(l->v);
-                       mloop->e = BMINDEX_GET(l->e);
+                       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++;
@@ -1899,139 +2076,6 @@ DerivedMesh *CDDM_from_BMEditMesh(BMEditMesh *em, Mesh *me)
        return dm;
 }
 
-typedef struct CDDM_LoopIter {
-       DMLoopIter head;
-       CDDerivedMesh *cddm;
-       int len, i;
-} CDDM_LoopIter;
-
-typedef struct CDDM_FaceIter {
-       DMFaceIter head;
-       CDDerivedMesh *cddm;
-       CDDM_LoopIter liter;
-} CDDM_FaceIter;
-
-void cddm_freeiter(void *self)
-{
-       MEM_freeN(self);
-}
-
-void cddm_stepiter(void *self)
-{
-       CDDM_FaceIter *iter = self;
-       MPoly *mp;
-       
-       mp = iter->cddm->mpoly + iter->head.index;
-       mp->flag = iter->head.flags;
-       mp->mat_nr = iter->head.mat_nr;
-
-       iter->head.index++;
-       if (iter->head.index >= iter->cddm->dm.numPolyData) {
-               iter->head.done = 1;
-               return;
-       }
-
-       mp = iter->cddm->mpoly + iter->head.index;
-
-       iter->head.flags = mp->flag;
-       iter->head.mat_nr = mp->mat_nr;
-       iter->head.len = mp->totloop;
-}
-
-void *cddm_faceiter_getcddata(void *self, int type, int layer)
-{
-       CDDM_FaceIter *iter = self;
-
-       if (layer == -1) return CustomData_get(&iter->cddm->dm.polyData, 
-                                              iter->head.index, type);
-       else return CustomData_get_n(&iter->cddm->dm.polyData, type, 
-                                   iter->head.index, layer);
-}
-
-void *cddm_loopiter_getcddata(void *self, int type, int layer)
-{
-       CDDM_LoopIter *iter = self;
-
-       if (layer == -1) return CustomData_get(&iter->cddm->dm.loopData, 
-                                              iter->head.index, type);
-       else return CustomData_get_n(&iter->cddm->dm.loopData, type, 
-                                    iter->head.index, layer);
-}
-
-void *cddm_loopiter_getvertcddata(void *self, int type, int layer)
-{
-       CDDM_LoopIter *iter = self;
-
-       if (layer == -1) return CustomData_get(&iter->cddm->dm.vertData, 
-                                              iter->cddm->mloop[iter->head.vindex].v,
-                                              type);
-       else return CustomData_get_n(&iter->cddm->dm.vertData, type, 
-                                    iter->cddm->mloop[iter->head.vindex].v, layer);
-}
-
-DMLoopIter *cddmiter_get_loopiter(void *self)
-{
-       CDDM_FaceIter *iter = self;
-       CDDM_LoopIter *liter = &iter->liter;
-       MPoly *mp = iter->cddm->mpoly + iter->head.index;
-
-       liter->i = -1;
-       liter->len = iter->head.len;
-       liter->head.index = mp->loopstart-1;
-       liter->head.done = 0;
-
-       liter->head.step(liter);
-
-       return (DMLoopIter*) liter;
-}
-
-void cddm_loopiter_step(void *self)
-{
-       CDDM_LoopIter *liter = self;
-       MLoop *ml;
-
-       liter->i++;
-       liter->head.index++;
-
-       if (liter->i == liter->len) {
-               liter->head.done = 1;
-               return;
-       }
-
-       ml = liter->cddm->mloop + liter->head.index;
-
-       liter->head.eindex = ml->e;
-       liter->head.v = liter->cddm->mvert[ml->v];
-       liter->head.vindex = ml->v;
-}
-
-DMFaceIter *cdDM_newFaceIter(DerivedMesh *source)
-{
-       CDDerivedMesh *cddm = (CDDerivedMesh*) source;
-       CDDM_FaceIter *iter = MEM_callocN(sizeof(CDDM_FaceIter), "DMFaceIter from cddm");
-
-       iter->head.free = cddm_freeiter;
-       iter->head.step = cddm_stepiter;
-       iter->head.getCDData = cddm_faceiter_getcddata;
-       iter->head.getLoopsIter = cddmiter_get_loopiter;
-
-       iter->liter.head.step = cddm_loopiter_step;
-       iter->liter.head.getLoopCDData = cddm_loopiter_getcddata;
-       iter->liter.head.getVertCDData = cddm_loopiter_getvertcddata;
-       iter->liter.cddm = cddm;
-
-       iter->cddm = cddm;
-
-       if (source->numFaceData) {
-               iter->head.index = -1;
-               iter->head.step(iter);
-       } else {
-               iter->head.done = 1;
-       }
-
-       return (DMFaceIter*) iter;
-}
-
 DerivedMesh *CDDM_copy(DerivedMesh *source, int faces_from_tessfaces)
 {
        CDDerivedMesh *cddm = cdDM_create("CDDM_copy cddm");
@@ -2072,10 +2116,14 @@ DerivedMesh *CDDM_copy(DerivedMesh *source, int faces_from_tessfaces)
 
        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 numLoops, int numPolys)
@@ -2145,86 +2193,39 @@ void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3])
 void CDDM_calc_normals(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
-       float (*temp_nors)[3];
-       float (*face_nors)[3];
-       float (*vert_nors)[3];
-       int i, j, *origIndex;
-       int numVerts = dm->numVertData;
-       int numFaces = dm->numFaceData;
-       MFace *mf;
-       MPoly *mp;
-       MVert *mv;
-       MLoop *ml;
-
-       if(numVerts == 0) return;
-
-       if (CustomData_has_layer(&dm->faceData, CD_NORMAL))
-               CustomData_free_layer(&dm->faceData, CD_NORMAL, dm->numFaceData, 0);
-
-       temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors),
-                                                       "CDDM_calc_normals temp_nors");
+       float (*face_nors)[3] = NULL;
+       
+       if(dm->numVertData == 0) return;
 
-       /*recalc tesselation to ensure we have valid origindex values
-         for mface->mpoly lookups.*/
+       /* 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);
-
-       numFaces = dm->numFaceData;
-
-       /*first go through and calculate normals for all the polys*/
-       temp_nors = MEM_callocN(sizeof(float)*3*dm->numPolyData, "temp_nors cdderivedmesh.c");
-       vert_nors = MEM_callocN(sizeof(float)*3*dm->numVertData, "vert_nors cdderivedmesh.c");
        
-       mp = cddm->mpoly;
-       for (i=0; i<dm->numPolyData; i++, mp++) {
-               mesh_calc_poly_normal(mp, cddm->mloop+mp->loopstart, cddm->mvert, temp_nors[i]);
-
-               ml = cddm->mloop + mp->loopstart;
-               for (j=0; j<mp->totloop; j++, ml++) {
-                       VECADD(vert_nors[ml->v], vert_nors[ml->v], temp_nors[i]);
-               }
-       }
-
-       face_nors = MEM_callocN(sizeof(float)*3*dm->numFaceData, "face_nors cdderivedmesh.c");
-       origIndex = CustomData_get_layer(&dm->faceData, CD_ORIGINDEX);
-
-       mf = cddm->mface;
-       for (i=0; i<dm->numFaceData; i++, mf++, origIndex++) {
-               VECCOPY(face_nors[i], temp_nors[*origIndex]);
-       }
-
-       mv = cddm->mvert;
-       for (i=0; i<dm->numVertData; i++, mv++) {
-               float *no = vert_nors[i];
-               
-               if (normalize_v3(no) == 0.0) {
-                       VECCOPY(no, mv->co);
-                       if (normalize_v3(no) == 0.0) {
-                               no[0] = 0.0f;
-                               no[1] = 0.0f;
-                               no[2] = 1.0f;
-                       }
-               }
-
-               normal_float_to_short_v3(mv->no, no);
-       }
-
-       MEM_freeN(temp_nors);
-       MEM_freeN(vert_nors);
-
-       /*this restores original poly origindex -> tessface origindex mapping,
-         instead of the poly index -> tessface origindex one we generated
-         with cdDM_recalcTesselation2*/
+       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);
+
        CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_ASSIGN, 
                face_nors, dm->numFaceData);
 }
 
-#if 0
+#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
 
  */
@@ -2240,96 +2241,20 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
        BLI_array_declare(mpoly);
        MLoop *ml, *mloop = NULL;
        BLI_array_declare(mloop);
-       SmallHash _hash, *hash=&_hash;
-       SmallHash _hash2, *hash2=&_hash2;
+       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;
        
-       BLI_smallhash_init(hash);
-       BLI_smallhash_init(hash2);
-
-#if 0
-       /*split off ngon faces with merges in them*/
-       mp = cddm->mpoly;
-       for (i=0; i<dm->numPolyData; i++, mp++) {
-               ml = cddm->mloop + mp->loopstart;
-               for (j=0; j<mp->totloop; j++, ml++) {
-                       MLoop *ml2 = NULL;
-                       int k, k1, a;
-                       
-                       if (ml->v == -1)
-                               continue;
-                       
-                       for (k1=0; k1<mp->totloop; k1++) {
-                               k = (j + k1) % mp->totloop;
-                               ml2 = cddm->mloop + mp->loopstart + k;
-                               
-                               if (ml == ml2 || ml2->v == -1)
-                                       continue;
-                               
-                               if (vtargetmap[ml->v] == ml2->v || vtargetmap[ml2->v] == ml->v) {
-                                       MLoop *ml3;
-                                       MPoly *mp2;
-                                       int s, e, l, tot;
-                                       
-                                       if (k < j) 
-                                               SWAP(int, k, j);
-                                       
-                                       s = j; e = k; tot = 0;
-                                       l = BLI_array_count(mloop);
-                                       ml3 = cddm->mloop + mp->loopstart + s;
-                                       for (a=s; a<e; a++, ml3++) {
-                                               if (ml3->v == -1)
-                                                       continue;
-                                               
-                                               BLI_smallhash_insert(hash, dm->numLoopData + BLI_array_count(mloop), SET_INT_IN_POINTER(mp->loopstart + a - s));
-                                               BLI_array_append(mloop, *ml3);
-                                               
-                                               ml3->v = -1;
-                                               ml3->e = -1;
-                                               tot++;
-                                       }
-                                       
-                                       if (!tot)
-                                               continue;
-                                       
-                                       BLI_smallhash_insert(hash2, dm->numPolyData + BLI_array_count(mpoly), SET_INT_IN_POINTER(i));
-       
-                                       mp2 = BLI_array_append(mpoly, *mp);
-                                       mp2->loopstart = l + dm->numLoopData;
-                                       mp2->totloop = tot;
-                               }
-                       }
-               }
-       }
-
-       ml = MEM_callocN(sizeof(MLoop)*(dm->numLoopData + BLI_array_count(mloop)), "merge mloop");
-       mp = MEM_callocN(sizeof(MPoly)*(dm->numPolyData + BLI_array_count(mloop)), "merge mpoly");
-       
-       memcpy(ml, cddm->mloop, sizeof(MLoop)*dm->numLoopData);
-       memcpy(mp, cddm->mpoly, sizeof(MPoly)*dm->numPolyData);
-       
-       cddm->mloop = ml; cddm->mpoly = mp;
-       
-       memcpy(cddm->mloop+dm->numLoopData, mloop, sizeof(MLoop)*BLI_array_count(mloop));
-       memcpy(cddm->mpoly+dm->numPolyData, mpoly, sizeof(MPoly)*BLI_array_count(mpoly));
-       
-       totloop = dm->numLoopData + BLI_array_count(mloop);
-       totpoly = dm->numPolyData + BLI_array_count(mpoly);
-       
-       BLI_array_empty(mloop);
-       BLI_array_empty(mpoly);
-#else
        totloop = dm->numLoopData;
        totpoly = dm->numPolyData;
-#endif
        
        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++) {
@@ -2340,6 +2265,13 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
                }
        }
        
+       /*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;
@@ -2347,27 +2279,40 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
                if (ml->v == -1)
                        continue;
                
-               if (vtargetmap[ml->v] != -1) {
-                       me = &cddm->medge[ml->e];
-                       if (me->v1 == ml->v)
-                               me->v1 = vtargetmap[ml->v];
-                       else
-                               me->v2 = vtargetmap[ml->v];
-                       
+               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++) {
-               if (me->v1 == me->v2)
+               int v1, v2;
+               
+               if (me->v1 == me->v2) {
+                       newe[i] = -1;
                        continue;
+               }
                
-               BLI_array_append(olde, i);
-               newe[i] = c++;
-               BLI_array_append(medge, *me);
+               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;
@@ -2383,9 +2328,9 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
                        
                        me = cddm->medge + ml->e;
                        if (me->v1 != me->v2) {
-                               BLI_array_append(oldl, j);
+                               BLI_array_append(oldl, j+mp->loopstart);
                                BLI_array_append(mloop, *ml);
-                               newl[c] = BLI_array_count(mloop)-1;
+                               newl[j+mp->loopstart] = BLI_array_count(mloop)-1;
                                c++;
                        }
                }
@@ -2401,71 +2346,50 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
        }
        
        /*create new cddm*/     
-       cddm2 = (CDDerivedMesh*) CDDM_new(BLI_array_count(mvert), BLI_array_count(medge), 0, BLI_array_count(mloop), BLI_array_count(mpoly));
-       
-       /*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);
-       mvert = cddm2->mvert; medge = cddm2->medge; mloop = cddm2->mloop; mpoly = cddm2->mpoly;
+       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 = cddm2->medge;
+       me = medge;
        for (i=0; i<cddm2->dm.numEdgeData; i++, me++) {
-               MEdge cpy;
-               
-               me->v1 = newv[me->v1];
-               me->v2 = newv[me->v2];
+               if (newv[me->v1] != -1)
+                       me->v1 = newv[me->v1];
+               if (newv[me->v2] != -1)
+                       me->v2 = newv[me->v2];
                
-               cpy = *me;
                CustomData_copy_data(&dm->edgeData, &cddm2->dm.edgeData, olde[i], i, 1);
-               *me = cpy;
        }
        
        /*update loop indices and copy customdata*/
-       ml = cddm2->mloop;
+       ml = mloop;
        for (i=0; i<cddm2->dm.numLoopData; i++, ml++) {
-               MLoop cpy;
-               
-               ml->e = newe[ml->e];
-               ml->v = newv[ml->v];
+               if (newe[ml->e] != -1)
+                       ml->e = newe[ml->e];
+               if (newv[ml->v] != -1)
+                       ml->v = newv[ml->v];
                        
-               cpy = *ml;
-               
-               if (oldl[i] >= dm->numLoopData)
-                       oldl[i] = GET_INT_FROM_POINTER(BLI_smallhash_lookup(hash, (intptr_t)oldl[i]));
-
                CustomData_copy_data(&dm->loopData, &cddm2->dm.loopData, oldl[i], i, 1);
-               *ml = cpy;
        }
        
        /*copy vertex customdata*/      
-       mv = cddm2->mvert;
+       mv = mvert;
        for (i=0; i<cddm2->dm.numVertData; i++, mv++) {
-               MVert cpy = *mv;
-               
                CustomData_copy_data(&dm->vertData, &cddm2->dm.vertData, oldv[i], i, 1);
-               *mv = cpy;
        }
        
        /*copy poly customdata*/
-       mp = cddm2->mpoly;
+       mp = mpoly;
        for (i=0; i<cddm2->dm.numPolyData; i++, mp++) {
-               MPoly cpy = *mp;
-               
-               if (oldl[i] >= dm->numPolyData)
-                       oldl[i] = GET_INT_FROM_POINTER(BLI_smallhash_lookup(hash, (intptr_t)oldl[i]));
-
                CustomData_copy_data(&dm->polyData, &cddm2->dm.polyData, oldp[i], i, 1);
-               *mp = cpy;
        }
        
-       /*eek! not sure what to do with ORIGINDEX stuff here!!*/        
-       cddm2->dm.numFaceData = mesh_recalcTesselation(&cddm2->dm.faceData, &cddm2->dm.loopData, &cddm2->dm.polyData, cddm2->mvert, 0, cddm2->dm.numLoopData, cddm2->dm.numPolyData, 1, 0);
-       cddm2->mface = CustomData_get_layer(&cddm->dm.faceData, CD_MFACE);
+       /*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); 
@@ -2481,10 +2405,10 @@ DerivedMesh *CDDM_merge_verts(DerivedMesh *dm, int *vtargetmap)
                MEM_freeN(oldl); 
        if (oldp) 
                MEM_freeN(oldp);
-       
-       BLI_smallhash_release(hash);
-       BLI_smallhash_release(hash2);
-       
+       if (ehash)
+               BLI_edgehash_free(ehash, NULL);
+
+       /*free old derivedmesh*/
        dm->needsFree = 1;
        dm->release(dm);
        
@@ -2679,6 +2603,16 @@ 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*/
@@ -2760,7 +2694,10 @@ void CDDM_tessfaces_to_faces(DerivedMesh *dm)
 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;
 }
 
@@ -2768,6 +2705,9 @@ 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;
 }
 
@@ -2775,5 +2715,8 @@ 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;
 }