Update DerivedMesh for dynamic-topology sculpt mode
[blender.git] / source / blender / blenkernel / intern / DerivedMesh.c
index 5774dd7b1bacd28ed264b09deb0dbd8feebf4067..ec8d37e1ae36976bd48c7b2b0feecb5b71ea8533 100644 (file)
 #include "BLI_math.h"
 #include "BLI_memarena.h"
 #include "BLI_array.h"
-#include "BLI_pbvh.h"
 #include "BLI_utildefines.h"
 #include "BLI_linklist.h"
 
-#include "BLF_translation.h"
-
+#include "BKE_pbvh.h"
 #include "BKE_cdderivedmesh.h"
 #include "BKE_displist.h"
 #include "BKE_key.h"
 #include "BKE_modifier.h"
 #include "BKE_mesh.h"
 #include "BKE_object.h"
+#include "BKE_object_deform.h"
 #include "BKE_paint.h"
 #include "BKE_texture.h"
 #include "BKE_multires.h"
@@ -74,7 +73,7 @@
 static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm);
 #endif
 
-#include "BLO_sys_types.h" // for intptr_t support
+#include "BLO_sys_types.h" /* for intptr_t support */
 
 #include "GL/glew.h"
 
@@ -266,9 +265,11 @@ void DM_init_funcs(DerivedMesh *dm)
        dm->getVertData = DM_get_vert_data;
        dm->getEdgeData = DM_get_edge_data;
        dm->getTessFaceData = DM_get_tessface_data;
+       dm->getPolyData = DM_get_poly_data;
        dm->getVertDataArray = DM_get_vert_data_layer;
        dm->getEdgeDataArray = DM_get_edge_data_layer;
        dm->getTessFaceDataArray = DM_get_tessface_data_layer;
+       dm->getPolyDataArray = DM_get_poly_data_layer;
 
        bvhcache_init(&dm->bvhCache);
 }
@@ -288,6 +289,13 @@ void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
        dm->needsFree = 1;
        dm->auto_bump_scale = -1.0f;
        dm->dirty = 0;
+
+       /* don't use CustomData_reset(...); because we dont want to touch customdata */
+       fill_vn_i(dm->vertData.typemap, CD_NUMTYPES, -1);
+       fill_vn_i(dm->edgeData.typemap, CD_NUMTYPES, -1);
+       fill_vn_i(dm->faceData.typemap, CD_NUMTYPES, -1);
+       fill_vn_i(dm->loopData.typemap, CD_NUMTYPES, -1);
+       fill_vn_i(dm->polyData.typemap, CD_NUMTYPES, -1);
 }
 
 void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
@@ -383,8 +391,8 @@ void DM_ensure_tessface(DerivedMesh *dm)
                }
        }
 
-       else if (dm->dirty && DM_DIRTY_TESS_CDLAYERS) {
-               BLI_assert(CustomData_has_layer(&dm->faceData, CD_POLYINDEX));
+       else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
+               BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX) || numTessFaces == 0);
                DM_update_tessface_data(dm);
        }
 
@@ -408,7 +416,7 @@ void DM_update_tessface_data(DerivedMesh *dm)
        const int hasPCol = CustomData_has_layer(ldata, CD_PREVIEW_MLOOPCOL);
        const int hasOrigSpace = CustomData_has_layer(ldata, CD_ORIGSPACE_MLOOP);
 
-       int *polyindex = CustomData_get_layer(fdata, CD_POLYINDEX);
+       int *polyindex = CustomData_get_layer(fdata, CD_ORIGINDEX);
 
        int mf_idx,
            totface = dm->getNumTessFaces(dm),
@@ -426,7 +434,7 @@ void DM_update_tessface_data(DerivedMesh *dm)
 
                /* Find out loop indices. */
                /* XXX Is there a better way to do this? */
-               /* NOTE: This assumes tessface are valid and in sync with loop/poly Else, most likely, segfault! */
+               /* NOTE: This assumes tessface are valid and in sync with loop/poly... Else, most likely, segfault! */
                for (i = mp[polyindex[mf_idx]].loopstart, not_done = mf_len; not_done; i++) {
                        MLoop *tml = &ml[i];
                        if (tml->v == mf->v1) {
@@ -465,11 +473,11 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
        int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly;
        int did_shapekeys = 0;
        
-       memset(&tmp.vdata, 0, sizeof(tmp.vdata));
-       memset(&tmp.edata, 0, sizeof(tmp.edata));
-       memset(&tmp.fdata, 0, sizeof(tmp.fdata));
-       memset(&tmp.ldata, 0, sizeof(tmp.ldata));
-       memset(&tmp.pdata, 0, sizeof(tmp.pdata));
+       CustomData_reset(&tmp.vdata);
+       CustomData_reset(&tmp.edata);
+       CustomData_reset(&tmp.fdata);
+       CustomData_reset(&tmp.ldata);
+       CustomData_reset(&tmp.pdata);
 
        totvert = tmp.totvert = dm->getNumVerts(dm);
        totedge = tmp.totedge = dm->getNumEdges(dm);
@@ -498,7 +506,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
                        }
                }
                else {
-                       /*if no object, set to INT_MAX so we don't mess up any shapekey layers*/
+                       /* if no object, set to INT_MAX so we don't mess up any shapekey layers */
                        uid = INT_MAX;
                }
 
@@ -541,7 +549,7 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
        CustomData_free(&me->pdata, me->totpoly);
 
        /* ok, this should now use new CD shapekey data,
-        * which shouuld be fed through the modifier
+        * which should be fed through the modifier
         * stack*/
        if (tmp.totvert != me->totvert && !did_shapekeys && me->key) {
                printf("%s: YEEK! this should be recoded! Shape key loss!: ID '%s'\n", __func__, tmp.id.name);
@@ -577,6 +585,13 @@ void DM_set_only_copy(DerivedMesh *dm, CustomDataMask mask)
        CustomData_set_only_copy(&dm->vertData, mask);
        CustomData_set_only_copy(&dm->edgeData, mask);
        CustomData_set_only_copy(&dm->faceData, mask);
+       /* this wasn't in 2.63 and is disabled for 2.64 because it gives problems with
+        * weight paint mode when there are modifiers applied, needs further investigation,
+        * see replies to r50969, Campbell */
+#if 0
+       CustomData_set_only_copy(&dm->loopData, mask);
+       CustomData_set_only_copy(&dm->polyData, mask);
+#endif
 }
 
 void DM_add_vert_layer(DerivedMesh *dm, int type, int alloctype, void *layer)
@@ -619,6 +634,12 @@ void *DM_get_tessface_data(DerivedMesh *dm, int index, int type)
        return CustomData_get(&dm->faceData, index, type);
 }
 
+void *DM_get_poly_data(DerivedMesh *dm, int index, int type)
+{
+       return CustomData_get(&dm->polyData, index, type);
+}
+
+
 void *DM_get_vert_data_layer(DerivedMesh *dm, int type)
 {
        if (type == CD_MVERT)
@@ -807,7 +828,7 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob,
        if (mti->isDisabled && mti->isDisabled(md, 0)) return NULL;
        
        if (build_shapekey_layers && me->key && (kb = BLI_findlink(&me->key->block, ob->shapenr - 1))) {
-               key_to_mesh(kb, me);
+               BKE_key_convert_to_mesh(kb, me);
        }
        
        if (mti->type == eModifierTypeType_OnlyDeform) {
@@ -836,30 +857,27 @@ DerivedMesh *mesh_create_derived_for_modifier(Scene *scene, Object *ob,
        return dm;
 }
 
-static float *get_editbmesh_orco_verts(BMEditMesh *em)
+static float (*get_editbmesh_orco_verts(BMEditMesh *em))[3]
 {
        BMIter iter;
        BMVert *eve;
-       float *orco;
-       int a, totvert;
+       float (*orco)[3];
+       int i;
 
        /* these may not really be the orco's, but it's only for preview.
         * could be solver better once, but isn't simple */
-
-       totvert = em->bm->totvert;
        
-       orco = MEM_mallocN(sizeof(float) * 3 * totvert, "BMEditMesh Orco");
+       orco = MEM_mallocN(sizeof(float) * 3 * em->bm->totvert, "BMEditMesh Orco");
 
-       eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
-       for (a = 0; eve; eve = BM_iter_step(&iter), a += 3) {
-               copy_v3_v3(orco + a, eve->co);
+       BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
+               copy_v3_v3(orco[i], eve->co);
        }
        
        return orco;
 }
 
 /* orco custom data layer */
-static void *get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free)
+static float (*get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free))[3]
 {
        *free = 0;
 
@@ -868,16 +886,16 @@ static void *get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free
                *free = 1;
 
                if (em)
-                       return (float(*)[3])get_editbmesh_orco_verts(em);
+                       return get_editbmesh_orco_verts(em);
                else
-                       return (float(*)[3])BKE_mesh_orco_verts_get(ob);
+                       return BKE_mesh_orco_verts_get(ob);
        }
        else if (layer == CD_CLOTH_ORCO) {
                /* apply shape key for cloth, this should really be solved
                 * by a more flexible customdata system, but not simple */
                if (!em) {
                        ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
-                       KeyBlock *kb = key_get_keyblock(ob_get_key(ob), clmd->sim_parms->shapekey_rest);
+                       KeyBlock *kb = BKE_keyblock_from_key(BKE_key_from_object(ob), clmd->sim_parms->shapekey_rest);
 
                        if (kb->data)
                                return kb->data;
@@ -895,7 +913,7 @@ static DerivedMesh *create_orco_dm(Object *ob, Mesh *me, BMEditMesh *em, int lay
        float (*orco)[3];
        int free;
 
-       if (em) dm = CDDM_from_BMEditMesh(em, me, FALSE, FALSE);
+       if (em) dm = CDDM_from_editbmesh(em, FALSE, FALSE);
        else dm = CDDM_from_mesh(me, ob);
 
        orco = get_orco_coords_dm(ob, em, layer, &free);
@@ -956,22 +974,22 @@ void weight_to_rgb(float r_rgb[3], const float weight)
 {
        const float blend = ((weight / 2.0f) + 0.5f);
 
-       if (weight <= 0.25f) {    // blue->cyan
+       if (weight <= 0.25f) {    /* blue->cyan */
                r_rgb[0] = 0.0f;
                r_rgb[1] = blend * weight * 4.0f;
                r_rgb[2] = blend;
        }
-       else if (weight <= 0.50f) {   // cyan->green
+       else if (weight <= 0.50f) {  /* cyan->green */
                r_rgb[0] = 0.0f;
                r_rgb[1] = blend;
                r_rgb[2] = blend * (1.0f - ((weight - 0.25f) * 4.0f));
        }
-       else if (weight <= 0.75f) { // green->yellow
+       else if (weight <= 0.75f) {  /* green->yellow */
                r_rgb[0] = blend * ((weight - 0.50f) * 4.0f);
                r_rgb[1] = blend;
                r_rgb[2] = 0.0f;
        }
-       else if (weight <= 1.0f) { // yellow->red
+       else if (weight <= 1.0f) {  /* yellow->red */
                r_rgb[0] = blend;
                r_rgb[1] = blend * (1.0f - ((weight - 0.75f) * 4.0f));
                r_rgb[2] = 0.0f;
@@ -1015,14 +1033,14 @@ static void calc_weightpaint_vert_color(
         unsigned char r_col[4],
         MDeformVert *dv, ColorBand *coba,
         const int defbase_tot, const int defbase_act,
-        const char *dg_flags,
-        const int selected, const int draw_flag)
+        const char *defbase_sel, const int defbase_sel_tot,
+        const int draw_flag)
 {
        float input = 0.0f;
        
        int make_black = FALSE;
 
-       if ((selected > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
+       if ((defbase_sel_tot > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
                int was_a_nonzero = FALSE;
                unsigned int i;
 
@@ -1031,7 +1049,7 @@ static void calc_weightpaint_vert_color(
                        /* in multipaint, get the average if auto normalize is inactive
                         * get the sum if it is active */
                        if (dw->def_nr < defbase_tot) {
-                               if (dg_flags[dw->def_nr]) {
+                               if (defbase_sel[dw->def_nr]) {
                                        if (dw->weight) {
                                                input += dw->weight;
                                                was_a_nonzero = TRUE;
@@ -1045,7 +1063,7 @@ static void calc_weightpaint_vert_color(
                        make_black = TRUE;
                }
                else if ((draw_flag & CALC_WP_AUTO_NORMALIZE) == FALSE) {
-                       input /= selected; /* get the average */
+                       input /= defbase_sel_tot; /* get the average */
                }
        }
        else {
@@ -1054,10 +1072,10 @@ static void calc_weightpaint_vert_color(
        }
 
        if (make_black) { /* TODO, theme color */
-               r_col[3] = 0;
+               r_col[3] = 255;
                r_col[2] = 0;
                r_col[1] = 0;
-               r_col[0] = 255;
+               r_col[0] = 0;
        }
        else {
                CLAMP(input, 0.0f, 1.0f);
@@ -1090,14 +1108,21 @@ static unsigned char *calc_weightpaint_vert_array(Object *ob, DerivedMesh *dm, i
                /* variables for multipaint */
                const int defbase_tot = BLI_countlist(&ob->defbase);
                const int defbase_act = ob->actdef - 1;
-               char *dg_flags = MEM_mallocN(defbase_tot * sizeof(char), __func__);
-               const int selected = get_selected_defgroups(ob, dg_flags, defbase_tot);
+
+               int defbase_sel_tot = 0;
+               char *defbase_sel = NULL;
+
+               if (draw_flag & CALC_WP_MULTIPAINT) {
+                       defbase_sel = BKE_objdef_selected_get(ob, defbase_tot, &defbase_sel_tot);
+               }
 
                for (i = numVerts; i != 0; i--, wc += 4, dv++) {
-                       calc_weightpaint_vert_color(wc, dv, coba, defbase_tot, defbase_act, dg_flags, selected, draw_flag);
+                       calc_weightpaint_vert_color(wc, dv, coba, defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag);
                }
 
-               MEM_freeN(dg_flags);
+               if (defbase_sel) {
+                       MEM_freeN(defbase_sel);
+               }
        }
        else {
                int col_i;
@@ -1131,119 +1156,64 @@ void DM_update_weight_mcol(Object *ob, DerivedMesh *dm, int const draw_flag,
        ColorBand *coba = stored_cb; /* warning, not a local var */
 
        unsigned char *wtcol_v;
-#if 0 /* See coment below. */
-       unsigned char *wtcol_f = dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL);
-#endif
        unsigned char(*wtcol_l)[4] = CustomData_get_layer(dm->getLoopDataLayout(dm), CD_PREVIEW_MLOOPCOL);
-#if 0 /* See coment below. */
-       MFace *mf = dm->getTessFaceArray(dm);
-#endif
        MLoop *mloop = dm->getLoopArray(dm), *ml;
        MPoly *mp = dm->getPolyArray(dm);
-#if 0
-       int numFaces = dm->getNumTessFaces(dm);
-#endif
        int numVerts = dm->getNumVerts(dm);
        int totloop;
        int i, j;
 
-#if 0 /* See comment below */
-         /* If no CD_PREVIEW_MCOL existed yet, add a new one! */
-       if (!wtcol_f)
-               wtcol_f = CustomData_add_layer(&dm->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
-
-       if (wtcol_f) {
-               unsigned char *wtcol_f_step = wtcol_f;
-# else
-#if 0
-       /* XXX We have to create a CD_PREVIEW_MCOL, else it might sigsev (after a SubSurf mod, eg)... */
-       if (!dm->getTessFaceDataArray(dm, CD_PREVIEW_MCOL))
-               CustomData_add_layer(&dm->faceData, CD_PREVIEW_MCOL, CD_CALLOC, NULL, numFaces);
-#endif
-
-       {
-#endif
-
-               /* Weights are given by caller. */
-               if (weights) {
-                       float *w = weights;
-                       /* If indices is not NULL, it means we do not have weights for all vertices,
-                        * so we must create them (and set them to zero)... */
-                       if (indices) {
-                               w = MEM_callocN(sizeof(float) * numVerts, "Temp weight array DM_update_weight_mcol");
-                               i = num;
-                               while (i--)
-                                       w[indices[i]] = weights[i];
-                       }
-
-                       /* Convert float weights to colors. */
-                       wtcol_v = calc_colors_from_weights_array(numVerts, w);
-
-                       if (indices)
-                               MEM_freeN(w);
+       /* Weights are given by caller. */
+       if (weights) {
+               float *w = weights;
+               /* If indices is not NULL, it means we do not have weights for all vertices,
+                * so we must create them (and set them to zero)... */
+               if (indices) {
+                       w = MEM_callocN(sizeof(float) * numVerts, "Temp weight array DM_update_weight_mcol");
+                       i = num;
+                       while (i--)
+                               w[indices[i]] = weights[i];
                }
 
-               /* No weights given, take them from active vgroup(s). */
-               else
-                       wtcol_v = calc_weightpaint_vert_array(ob, dm, draw_flag, coba);
+               /* Convert float weights to colors. */
+               wtcol_v = calc_colors_from_weights_array(numVerts, w);
 
-               /* Now copy colors in all face verts. */
-               /*first add colors to the tessellation faces*/
-               /* XXX Why update that layer? We have to update WEIGHT_MLOOPCOL anyway, 
-                *     and tessellation recreates mface layers from mloop/mpoly ones, so no
-                *     need to fill WEIGHT_MCOL here. */
-#if 0
-               for (i = 0; i < numFaces; i++, mf++, wtcol_f_step += (4 * 4)) {
-                       /*origindex being NULL means we're operating on original mesh data*/
-#if 0
-                       unsigned int fidx = mf->v4 ? 3 : 2;
-
-#else   /* better zero out triangles 4th component. else valgrind complains when the buffer's copied */
-                       unsigned int fidx;
-                       if (mf->v4) {
-                               fidx = 3;
-                       }
-                       else {
-                               fidx = 2;
-                               *(int *)(&wtcol_f_step[3 * 4]) = 0;
-                       }
-#endif
+               if (indices)
+                       MEM_freeN(w);
+       }
 
-                       do {
-                               copy_v4_v4_char((char *)&wtcol_f_step[fidx * 4],
-                                               (char *)&wtcol_v[4 * (*(&mf->v1 + fidx))]);
-                       } while (fidx--);
-               }
-#endif
-               /*now add to loops, so the data can be passed through the modifier stack*/
-               /* If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
-               if (!wtcol_l) {
-                       BLI_array_declare(wtcol_l);
-                       totloop = 0;
-                       for (i = 0; i < dm->numPolyData; i++, mp++) {
-                               ml = mloop + mp->loopstart;
-
-                               BLI_array_grow_items(wtcol_l, mp->totloop);
-                               for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
-                                       copy_v4_v4_char((char *)&wtcol_l[totloop],
-                                                       (char *)&wtcol_v[4 * ml->v]);
-                               }
+       /* No weights given, take them from active vgroup(s). */
+       else
+               wtcol_v = calc_weightpaint_vert_array(ob, dm, draw_flag, coba);
+
+       /* now add to loops, so the data can be passed through the modifier stack */
+       /* If no CD_PREVIEW_MLOOPCOL existed yet, we have to add a new one! */
+       if (!wtcol_l) {
+               BLI_array_declare(wtcol_l);
+               totloop = 0;
+               for (i = 0; i < dm->numPolyData; i++, mp++) {
+                       ml = mloop + mp->loopstart;
+
+                       BLI_array_grow_items(wtcol_l, mp->totloop);
+                       for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
+                               copy_v4_v4_char((char *)&wtcol_l[totloop],
+                                               (char *)&wtcol_v[4 * ml->v]);
                        }
-                       CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, totloop);
                }
-               else {
-                       totloop = 0;
-                       for (i = 0; i < dm->numPolyData; i++, mp++) {
-                               ml = mloop + mp->loopstart;
+               CustomData_add_layer(&dm->loopData, CD_PREVIEW_MLOOPCOL, CD_ASSIGN, wtcol_l, totloop);
+       }
+       else {
+               totloop = 0;
+               for (i = 0; i < dm->numPolyData; i++, mp++) {
+                       ml = mloop + mp->loopstart;
 
-                               for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
-                                       copy_v4_v4_char((char *)&wtcol_l[totloop],
-                                                       (char *)&wtcol_v[4 * ml->v]);
-                               }
+                       for (j = 0; j < mp->totloop; j++, ml++, totloop++) {
+                               copy_v4_v4_char((char *)&wtcol_l[totloop],
+                                               (char *)&wtcol_v[4 * ml->v]);
                        }
                }
-               MEM_freeN(wtcol_v);
        }
+       MEM_freeN(wtcol_v);
 
        dm->dirty |= DM_DIRTY_TESS_CDLAYERS;
 }
@@ -1255,7 +1225,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape
        int i, j, tot;
        
        if (!me->key)
-               return; 
+               return;
        
        tot = CustomData_number_of_layers(&dm->vertData, CD_SHAPEKEY);
        for (i = 0; i < tot; i++) {
@@ -1268,7 +1238,7 @@ static void shapekey_layers_to_keyblocks(DerivedMesh *dm, Mesh *me, int actshape
                }
                
                if (!kb) {
-                       kb = add_keyblock(me->key, layer->name);
+                       kb = BKE_keyblock_add(me->key, layer->name);
                        kb->uid = layer->uid;
                }
                
@@ -1360,7 +1330,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        ModifierData *firstmd, *md, *previewmd = NULL;
        CDMaskLink *datamasks, *curr;
        /* XXX Always copying POLYINDEX, else tessellated data are no more valid! */
-       CustomDataMask mask, nextmask, append_mask = CD_MASK_POLYINDEX;
+       CustomDataMask mask, nextmask, append_mask = CD_MASK_ORIGINDEX;
        float (*deformedVerts)[3] = NULL;
        DerivedMesh *dm = NULL, *orcodm, *clothorcodm, *finaldm;
        int numVerts = me->totvert;
@@ -1370,6 +1340,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        MultiresModifierData *mmd = get_multires_modifier(scene, ob, 0);
        int has_multires = mmd != NULL, multires_applied = 0;
        int sculpt_mode = ob->mode & OB_MODE_SCULPT && ob->sculpt;
+       int sculpt_dyntopo = (sculpt_mode && ob->sculpt->bm);
 
        const int draw_flag = ((scene->toolsettings->multipaint ? CALC_WP_MULTIPAINT : 0) |
                               (scene->toolsettings->auto_normalize ? CALC_WP_AUTO_NORMALIZE : 0));
@@ -1437,7 +1408,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        if (!modifier_isEnabled(scene, md, required_mode)) continue;
                        if (useDeform < 0 && mti->dependsOnTime && mti->dependsOnTime(md)) continue;
 
-                       if (mti->type == eModifierTypeType_OnlyDeform) {
+                       if (mti->type == eModifierTypeType_OnlyDeform && !sculpt_dyntopo) {
                                if (!deformedVerts)
                                        deformedVerts = mesh_getVertexCos(me, &numVerts);
 
@@ -1448,7 +1419,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        }
                        
                        /* grab modifiers until index i */
-                       if ((index >= 0) && (modifiers_indexInObject(ob, md) >= index))
+                       if ((index >= 0) && (BLI_findindex(&ob->modifiers, md) >= index))
                                break;
                }
 
@@ -1492,12 +1463,17 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                if (!modifier_isEnabled(scene, md, required_mode)) continue;
                if (mti->type == eModifierTypeType_OnlyDeform && !useDeform) continue;
                if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
-                       modifier_setError(md, "%s", TIP_("Modifier requires original data, bad stack position."));
+                       modifier_setError(md, "Modifier requires original data, bad stack position");
                        continue;
                }
-               if (sculpt_mode && (!has_multires || multires_applied)) {
+               if (sculpt_mode &&
+                       (!has_multires || multires_applied || ob->sculpt->bm))
+               {
                        int unsupported = 0;
 
+                       if (sculpt_dyntopo)
+                               unsupported = TRUE;
+
                        if (scene->toolsettings->sculpt->flags & SCULPT_ONLY_DEFORM)
                                unsupported |= mti->type != eModifierTypeType_OnlyDeform;
 
@@ -1505,7 +1481,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        unsupported |= multires_applied;
 
                        if (unsupported) {
-                               modifier_setError(md, "%s", TIP_("Not supported in sculpt mode."));
+                               modifier_setError(md, "Not supported in sculpt mode");
                                continue;
                        }
                }
@@ -1652,8 +1628,8 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
 
                                nextmask &= ~CD_MASK_ORCO;
                                DM_set_only_copy(orcodm, nextmask | CD_MASK_ORIGINDEX |
-                                                                (mti->requiredDataMask ?
-                                                                 mti->requiredDataMask(ob, md) : 0));
+                                                (mti->requiredDataMask ?
+                                                 mti->requiredDataMask(ob, md) : 0));
                                ndm = mti->applyModifier(md, ob, orcodm, app_flags & ~MOD_APPLY_USECACHE);
 
                                if (ndm) {
@@ -1693,7 +1669,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                isPrevDeform = (mti->type == eModifierTypeType_OnlyDeform);
 
                /* grab modifiers until index i */
-               if ((index >= 0) && (modifiers_indexInObject(ob, md) >= index))
+               if ((index >= 0) && (BLI_findindex(&ob->modifiers, md) >= index))
                        break;
 
                if (sculpt_mode && md->type == eModifierType_Multires)
@@ -1788,16 +1764,16 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
 #if 0
                if (num_tessface == 0 && finaldm->getNumTessFaces(finaldm) == 0)
 #else
-               if (finaldm->getNumTessFaces(finaldm) == 0) /* || !CustomData_has_layer(&finaldm->faceData, CD_POLYINDEX)) */
+               if (finaldm->getNumTessFaces(finaldm) == 0) /* || !CustomData_has_layer(&finaldm->faceData, CD_ORIGINDEX)) */
 #endif
                {
                        finaldm->recalcTessellation(finaldm);
                }
-               /* Even if tessellation is not needed, some modifiers migh have modified CD layers
+               /* Even if tessellation is not needed, some modifiers might have modified CD layers
                 * (like mloopcol or mloopuv), hence we have to update those. */
                else if (finaldm->dirty & DM_DIRTY_TESS_CDLAYERS) {
-                       /* A tessellation already exists, it should always have a CD_POLYINDEX. */
-                       BLI_assert(CustomData_has_layer(&finaldm->faceData, CD_POLYINDEX));
+                       /* A tessellation already exists, it should always have a CD_ORIGINDEX. */
+                       BLI_assert(CustomData_has_layer(&finaldm->faceData, CD_ORIGINDEX));
                        DM_update_tessface_data(finaldm);
                }
                /* Need to watch this, it can cause issues, see bug [#29338]             */
@@ -1842,17 +1818,18 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        BLI_linklist_free((LinkNode *)datamasks, NULL);
 }
 
-float (*editbmesh_get_vertex_cos(BMEditMesh * em, int *numVerts_r))[3]
+float (*editbmesh_get_vertex_cos(BMEditMesh *em, int *numVerts_r))[3]
 {
-       int i, numVerts = *numVerts_r = em->bm->totvert;
-       float (*cos)[3];
        BMIter iter;
        BMVert *eve;
+       float (*cos)[3];
+       int i;
+
+       *numVerts_r = em->bm->totvert;
 
-       cos = MEM_mallocN(sizeof(float) * 3 * numVerts, "vertexcos");
+       cos = MEM_mallocN(sizeof(float) * 3 * em->bm->totvert, "vertexcos");
 
-       eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
-       for (i = 0; eve; eve = BM_iter_step(&iter), i++) {
+       BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
                copy_v3_v3(cos[i], eve->co);
        }
 
@@ -1866,7 +1843,7 @@ int editbmesh_modifier_is_enabled(Scene *scene, ModifierData *md, DerivedMesh *d
 
        if (!modifier_isEnabled(scene, md, required_mode)) return 0;
        if ((mti->flags & eModifierTypeFlag_RequiresOriginalData) && dm) {
-               modifier_setError(md, "%s", TIP_("Modifier requires original data, bad stack position."));
+               modifier_setError(md, "Modifier requires original data, bad stack position");
                return 0;
        }
        
@@ -1961,7 +1938,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
 
                        }
                        else {
-                               dm = CDDM_from_BMEditMesh(em, ob->data, FALSE, FALSE);
+                               dm = CDDM_from_editbmesh(em, FALSE, FALSE);
 
                                if (deformedVerts) {
                                        CDDM_apply_vert_coords(dm, deformedVerts);
@@ -2052,12 +2029,18 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
        }
        else if (dm) {
                *final_r = dm;
-               (*final_r)->calcNormals(*final_r); /* BMESH_ONLY - BMESH_TODO. check if this is needed */
+
+               /* once we support skipping normal calculation with modifiers we may want to add this back */
+#if 0  // was added for bmesh but is not needed
+               (*final_r)->calcNormals(*final_r);
+#endif
        }
        else if (!deformedVerts && cage_r && *cage_r) {
                /* cage should already have up to date normals */
                *final_r = *cage_r;
-               (*final_r)->calcNormals(*final_r); /* BMESH_ONLY - BMESH_TODO. check if this is needed */
+#if 0  // was added for bmesh but is not needed
+               (*final_r)->calcNormals(*final_r);
+#endif
        }
        else {
                /* this is just a copy of the editmesh, no need to calc normals */
@@ -2073,7 +2056,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
        if ((*final_r)->type != DM_TYPE_EDITBMESH) {
                DM_ensure_tessface(*final_r);
        }
-       if (cage_r) {
+       if (cage_r && *cage_r) {
                if ((*cage_r)->type != DM_TYPE_EDITBMESH) {
                        if (*cage_r != *final_r) {
                                DM_ensure_tessface(*cage_r);
@@ -2133,6 +2116,8 @@ static void mesh_build_data(Scene *scene, Object *ob, CustomDataMask dataMask,
        /* weight paint and face select need original indices because of selection buffer drawing */
        int needMapping = (ob == obact) && (editing || (ob->mode & (OB_MODE_WEIGHT_PAINT | OB_MODE_VERTEX_PAINT | OB_MODE_TEXTURE_PAINT)));
 
+       BLI_assert(ob->type == OB_MESH);
+
        clear_mesh_caches(ob);
 
        mesh_calc_modifiers(scene, ob, NULL, &ob->derivedDeform,
@@ -2234,8 +2219,16 @@ DerivedMesh *mesh_create_derived_view(Scene *scene, Object *ob, CustomDataMask d
 {
        DerivedMesh *final;
 
+       /* XXX hack
+        * psys modifier updates particle state when called during dupli-list generation,
+        * which can lead to wrong transforms. This disables particle system modifier execution.
+        */
+       ob->transflag |= OB_NO_PSYS_UPDATE;
+
        mesh_calc_modifiers(scene, ob, NULL, NULL, &final, 0, 1, 0, dataMask, -1, 0, 0);
 
+       ob->transflag &= ~OB_NO_PSYS_UPDATE;
+
        return final;
 }
 
@@ -2323,20 +2316,19 @@ DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em)
 static void make_vertexcosnos__mapFunc(void *userData, int index, const float co[3],
                                        const float no_f[3], const short no_s[3])
 {
-       float *vec = userData;
-       
-       vec += 6 * index;
+       DMCoNo *co_no = &((DMCoNo *)userData)[index];
 
        /* check if we've been here before (normal should not be 0) */
-       if (vec[3] || vec[4] || vec[5]) return;
+       if (!is_zero_v3(co_no->no)) {
+               return;
+       }
 
-       copy_v3_v3(vec, co);
-       vec += 3;
+       copy_v3_v3(co_no->co, co);
        if (no_f) {
-               copy_v3_v3(vec, no_f);
+               copy_v3_v3(co_no->no, no_f);
        }
        else {
-               normal_short_to_float_v3(vec, no_s);
+               normal_short_to_float_v3(co_no->no, no_s);
        }
 }
 
@@ -2345,29 +2337,29 @@ static void make_vertexcosnos__mapFunc(void *userData, int index, const float co
 /* it stores the normals as floats, but they can still be scaled as shorts (32767 = unit) */
 /* in use now by vertex/weight paint and particle generating */
 
-float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
+DMCoNo *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
 {
        Mesh *me = ob->data;
        DerivedMesh *dm;
-       float *vertexcosnos;
+       DMCoNo *vertexcosnos;
        
        /* lets prevent crashing... */
        if (ob->type != OB_MESH || me->totvert == 0)
                return NULL;
        
        dm = mesh_get_derived_final(scene, ob, CD_MASK_BAREMESH | CD_MASK_ORIGINDEX);
-       vertexcosnos = MEM_callocN(6 * sizeof(float) * me->totvert, "vertexcosnos map");
+       vertexcosnos = MEM_callocN(sizeof(DMCoNo) * me->totvert, "vertexcosnos map");
        
        if (dm->foreachMappedVert) {
                dm->foreachMappedVert(dm, make_vertexcosnos__mapFunc, vertexcosnos);
        }
        else {
-               float *fp = vertexcosnos;
+               DMCoNo *v_co_no = vertexcosnos;
                int a;
                
-               for (a = 0; a < me->totvert; a++, fp += 6) {
-                       dm->getVertCo(dm, a, fp);
-                       dm->getVertNo(dm, a, fp + 3);
+               for (a = 0; a < me->totvert; a++, v_co_no++) {
+                       dm->getVertCo(dm, a, v_co_no->co);
+                       dm->getVertNo(dm, a, v_co_no->no);
                }
        }
        
@@ -2379,16 +2371,16 @@ float *mesh_get_mapped_verts_nors(Scene *scene, Object *ob)
 
 typedef struct {
        float *precomputedFaceNormals;
-       MTFace *mtface;     // texture coordinates
-       MFace *mface;       // indices
-       MVert *mvert;       // vertices & normals
+       MTFace *mtface;     /* texture coordinates */
+       MFace *mface;       /* indices */
+       MVert *mvert;       /* vertices & normals */
        float (*orco)[3];
-       float (*tangent)[4];    // destination
+       float (*tangent)[4];    /* destination */
        int numTessFaces;
 
 } SGLSLMeshToTangent;
 
-// interface
+/* interface */
 #include "mikktspace.h"
 
 static int GetNumFaces(const SMikkTSpaceContext *pContext)
@@ -2405,7 +2397,7 @@ static int GetNumVertsOfFace(const SMikkTSpaceContext *pContext, const int face_
 
 static void GetPosition(const SMikkTSpaceContext *pContext, float fPos[], const int face_num, const int vert_index)
 {
-       //assert(vert_index>=0 && vert_index<4);
+       //assert(vert_index >= 0 && vert_index < 4);
        SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
        const float *co = pMesh->mvert[(&pMesh->mface[face_num].v1)[vert_index]].co;
        copy_v3_v3(fPos, co);
@@ -2413,7 +2405,7 @@ static void GetPosition(const SMikkTSpaceContext *pContext, float fPos[], const
 
 static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float fUV[], const int face_num, const int vert_index)
 {
-       //assert(vert_index>=0 && vert_index<4);
+       //assert(vert_index >= 0 && vert_index < 4);
        SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
 
        if (pMesh->mtface != NULL) {
@@ -2428,7 +2420,7 @@ static void GetTextureCoordinate(const SMikkTSpaceContext *pContext, float fUV[]
 
 static void GetNormal(const SMikkTSpaceContext *pContext, float fNorm[], const int face_num, const int vert_index)
 {
-       //assert(vert_index>=0 && vert_index<4);
+       //assert(vert_index >= 0 && vert_index < 4);
        SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
 
        const int smoothnormal = (pMesh->mface[face_num].flag & ME_SMOOTH);
@@ -2458,7 +2450,7 @@ static void GetNormal(const SMikkTSpaceContext *pContext, float fNorm[], const i
 }
 static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[], const float fSign, const int face_num, const int iVert)
 {
-       //assert(vert_index>=0 && vert_index<4);
+       //assert(vert_index >= 0 && vert_index < 4);
        SGLSLMeshToTangent *pMesh = (SGLSLMeshToTangent *) pContext->m_pUserData;
        float *pRes = pMesh->tangent[4 * face_num + iVert];
        copy_v3_v3(pRes, fvTangent);
@@ -2469,15 +2461,11 @@ static void SetTSpace(const SMikkTSpaceContext *pContext, const float fvTangent[
 void DM_add_tangent_layer(DerivedMesh *dm)
 {
        /* mesh vars */
-       MTFace *mtface, *tf;
-       MFace *mface, *mf;
-       MVert *mvert, *v1, *v2, *v3, *v4;
-       MemArena *arena = NULL;
-       VertexTangent **vtangents = NULL;
+       MVert *mvert;
+       MTFace *mtface;
+       MFace *mface;
        float (*orco)[3] = NULL, (*tangent)[4];
-       float *uv1, *uv2, *uv3, *uv4, *vtang;
-       float fno[3], tang[3], uv[4][2];
-       int i, j, len, mf_vi[4], totvert, totface, iCalcNewMethod;
+       int /* totvert, */ totface;
        float *nors;
 
        if (CustomData_get_layer_index(&dm->faceData, CD_TANGENT) != -1)
@@ -2486,7 +2474,7 @@ void DM_add_tangent_layer(DerivedMesh *dm)
        nors = dm->getTessFaceDataArray(dm, CD_NORMAL);
 
        /* check we have all the needed layers */
-       totvert = dm->getNumVerts(dm);
+       /* totvert = dm->getNumVerts(dm); */ /* UNUSED */
        totface = dm->getNumTessFaces(dm);
 
        mvert = dm->getVertArray(dm);
@@ -2503,14 +2491,8 @@ void DM_add_tangent_layer(DerivedMesh *dm)
        DM_add_tessface_layer(dm, CD_TANGENT, CD_CALLOC, NULL);
        tangent = DM_get_tessface_data_layer(dm, CD_TANGENT);
        
-       /* allocate some space */
-       arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "tangent layer arena");
-       BLI_memarena_use_calloc(arena);
-       vtangents = MEM_callocN(sizeof(VertexTangent *) * totvert, "VertexTangent");
-
-       // new computation method
-       iCalcNewMethod = 1;
-       if (iCalcNewMethod != 0) {
+       /* new computation method */
+       {
                SGLSLMeshToTangent mesh2tangent = {0};
                SMikkTSpaceContext sContext = {0};
                SMikkTSpaceInterface sInterface = {0};
@@ -2532,88 +2514,14 @@ void DM_add_tangent_layer(DerivedMesh *dm)
                sInterface.m_getNormal = GetNormal;
                sInterface.m_setTSpaceBasic = SetTSpace;
 
-               // 0 if failed
-               iCalcNewMethod = genTangSpaceDefault(&sContext);
-       }
-
-       if (!iCalcNewMethod) {
-               /* sum tangents at connected vertices */
-               for (i = 0, tf = mtface, mf = mface; i < totface; mf++, tf++, i++) {
-                       v1 = &mvert[mf->v1];
-                       v2 = &mvert[mf->v2];
-                       v3 = &mvert[mf->v3];
-
-                       if (mf->v4) {
-                               v4 = &mvert[mf->v4];
-                               normal_quad_v3(fno, v4->co, v3->co, v2->co, v1->co);
-                       }
-                       else {
-                               v4 = NULL;
-                               normal_tri_v3(fno, v3->co, v2->co, v1->co);
-                       }
-               
-                       if (mtface) {
-                               uv1 = tf->uv[0];
-                               uv2 = tf->uv[1];
-                               uv3 = tf->uv[2];
-                               uv4 = tf->uv[3];
-                       }
-                       else {
-                               uv1 = uv[0]; uv2 = uv[1]; uv3 = uv[2]; uv4 = uv[3];
-                               map_to_sphere(&uv[0][0], &uv[0][1], orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2]);
-                               map_to_sphere(&uv[1][0], &uv[1][1], orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2]);
-                               map_to_sphere(&uv[2][0], &uv[2][1], orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2]);
-                               if (v4)
-                                       map_to_sphere(&uv[3][0], &uv[3][1], orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2]);
-                       }
-               
-                       tangent_from_uv(uv1, uv2, uv3, v1->co, v2->co, v3->co, fno, tang);
-                       sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
-                       sum_or_add_vertex_tangent(arena, &vtangents[mf->v2], tang, uv2);
-                       sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
-               
-                       if (mf->v4) {
-                               v4 = &mvert[mf->v4];
-                       
-                               tangent_from_uv(uv1, uv3, uv4, v1->co, v3->co, v4->co, fno, tang);
-                               sum_or_add_vertex_tangent(arena, &vtangents[mf->v1], tang, uv1);
-                               sum_or_add_vertex_tangent(arena, &vtangents[mf->v3], tang, uv3);
-                               sum_or_add_vertex_tangent(arena, &vtangents[mf->v4], tang, uv4);
-                       }
-               }
-       
-               /* write tangent to layer */
-               for (i = 0, tf = mtface, mf = mface; i < totface; mf++, tf++, i++, tangent += 4) {
-                       len = (mf->v4) ? 4 : 3;
-
-                       if (mtface == NULL) {
-                               map_to_sphere(&uv[0][0], &uv[0][1], orco[mf->v1][0], orco[mf->v1][1], orco[mf->v1][2]);
-                               map_to_sphere(&uv[1][0], &uv[1][1], orco[mf->v2][0], orco[mf->v2][1], orco[mf->v2][2]);
-                               map_to_sphere(&uv[2][0], &uv[2][1], orco[mf->v3][0], orco[mf->v3][1], orco[mf->v3][2]);
-                               if (len == 4)
-                                       map_to_sphere(&uv[3][0], &uv[3][1], orco[mf->v4][0], orco[mf->v4][1], orco[mf->v4][2]);
-                       }
-               
-                       mf_vi[0] = mf->v1;
-                       mf_vi[1] = mf->v2;
-                       mf_vi[2] = mf->v3;
-                       mf_vi[3] = mf->v4;
-               
-                       for (j = 0; j < len; j++) {
-                               vtang = find_vertex_tangent(vtangents[mf_vi[j]], mtface ? tf->uv[j] : uv[j]);
-                               normalize_v3_v3(tangent[j], vtang);
-                               ((float *) tangent[j])[3] = 1.0f;
-                       }
-               }
+               /* 0 if failed */
+               genTangSpaceDefault(&sContext);
        }
-       
-       BLI_memarena_free(arena);
-       MEM_freeN(vtangents);
 }
 
 void DM_calc_auto_bump_scale(DerivedMesh *dm)
 {
-       /* int totvert= dm->getNumVerts(dm); */ /* UNUSED */
+       /* int totvert = dm->getNumVerts(dm); */ /* UNUSED */
        int totface = dm->getNumTessFaces(dm);
 
        MVert *mvert = dm->getVertArray(dm);
@@ -2638,7 +2546,7 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm)
                                        tex_coords[3] = mtface[f].uv[3];
                                }
 
-                               // discard degenerate faces
+                               /* discard degenerate faces */
                                is_degenerate = 0;
                                if (equals_v3v3(verts[0], verts[1]) || equals_v3v3(verts[0], verts[2]) || equals_v3v3(verts[1], verts[2]) ||
                                    equals_v2v2(tex_coords[0], tex_coords[1]) || equals_v2v2(tex_coords[0], tex_coords[2]) || equals_v2v2(tex_coords[1], tex_coords[2]))
@@ -2646,7 +2554,7 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm)
                                        is_degenerate = 1;
                                }
 
-                               // verify last vertex as well if this is a quad
+                               /* verify last vertex as well if this is a quad */
                                if (is_degenerate == 0 && nr_verts == 4) {
                                        if (equals_v3v3(verts[3], verts[0]) || equals_v3v3(verts[3], verts[1]) || equals_v3v3(verts[3], verts[2]) ||
                                            equals_v2v2(tex_coords[3], tex_coords[0]) || equals_v2v2(tex_coords[3], tex_coords[1]) || equals_v2v2(tex_coords[3], tex_coords[2]))
@@ -2654,7 +2562,7 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm)
                                                is_degenerate = 1;
                                        }
 
-                                       // verify the winding is consistent
+                                       /* verify the winding is consistent */
                                        if (is_degenerate == 0) {
                                                float prev_edge[2];
                                                int is_signed = 0;
@@ -2681,11 +2589,11 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm)
                                        }
                                }
 
-                               // proceed if not a degenerate face
+                               /* proceed if not a degenerate face */
                                if (is_degenerate == 0) {
                                        int nr_tris_to_pile = 0;
-                                       // quads split at shortest diagonal
-                                       int offs = 0;       // initial triangulation is 0,1,2 and 0, 2, 3
+                                       /* quads split at shortest diagonal */
+                                       int offs = 0;  /* initial triangulation is 0,1,2 and 0, 2, 3 */
                                        if (nr_verts == 4) {
                                                float pos_len_diag0, pos_len_diag1;
                                                float vtmp[3];
@@ -2743,7 +2651,7 @@ void DM_calc_auto_bump_scale(DerivedMesh *dm)
                        }
                }
 
-               // finalize
+               /* finalize */
                {
                        const float avg_area_ratio = (nr_accumulated > 0) ? ((float)(dsum / nr_accumulated)) : 1.0f;
                        const float use_as_render_bump_scale = sqrtf(avg_area_ratio);       // use width of average surface ratio as your bump scale
@@ -3187,4 +3095,25 @@ void DM_debug_print(DerivedMesh *dm)
        MEM_freeN(str);
 }
 
+void DM_debug_print_cdlayers(CustomData *data)
+{
+       int i;
+       CustomDataLayer *layer;
+
+       printf("{\n");
+
+       for (i = 0, layer = data->layers; i < data->totlayer; i++, layer++) {
+
+               const char *name = CustomData_layertype_name(layer->type);
+               const int size = CustomData_sizeof(layer->type);
+               const char *structname;
+               int structnum;
+               CustomData_file_write_info(layer->type, &structname, &structnum);
+               printf("        dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+                      name, structname, layer->type, (void *)layer->data, size, (int)(MEM_allocN_len(layer->data) / size));
+       }
+
+       printf("}\n");
+}
+
 #endif /* NDEBUG */