Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / source / blender / blenkernel / intern / cdderivedmesh.c
index ca81e216006b72316e6e2f9e9e33f54cac4c0859..d130c7b40ac56fee8f6d0028bbd23072c598616c 100644 (file)
@@ -1,52 +1,53 @@
 /*
-* $Id$
-*
-* ***** BEGIN GPL LICENSE BLOCK *****
-*
-* This program is free software; you can redistribute it and/or
-* modify it under the terms of the GNU General Public License
-* as published by the Free Software Foundation; either version 2
-* of the License, or (at your option) any later version.
-*
-* This program is distributed in the hope that it will be useful,
-* but WITHOUT ANY WARRANTY; without even the implied warranty of
-* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-* GNU General Public License for more details.
-*
-* You should have received a copy of the GNU General Public License
-* along with this program; if not, write to the Free Software  Foundation,
-* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
-*
-* The Original Code is Copyright (C) 2006 Blender Foundation.
-* All rights reserved.
-*
-* The Original Code is: all of this file.
-*
-* Contributor(s): Ben Batt <benbatt@gmail.com>
-*
-* ***** END GPL LICENSE BLOCK *****
-*
-* Implementation of CDDerivedMesh.
-*
-* BKE_cdderivedmesh.h contains the function prototypes for this file.
-*
-*/ 
-
-/* TODO maybe BIF_gl.h should include string.h? */
-#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"
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software  Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2006 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): Ben Batt <benbatt@gmail.com>
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implementation of CDDerivedMesh.
+ *
+ * BKE_cdderivedmesh.h contains the function prototypes for this file.
+ *
+ */
+
+/** \file blender/blenkernel/intern/cdderivedmesh.c
+ *  \ingroup bke
+ */
+
+#include "GL/glew.h"
 
 #include "BLI_blenlib.h"
 #include "BLI_edgehash.h"
 #include "BLI_editVert.h"
 #include "BLI_math.h"
 #include "BLI_pbvh.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"
@@ -75,6 +76,7 @@ typedef struct {
        /* Cached */
        struct PBVH *pbvh;
        int pbvh_draw;
+
        /* Mesh connectivity */
        struct ListBase *fmap;
        struct IndexNode *fmap_mem;
@@ -165,11 +167,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)
@@ -189,9 +187,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;
 }
@@ -199,7 +209,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;
@@ -217,15 +226,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;
@@ -241,8 +279,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();
        }
@@ -289,7 +329,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 {
@@ -418,7 +458,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;
@@ -504,9 +544,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( );
@@ -535,8 +576,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" );
@@ -550,26 +594,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 );
                                }
                        }
@@ -583,13 +627,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);
                        }
                }
@@ -601,7 +645,7 @@ 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 (*drawParams)(MTFace *tface, int has_mcol, int matnr),
                           int (*drawParamsMapped)(void *userData, int index),
                           void *userData) 
 {
@@ -617,6 +661,8 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
        if(!mcol)
                mcol = dm->getFaceDataArray(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++) {
@@ -625,7 +671,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) {
@@ -697,7 +743,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 ) {
@@ -708,9 +754,10 @@ static void cdDM_drawFacesTex_common(DerivedMesh *dm,
                                unsigned char *colors = MEM_mallocN(dm->getNumFaces(dm)*4*3*sizeof(unsigned char), "cdDM_drawFacesTex_common");
                                for( i=0; i < dm->getNumFaces(dm); i++ ) {
                                        for( j=0; j < 4; j++ ) {
-                                               colors[i*12+j*3] = col[i*4+j].r;
+                                               /* bgr -> rgb is intentional (and stupid), but how its stored internally */
+                                               colors[i*12+j*3] = col[i*4+j].b;
                                                colors[i*12+j*3+1] = col[i*4+j].g;
-                                               colors[i*12+j*3+2] = col[i*4+j].b;
+                                               colors[i*12+j*3+2] = col[i*4+j].r;
                                        }
                                }
                                GPU_color3_upload(dm,colors);
@@ -724,17 +771,32 @@ 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) {
-                                       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) {
                                                orig = index[actualFace];
+                                               if(orig == ORIGINDEX_NONE) continue;
                                                if(drawParamsMapped)
                                                        flag = drawParamsMapped(userData, orig);
                                        }
@@ -756,13 +818,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);
                                }
                        }
                }
@@ -772,12 +834,13 @@ 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_mcol, 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)
+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;
@@ -792,22 +855,24 @@ static void cdDM_drawMappedFaces(DerivedMesh *dm, int (*setDrawOptions)(void *us
        if(!mc)
                mc = DM_get_face_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)
@@ -870,36 +935,72 @@ 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];
+
+                                               if(orig==ORIGINDEX_NONE || next_orig==ORIGINDEX_NONE) {
+                                                       flush= 1;
+                                               } else {
+                                                       /* 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;
+                                               }
+                                       }
 
-                               /* 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(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;
+                                       }
                                }
                        }
+
                        glShadeModel(GL_FLAT);
                }
                GPU_buffer_unbind();
@@ -911,6 +1012,50 @@ 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;
@@ -918,27 +1063,26 @@ 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);
+       /* MTFace *tf = dm->getFaceDataArray(dm, CD_MTFACE); */ /* UNUSED */
        float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
-       int a, b, dodraw, smoothnormal, matnr, new_matnr;
-       int transp, new_transp, orig_transp;
+       int a, b, dodraw, matnr, new_matnr;
        int orig, *index = dm->getFaceDataArray(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) {
@@ -957,30 +1101,16 @@ 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;
                        }
 
-                       if(tf) {
-                               new_transp = tf[a].transp;
-
-                               if(new_transp != transp) {
-                                       glEnd();
-
-                                       if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
-                                               GPU_set_material_blend_mode(orig_transp);
-                                       else
-                                               GPU_set_material_blend_mode(new_transp);
-                                       transp = new_transp;
-
-                                       glBegin(GL_QUADS);
-                               }
-                       }
-
-                       smoothnormal = (mface->flag & ME_SMOOTH);
-
                        if(!smoothnormal) {
                                if(nors) {
                                        glNormal3fv(nors[a]);
@@ -997,45 +1127,22 @@ 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];                                                   \
-                       glVertexAttrib3fvARB(attribs.tang.glIndex, tang);                                               \
-               }                                                                                                                                                       \
-               if(smoothnormal)                                                                                                                        \
-                       glNormal3sv(mvert[index].no);                                                                                   \
-               glVertex3fv(mvert[index].co);                                                                                           \
-       }
+                       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);
 
-                       PASSVERT(mface->v1, 0);
-                       PASSVERT(mface->v2, 1);
-                       PASSVERT(mface->v3, 2);
                        if(mface->v4)
-                               PASSVERT(mface->v4, 3)
+                               cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v4, 3, smoothnormal);
                        else
-                               PASSVERT(mface->v3, 2)
-
-#undef PASSVERT
+                               cddm_draw_attrib_vertex(&attribs, mvert, a, mface->v3, 2, smoothnormal);
                }
                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 start = 0, numfaces = 0 /* , prevdraw = 0 */ /* UNUSED */, curface = 0;
                int i;
 
                MFace *mf = mface;
@@ -1046,9 +1153,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;
@@ -1070,16 +1177,16 @@ 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;
                                                        }
 
                                                }
                                        }
                                        numdata = 0;
                                        start = curface;
-                                       prevdraw = dodraw;
+                                       /* prevdraw = dodraw; */ /* UNUSED */
                                        dodraw = setMaterial(matnr = new_matnr, &gattribs);
                                        if(dodraw) {
                                                DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
@@ -1104,22 +1211,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;
                                                        }
@@ -1127,7 +1234,7 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                                else {
                                                        /* if the buffer was set, dont use it again.
                                                         * prevdraw was assumed true but didnt run so set to false - [#21036] */
-                                                       prevdraw= 0;
+                                                       /* prevdraw= 0; */ /* UNUSED */
                                                        buffer= NULL;
                                                }
                                        }
@@ -1136,33 +1243,6 @@ static void cdDM_drawMappedFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, vo
                                        continue;
                                }
 
-                               if(tf) {
-                                       new_transp = tf[a].transp;
-
-                                       if(new_transp != transp) {
-                                               numfaces = curface - start;
-                                               if( numfaces > 0 ) {
-                                                       if( dodraw ) {
-                                                               if( numdata != 0 ) {
-                                                                       GPU_buffer_unlock(buffer);
-                                                                       GPU_interleaved_attrib_setup(buffer,datatypes,numdata);
-                                                               }
-                                                               glDrawArrays(GL_TRIANGLES,start*3,(curface-start)*3);
-                                                               if( numdata != 0 ) {
-                                                                       varray = GPU_buffer_lock_stream(buffer);
-                                                               }
-                                                       }
-                                               }
-                                               start = curface;
-
-                                               if(new_transp == GPU_BLEND_SOLID && orig_transp != GPU_BLEND_SOLID)
-                                                       GPU_set_material_blend_mode(orig_transp);
-                                               else
-                                                       GPU_set_material_blend_mode(new_transp);
-                                               transp = new_transp;
-                                       }
-                               }
-                               
                                if( numdata != 0 ) {
                                        offset = 0;
                                        if(attribs.totorco) {
@@ -1194,13 +1274,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) {
@@ -1234,13 +1315,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++;
@@ -1258,7 +1340,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);
@@ -1269,6 +1351,85 @@ static void cdDM_drawFacesGLSL(DerivedMesh *dm, int (*setMaterial)(int, void *at
        dm->drawMappedFacesGLSL(dm, setMaterial, NULL, NULL);
 }
 
+static void cdDM_drawMappedFacesMat(DerivedMesh *dm,
+       void (*setMaterial)(void *userData, int, void *attribs),
+       int (*setFace)(void *userData, int index), void *userData)
+{
+       CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
+       GPUVertexAttribs gattribs;
+       DMVertexAttribs attribs;
+       MVert *mvert = cddm->mvert;
+       MFace *mf = cddm->mface;
+       float (*nors)[3] = dm->getFaceDataArray(dm, CD_NORMAL);
+       int a, matnr, new_matnr;
+       int orig, *index = dm->getFaceDataArray(dm, CD_ORIGINDEX);
+
+       cdDM_update_normals_from_pbvh(dm);
+
+       matnr = -1;
+
+       glShadeModel(GL_SMOOTH);
+
+       memset(&attribs, 0, sizeof(attribs));
+
+       glBegin(GL_QUADS);
+
+       for(a = 0; a < dm->numFaceData; a++, mf++) {
+               const int smoothnormal = (mf->flag & ME_SMOOTH);
+
+               /* material */
+               new_matnr = mf->mat_nr + 1;
+
+               if(new_matnr != matnr) {
+                       glEnd();
+
+                       setMaterial(userData, matnr = new_matnr, &gattribs);
+                       DM_vertex_attributes_from_gpu(dm, &gattribs, &attribs);
+
+                       glBegin(GL_QUADS);
+               }
+
+               /* skipping faces */
+               if(setFace) {
+                       orig = (index)? index[a]: a;
+
+                       if(orig != ORIGINDEX_NONE && !setFace(userData, orig))
+                               continue;
+               }
+
+               /* smooth normal */
+               if(!smoothnormal) {
+                       if(nors) {
+                               glNormal3fv(nors[a]);
+                       }
+                       else {
+                               /* TODO ideally a normal layer should always be available */
+                               float nor[3];
+
+                               if(mf->v4)
+                                       normal_quad_v3( nor,mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co, mvert[mf->v4].co);
+                               else
+                                       normal_tri_v3( nor,mvert[mf->v1].co, mvert[mf->v2].co, mvert[mf->v3].co);
+
+                               glNormal3fv(nor);
+                       }
+               }
+
+               /* vertices */
+               cddm_draw_attrib_vertex(&attribs, mvert, a, mf->v1, 0, smoothnormal);
+               cddm_draw_attrib_vertex(&attribs, mvert, a, mf->v2, 1, smoothnormal);
+               cddm_draw_attrib_vertex(&attribs, mvert, a, mf->v3, 2, smoothnormal);
+
+               if(mf->v4)
+                       cddm_draw_attrib_vertex(&attribs, mvert, a, mf->v4, 3, smoothnormal);
+               else
+                       cddm_draw_attrib_vertex(&attribs, mvert, a, mf->v3, 2, smoothnormal);
+       }
+       glEnd();
+
+       glShadeModel(GL_FLAT);
+}
+
 static void cdDM_drawMappedEdges(DerivedMesh *dm, int (*setDrawOptions)(void *userData, int index), void *userData)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*) dm;
@@ -1439,6 +1600,7 @@ static CDDerivedMesh *cdDM_create(const char *desc)
        dm->drawMappedFaces = cdDM_drawMappedFaces;
        dm->drawMappedFacesTex = cdDM_drawMappedFacesTex;
        dm->drawMappedFacesGLSL = cdDM_drawMappedFacesGLSL;
+       dm->drawMappedFacesMat = cdDM_drawMappedFacesMat;
 
        dm->foreachMappedVert = cdDM_foreachMappedVert;
        dm->foreachMappedEdge = cdDM_foreachMappedEdge;
@@ -1471,7 +1633,7 @@ DerivedMesh *CDDM_new(int numVerts, int numEdges, int numFaces)
        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;
@@ -1500,7 +1662,7 @@ DerivedMesh *CDDM_from_mesh(Mesh *mesh, Object *ob)
        return dm;
 }
 
-DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *me)
+DerivedMesh *CDDM_from_editmesh(EditMesh *em, Mesh *UNUSED(me))
 {
        DerivedMesh *dm = CDDM_new(BLI_countlist(&em->verts),
                                                           BLI_countlist(&em->edges),
@@ -1545,12 +1707,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;
@@ -1601,7 +1760,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)
@@ -1668,6 +1827,8 @@ DerivedMesh *CDDM_copy(DerivedMesh *source)
        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)
 {
@@ -1726,29 +1887,18 @@ void CDDM_apply_vert_normals(DerivedMesh *dm, short (*vertNormals)[3])
        cddm->mvert = vert;
 
        for(i = 0; i < dm->numVertData; ++i, ++vert)
-               VECCOPY(vert->no, vertNormals[i]);
+               copy_v3_v3_short(vert->no, vertNormals[i]);
 }
 
-/* adapted from mesh_calc_normals */
 void CDDM_calc_normals(DerivedMesh *dm)
 {
        CDDerivedMesh *cddm = (CDDerivedMesh*)dm;
-       float (*temp_nors)[3];
        float (*face_nors)[3];
-       int i;
-       int numVerts = dm->numVertData;
-       int numFaces = dm->numFaceData;
-       MFace *mf;
-       MVert *mv;
-
-       if(numVerts == 0) return;
 
-       temp_nors = MEM_callocN(numVerts * sizeof(*temp_nors),
-                                                       "CDDM_calc_normals temp_nors");
+       if(dm->numVertData == 0) return;
 
        /* we don't want to overwrite any referenced layers */
-       mv = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
-       cddm->mvert = mv;
+       cddm->mvert = CustomData_duplicate_referenced_layer(&dm->vertData, CD_MVERT);
 
        /* make a face normal layer if not present */
        face_nors = CustomData_get_layer(&dm->faceData, CD_NORMAL);
@@ -1756,34 +1906,8 @@ void CDDM_calc_normals(DerivedMesh *dm)
                face_nors = CustomData_add_layer(&dm->faceData, CD_NORMAL, CD_CALLOC,
                                                                                 NULL, dm->numFaceData);
 
-       /* calculate face normals and add to vertex normals */
-       mf = CDDM_get_faces(dm);
-       for(i = 0; i < numFaces; i++, mf++) {
-               float *f_no = face_nors[i];
-
-               if(mf->v4)
-                       normal_quad_v3( f_no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co, mv[mf->v4].co);
-               else
-                       normal_tri_v3( f_no,mv[mf->v1].co, mv[mf->v2].co, mv[mf->v3].co);
-               
-               add_v3_v3(temp_nors[mf->v1], f_no);
-               add_v3_v3(temp_nors[mf->v2], f_no);
-               add_v3_v3(temp_nors[mf->v3], f_no);
-               if(mf->v4)
-                       add_v3_v3(temp_nors[mf->v4], f_no);
-       }
-
-       /* normalize vertex normals and assign */
-       for(i = 0; i < numVerts; i++, mv++) {
-               float *no = temp_nors[i];
-               
-               if (normalize_v3(no) == 0.0)
-                       normalize_v3_v3(no, mv->co);
-
-               normal_float_to_short_v3(mv->no, no);
-       }
-       
-       MEM_freeN(temp_nors);
+       /* calculate face normals */
+       mesh_calc_normals(cddm->mvert, dm->numVertData, CDDM_get_faces(dm), dm->numFaceData, face_nors);
 }
 
 void CDDM_calc_edges(DerivedMesh *dm)