svn merge ^/trunk/blender -r43482:43524
[blender.git] / source / blender / blenkernel / intern / DerivedMesh.c
index 6ff3b20049c1ed950bdc108c96545b158705ac34..63605c14f6cb3cb5567bb4f1fb4714eff2d2fadd 100644 (file)
@@ -64,6 +64,7 @@
 #include "BKE_particle.h"
 #include "BKE_tessmesh.h"
 #include "BKE_bvhutils.h"
+#include "BKE_deform.h"
 
 #ifdef WITH_GAMEENGINE
 #include "BKE_navmesh_conversion.h"
@@ -275,6 +276,7 @@ void DM_init(DerivedMesh *dm, DerivedMeshType type, int numVerts, int numEdges,
        DM_init_funcs(dm);
        
        dm->needsFree = 1;
+       dm->auto_bump_scale = -1.0f;
 }
 
 void DM_from_template(DerivedMesh *dm, DerivedMesh *source, DerivedMeshType type,
@@ -350,6 +352,26 @@ void DM_DupPolys(DerivedMesh *source, DerivedMesh *target)
        }
 }
 
+/* note: until all modifiers can take MPoly's as input,
+ * use this at the start of modifiers  */
+void DM_ensure_tessface(DerivedMesh *dm)
+{
+       const int numTessFaces = dm->getNumTessFaces(dm);
+       const int numPolys =     dm->getNumPolys(dm);
+
+       if ( (numTessFaces == 0) && (numPolys != 0)) {
+               dm->recalcTesselation(dm);
+
+               if (dm->getNumTessFaces(dm)) {
+                       printf("warning %s: could not create tessfaces from %d polygons, dm->type=%d\n",
+                              __func__, numPolys, dm->type);
+               }
+               else {
+                       printf("info %s: polys -> ngons calculated\n", __func__);
+               }
+       }
+}
+
 void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
 {
        /* dm might depend on me, so we need to do everything with a local copy */
@@ -424,11 +446,11 @@ void DM_to_mesh(DerivedMesh *dm, Mesh *me, Object *ob)
        }
 
        /* yes, must be before _and_ after tesselate */
-       mesh_update_customdata_pointers(&tmp);
+       mesh_update_customdata_pointers(&tmp, TRUE);
 
        tmp.totface = mesh_recalcTesselation(&tmp.fdata, &tmp.ldata, &tmp.pdata, tmp.mvert, tmp.totface, tmp.totloop, tmp.totpoly);
 
-       mesh_update_customdata_pointers(&tmp);
+       mesh_update_customdata_pointers(&tmp, TRUE);
 
 
        CustomData_free(&me->vdata, me->totvert);
@@ -767,12 +789,10 @@ static void *get_orco_coords_dm(Object *ob, BMEditMesh *em, int layer, int *free
                   by a more flexible customdata system, but not simple */
                if(!em) {
                        ClothModifierData *clmd = (ClothModifierData *)modifiers_findByType(ob, eModifierType_Cloth);
-                       if (clmd) {
-                               KeyBlock *kb= key_get_keyblock(ob_get_key(ob), clmd->sim_parms->shapekey_rest);
-       
-                               if(kb->data)
-                                       return kb->data;
-                       }
+                       KeyBlock *kb= key_get_keyblock(ob_get_key(ob), clmd->sim_parms->shapekey_rest);
+
+                       if(kb->data)
+                               return kb->data;
                }
 
                return NULL;
@@ -787,7 +807,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, 0);
+       if(em) dm= CDDM_from_BMEditMesh(em, me, FALSE, FALSE);
        else dm= CDDM_from_mesh(me, ob);
 
        orco= get_orco_coords_dm(ob, em, layer, &free);
@@ -868,75 +888,87 @@ void weight_to_rgb(float r_rgb[3], const float weight)
                r_rgb[1]= blend * (1.0f-((weight-0.75f)*4.0f));
                r_rgb[2]= 0.0f;
        }
+       else {
+               /* exceptional value, unclamped or nan,
+                * avoid uninitialized memory use */
+               r_rgb[0]= 1.0f;
+               r_rgb[1]= 0.0f;
+               r_rgb[2]= 1.0f;
+       }
 }
 
 /* draw_flag's for calc_weightpaint_vert_color */
 enum {
        CALC_WP_MULTIPAINT= (1<<0),
-       CALC_WP_AUTO_NORMALIZE= (1<<1),
+       CALC_WP_AUTO_NORMALIZE= (1<<1)
 };
 
-static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, unsigned char *col, char *dg_flags, int selected, int UNUSED(unselected), const int draw_flag)
+static void weightpaint_color(unsigned char r_col[4], ColorBand *coba, const float input)
 {
-       Mesh *me = ob->data;
-       float colf[4], input = 0.0f;
-       int i;
+       float colf[4];
+
+       if(coba) do_colorband(coba, input, colf);
+       else     weight_to_rgb(colf, input);
 
+       r_col[3] = (unsigned char)(colf[0] * 255.0f);
+       r_col[2] = (unsigned char)(colf[1] * 255.0f);
+       r_col[1] = (unsigned char)(colf[2] * 255.0f);
+       r_col[0] = 255;
+}
+
+
+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)
+{
+       float input = 0.0f;
        
        int make_black= FALSE;
 
-       if (me->dvert) {
-               if ((selected > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
-                       
-                       int was_a_nonzero= FALSE;
-                       for (i=0; i<me->dvert[vert].totweight; i++) {
-                               /* in multipaint, get the average if auto normalize is inactive
-                                * get the sum if it is active */
-                               if(dg_flags[me->dvert[vert].dw[i].def_nr]) {
-                                       if(me->dvert[vert].dw[i].weight) {
-                                               input+= me->dvert[vert].dw[i].weight;
+       if ((selected > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
+               int was_a_nonzero= FALSE;
+               unsigned int i;
+
+               MDeformWeight *dw= dv->dw;
+               for (i = dv->totweight; i != 0; i--, dw++) {
+                       /* 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 (dw->weight) {
+                                               input += dw->weight;
                                                was_a_nonzero= TRUE;
                                        }
                                }
                        }
+               }
 
-                       /* make it black if the selected groups have no weight on a vertex */
-                       if(was_a_nonzero == FALSE) {
-                               make_black = TRUE;
-                       }
-                       else if ((draw_flag & CALC_WP_AUTO_NORMALIZE) == FALSE) {
-                               input /= selected; /* get the average */
-                       }
+               /* make it black if the selected groups have no weight on a vertex */
+               if (was_a_nonzero == FALSE) {
+                       make_black = TRUE;
                }
-               else {
-                       /* default, non tricky behavior */
-                       for (i=0; i<me->dvert[vert].totweight; i++) {
-                               if (me->dvert[vert].dw[i].def_nr==ob->actdef-1) {
-                                       input+=me->dvert[vert].dw[i].weight;
-                               }
-                       }
+               else if ((draw_flag & CALC_WP_AUTO_NORMALIZE) == FALSE) {
+                       input /= selected; /* get the average */
                }
        }
-       
-       if (make_black) {
-               col[3] = 0;
-               col[2] = 0;
-               col[1] = 0;
-               col[0] = 255;
-               return;
+       else {
+               /* default, non tricky behavior */
+               input= defvert_find_weight(dv, defbase_act);
        }
 
-       CLAMP(input, 0.0f, 1.0f);       
-
-       if(coba)
-               do_colorband(coba, input, colf);
-       else
-               weight_to_rgb(colf, input);
-       
-       col[3] = (unsigned char)(colf[0] * 255.0f);
-       col[2] = (unsigned char)(colf[1] * 255.0f);
-       col[1] = (unsigned char)(colf[2] * 255.0f);
-       col[0] = 255;
+       if (make_black) { /* TODO, theme color */
+               r_col[3] = 0;
+               r_col[2] = 0;
+               r_col[1] = 0;
+               r_col[0] = 255;
+       }
+       else {
+               CLAMP(input, 0.0f, 1.0f);
+               weightpaint_color(r_col, coba, input);
+       }
 }
 
 static ColorBand *stored_cb= NULL;
@@ -946,38 +978,84 @@ void vDM_ColorBand_store(ColorBand *coba)
        stored_cb= coba;
 }
 
+/* return an array of vertex weight colors, caller must free.
+ *
+ * note that we could save some memory and allocate RGB only but then we'd need to
+ * re-arrange the colors when copying to the face since MCol has odd ordering,
+ * so leave this as is - campbell */
+static unsigned char *calc_weightpaint_vert_array(Object *ob, int const draw_flag, ColorBand *coba)
+{
+       Mesh *me = ob->data;
+       unsigned char *wtcol_v = MEM_mallocN (sizeof(unsigned char) * me->totvert * 4, "weightmap_v");
+
+       if (me->dvert) {
+               unsigned char *wc = wtcol_v;
+               MDeformVert *dv= me->dvert;
+               unsigned int i;
+
+               /* varisbles 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);
+               /* const int unselected = defbase_tot - selected; */ /* UNUSED */
+
+               for (i = me->totvert; i != 0; i--, wc += 4, dv++) {
+                       calc_weightpaint_vert_color(wc, dv, coba, defbase_tot, defbase_act, dg_flags, selected, draw_flag);
+               }
+
+               MEM_freeN(dg_flags);
+       }
+       else {
+               int col_i;
+               weightpaint_color((unsigned char *)&col_i, coba, 0.0f);
+               fill_vn_i((int *)wtcol_v, me->totvert, col_i);
+       }
+
+       return wtcol_v;
+}
+
 static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm, int const draw_flag)
 {
-       // Mesh *me = ob->data; // UNUSED
+       ColorBand *coba= stored_cb;     /* warning, not a local var */
+       unsigned char *wtcol_v = calc_weightpaint_vert_array(ob, draw_flag, coba);
+       unsigned char *wtcol_f;
+       unsigned char(*wtcol_l)[4] = NULL;
+       BLI_array_declare(wtcol_l);
        MFace *mf = dm->getTessFaceArray(dm);
        MLoop *mloop = dm->getLoopArray(dm), *ml;
        MPoly *mp = dm->getPolyArray(dm);
-       ColorBand *coba= stored_cb;     /* warning, not a local var */
-       unsigned char *wtcol;
-       unsigned char(*wlcol)[4] = NULL;
-       BLI_array_declare(wlcol);
        int i, j, totface=dm->getNumTessFaces(dm), totloop;
        int *origIndex = dm->getVertDataArray(dm, CD_ORIGINDEX);
+       unsigned char *wtcol_f_step;
 
-       int defbase_len = BLI_countlist(&ob->defbase);
-       char *defbase_sel = MEM_mallocN(defbase_len * sizeof(char), __func__);
-       int selected = get_selected_defgroups(ob, defbase_sel, defbase_len);
-       int unselected = defbase_len - selected;
+       wtcol_f = MEM_mallocN(sizeof (unsigned char) * totface*4*4, "weightmap_f");
+       wtcol_f_step = wtcol_f;
 
-       wtcol = MEM_callocN (sizeof (unsigned char) * totface*4*4, "weightmap");
-       
        /*first add colors to the tesselation faces*/
-       memset(wtcol, 0x55, sizeof (unsigned char) * totface*4*4);
-       for (i=0; i<totface; i++, mf++) {
+       for (i=0; i<totface; i++, mf++, wtcol_f_step += (4 * 4)) {
                /*origindex being NULL means we're operating on original mesh data*/
-               calc_weightpaint_vert_color(ob, coba, mf->v1, &wtcol[(i*4 + 0)*4], defbase_sel, selected, unselected, draw_flag);
-               calc_weightpaint_vert_color(ob, coba, mf->v2, &wtcol[(i*4 + 1)*4], defbase_sel, selected, unselected, draw_flag);
-               calc_weightpaint_vert_color(ob, coba, mf->v3, &wtcol[(i*4 + 2)*4], defbase_sel, selected, unselected, draw_flag);
-               if (mf->v4)
-                       calc_weightpaint_vert_color(ob, coba, mf->v4, &wtcol[(i*4 + 3)*4], defbase_sel, selected, unselected, draw_flag);
+#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
+
+               do {
+                       copy_v4_v4_char((char *)&wtcol_f_step[fidx * 4],
+                                       (char *)&wtcol_v[4 * (*(&mf->v1 + fidx))]);
+               } while (fidx--);
        }
-       
-       CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, totface);
+
+       CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol_f, totface);
 
        /*now add to loops, so the data can be passed through the modifier stack*/
        totloop = 0;
@@ -985,16 +1063,15 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm, int const draw_flag)
                ml = mloop + mp->loopstart;
 
                for (j=0; j<mp->totloop; j++, ml++, totloop++) {
-                       BLI_array_growone(wlcol);
-
-                       calc_weightpaint_vert_color(ob, coba, origIndex ? origIndex[ml->v] : ml->v,
-                                                                               (unsigned char *)&wlcol[totloop], defbase_sel, selected, unselected, draw_flag);
+                       BLI_array_growone(wtcol_l);
+                       copy_v4_v4_char((char *)&wtcol_l[totloop],
+                                       (char *)&wtcol_v[4 * (origIndex ? origIndex[ml->v] : ml->v)]);
                }
        }
 
-       MEM_freeN(defbase_sel);
+       MEM_freeN(wtcol_v);
 
-       CustomData_add_layer(&dm->loopData, CD_WEIGHT_MLOOPCOL, CD_ASSIGN, wlcol, totloop);
+       CustomData_add_layer(&dm->loopData, CD_WEIGHT_MLOOPCOL, CD_ASSIGN, wtcol_l, totloop);
 }
 
 
@@ -1170,7 +1247,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                 */
                if (deform_r) {
                        *deform_r = CDDM_from_mesh(me, ob);
-                       
+                        
                        if (build_shapekey_layers)
                                add_shapekey_layers(dm, me, ob);
                        
@@ -1256,7 +1333,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
 
                        /* if this is not the last modifier in the stack then recalculate the normals
                         * to avoid giving bogus normals to the next modifier see: [#23673] */
-                       if(dm && isPrevDeform &&  mti->dependsOnNormals && mti->dependsOnNormals(md)) {
+                       if(isPrevDeform &&  mti->dependsOnNormals && mti->dependsOnNormals(md)) {
                                /* XXX, this covers bug #23673, but we may need normal calc for other types */
                                if(dm && dm->type == DM_TYPE_CDDM) {
                                        CDDM_apply_vert_coords(dm, deformedVerts);
@@ -1459,13 +1536,22 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        }
 #endif /* WITH_GAMEENGINE */
 
+
+       /* --------------------------------------------------------------------- */
        /* Re-tesselation is necessary to push render data (uvs, textures, colors)
-          from loops and polys onto the tessfaces. This may be currently be redundant
-          in cases where the render mode doesn't use these inputs, but ideally
-          eventually tesselation would happen on-demand, and this is one of the primary
-          places it would be needed. */
+        * from loops and polys onto the tessfaces. This may be currently be
+        * redundantin cases where the render mode doesn't use these inputs, but
+        * ideally eventually tesselation would happen on-demand, and this is one
+        * of the primary places it would be needed. */
        finaldm->recalcTesselation(finaldm);
+       /* if we have no modifiers applied we'lll still want the tessface normals
+        * to be calculated from the polygon noramals,
+        * 'CDDM_calc_normals_mapping' checks for this case - campbell */
        finaldm->calcNormals(finaldm);
+       /* Need to watch this, it can cause issues, see bug [#29338]             */
+       /* take care with this block, we really need testing frameworks          */
+       /* --------------------------------------------------------------------- */
+
 
        *final_r = finaldm;
 
@@ -1518,7 +1604,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
        ModifierData *md;
        float (*deformedVerts)[3] = NULL;
        CustomDataMask mask;
-       DerivedMesh *dm = NULL, *orcodm = NULL, *finaldm = NULL;
+       DerivedMesh *dm, *orcodm = NULL;
        int i, numVerts = 0, cageIndex = modifiers_getCageIndex(scene, ob, NULL, 1);
        LinkNode *datamasks, *curr;
        int required_mode = eModifierMode_Realtime | eModifierMode_Editmode;
@@ -1529,6 +1615,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
                *cage_r = getEditDerivedBMesh(em, ob, NULL);
        }
 
+       dm = NULL;
        md = modifiers_getVirtualModifierList(ob);
 
        datamasks = modifiers_calcDataMasks(scene, ob, md, dataMask, required_mode);
@@ -1593,7 +1680,7 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
                                }
 
                        } else {
-                               dm = CDDM_from_BMEditMesh(em, ob->data, 0);
+                               dm = CDDM_from_BMEditMesh(em, ob->data, FALSE, FALSE);
 
                                if(deformedVerts) {
                                        CDDM_apply_vert_coords(dm, deformedVerts);
@@ -1670,24 +1757,24 @@ static void editbmesh_calc_modifiers(Scene *scene, Object *ob, BMEditMesh *em, D
         * then we need to build one.
         */
        if(dm && deformedVerts) {
-               finaldm = CDDM_copy(dm, 0);
+               *final_r = CDDM_copy(dm, 0);
 
                if(!(cage_r && dm == *cage_r)) dm->release(dm);
 
                CDDM_apply_vert_coords(*final_r, deformedVerts);
+               CDDM_calc_normals_mapping(*final_r);
        } else if (dm) {
-               finaldm = dm;
+               *final_r = dm;
+               (*final_r)->calcNormals(*final_r); /* BMESH_ONLY - BMESH_TODO. check if this is needed */
        } else if (!deformedVerts && cage_r && *cage_r) {
-               finaldm = *cage_r;
+               *final_r = *cage_r;
+               (*final_r)->calcNormals(*final_r); /* BMESH_ONLY - BMESH_TODO. check if this is needed */
        } else {
-               finaldm = getEditDerivedBMesh(em, ob, deformedVerts);
+               *final_r = getEditDerivedBMesh(em, ob, deformedVerts);
                deformedVerts = NULL;
+               (*final_r)->calcNormals(*final_r); /* BMESH_ONLY - BMESH_TODO. check if this is needed */
        }
 
-       finaldm->calcNormals(finaldm);
-
-       *final_r = finaldm;
-
        /* add an orco layer if needed */
        if(dataMask & CD_MASK_ORCO)
                add_orco_dm(ob, em, *final_r, orcodm, CD_ORCO);
@@ -2206,6 +2293,159 @@ void DM_add_tangent_layer(DerivedMesh *dm)
        MEM_freeN(vtangents);
 }
 
+void DM_calc_auto_bump_scale(DerivedMesh *dm)
+{
+       /* int totvert= dm->getNumVerts(dm); */ /* UNUSED */
+       int totface= dm->getNumTessFaces(dm);
+
+       MVert * mvert = dm->getVertArray(dm);
+       MFace * mface = dm->getTessFaceArray(dm);
+       MTFace * mtface = dm->getTessFaceDataArray(dm, CD_MTFACE);
+
+       if(mtface)
+       {
+               double dsum = 0.0;
+               int nr_accumulated = 0;
+               int f;
+
+               for ( f=0; f<totface; f++ )
+               {
+                       {
+                               float * verts[4], * tex_coords[4];
+                               const int nr_verts = mface[f].v4!=0 ? 4 : 3;
+                               int i, is_degenerate;
+
+                               verts[0]=mvert[mface[f].v1].co; verts[1]=mvert[mface[f].v2].co; verts[2]=mvert[mface[f].v3].co;
+                               tex_coords[0]=mtface[f].uv[0]; tex_coords[1]=mtface[f].uv[1]; tex_coords[2]=mtface[f].uv[2];
+                               if(nr_verts==4)
+                               {
+                                       verts[3]=mvert[mface[f].v4].co;
+                                       tex_coords[3]=mtface[f].uv[3];
+                               }
+
+                               // 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]) )
+                               {
+                                       is_degenerate = 1;
+                               }
+
+                               // 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]) )
+                                       {
+                                               is_degenerate = 1;
+                                       }
+
+                                       // verify the winding is consistent
+                                       if ( is_degenerate==0 )
+                                       {
+                                               float prev_edge[2];
+                                               int is_signed = 0;
+                                               sub_v2_v2v2(prev_edge, tex_coords[0], tex_coords[3]);
+
+                                               i = 0;
+                                               while ( is_degenerate==0 && i<4 )
+                                               {
+                                                       float cur_edge[2], signed_area;
+                                                       sub_v2_v2v2(cur_edge, tex_coords[(i+1)&0x3], tex_coords[i]);
+                                                       signed_area = prev_edge[0]*cur_edge[1] - prev_edge[1]*cur_edge[0];
+                                                       if ( i==0 ) is_signed = signed_area<0.0f ? 1 : 0;
+                                                       else if((is_signed!=0)!=(signed_area<0.0f)) is_degenerate=1;
+
+                                                       if ( is_degenerate==0 )
+                                                       {
+                                                               copy_v2_v2(prev_edge, cur_edge);
+                                                               ++i;
+                                                       }
+                                               }
+                                       }
+                               }
+
+                               // 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
+                                       if ( nr_verts==4 )
+                                       {
+                                               float pos_len_diag0, pos_len_diag1;
+                                               float vtmp[3];
+                                               sub_v3_v3v3(vtmp, verts[2], verts[0]);
+                                               pos_len_diag0 = dot_v3v3(vtmp, vtmp);
+                                               sub_v3_v3v3(vtmp, verts[3], verts[1]);
+                                               pos_len_diag1 = dot_v3v3(vtmp, vtmp);
+
+                                               if(pos_len_diag1<pos_len_diag0)
+                                                       offs=1;         // alter split
+                                               else if(pos_len_diag0==pos_len_diag1)           // do UV check instead
+                                               {
+                                                       float tex_len_diag0, tex_len_diag1;
+
+                                                       sub_v2_v2v2(vtmp, tex_coords[2], tex_coords[0]);
+                                                       tex_len_diag0 = dot_v2v2(vtmp, vtmp);
+                                                       sub_v2_v2v2(vtmp, tex_coords[3], tex_coords[1]);
+                                                       tex_len_diag1 = dot_v2v2(vtmp, vtmp);
+
+                                                       if(tex_len_diag1<tex_len_diag0)
+                                                       {
+                                                               offs=1;         // alter split
+                                                       }
+                                               }
+                                       }
+                                       nr_tris_to_pile = nr_verts-2 ;
+                                       if ( nr_tris_to_pile==1 || nr_tris_to_pile==2 )
+                                       {
+                                               const int indices[] = {offs+0, offs+1, offs+2, offs+0, offs+2, (offs+3)&0x3 };
+                                               int t;
+                                               for ( t=0; t<nr_tris_to_pile; t++ )
+                                               {
+                                                       float f2x_area_uv;
+                                                       float * p0 = verts[indices[t*3+0]];
+                                                       float * p1 = verts[indices[t*3+1]];
+                                                       float * p2 = verts[indices[t*3+2]];
+
+                                                       float edge_t0[2], edge_t1[2];
+                                                       sub_v2_v2v2(edge_t0, tex_coords[indices[t*3+1]], tex_coords[indices[t*3+0]]);
+                                                       sub_v2_v2v2(edge_t1, tex_coords[indices[t*3+2]], tex_coords[indices[t*3+0]]);
+
+                                                       f2x_area_uv = fabsf(edge_t0[0]*edge_t1[1] - edge_t0[1]*edge_t1[0]);
+                                                       if ( f2x_area_uv>FLT_EPSILON )
+                                                       {
+                                                               float norm[3], v0[3], v1[3], f2x_surf_area, fsurf_ratio;
+                                                               sub_v3_v3v3(v0, p1, p0);
+                                                               sub_v3_v3v3(v1, p2, p0);
+                                                               cross_v3_v3v3(norm, v0, v1);
+
+                                                               f2x_surf_area = len_v3(norm);
+                                                               fsurf_ratio = f2x_surf_area/f2x_area_uv;        // tri area divided by texture area
+
+                                                               ++nr_accumulated;
+                                                               dsum += (double)(fsurf_ratio);
+                                                       }
+                                               }
+                                       }
+                               }
+                       }
+               }
+
+               // 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
+                       dm->auto_bump_scale = use_as_render_bump_scale;
+               }
+       }
+       else
+       {
+               dm->auto_bump_scale = 1.0f;
+       }
+}
+
 void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs, DMVertexAttribs *attribs)
 {
        CustomData *vdata, *fdata, *tfdata = NULL;
@@ -2219,6 +2459,10 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
        vdata = &dm->vertData;
        fdata = tfdata = dm->getTessFaceDataLayout(dm);
        
+       /* calc auto bump scale if necessary */
+       if(dm->auto_bump_scale<=0.0f)
+               DM_calc_auto_bump_scale(dm);
+
        /* add a tangent layer if necessary */
        for(b = 0; b < gattribs->totlayer; b++)
                if(gattribs->layer[b].type == CD_TANGENT)
@@ -2240,7 +2484,10 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
                                attribs->tface[a].array = tfdata->layers[layer].data;
                                attribs->tface[a].emOffset = tfdata->layers[layer].offset;
                                attribs->tface[a].glIndex = gattribs->layer[b].glindex;
-                       } /*else {
+                               /* attribs->tface[a].glTexco = gattribs->layer[b].gltexco; */ /* BMESH_TODO, trunk has this but not bmesh, need to investigate whats going on here - campbell */
+                       }
+                       /* BMESH ONLY, may need to get this working?, otherwise remove */
+                       /* else {
                                int player;
                                CustomData *pdata = dm->getPolyDataLayout(dm);
                                
@@ -2259,7 +2506,8 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
                                        attribs->tface[a].glTexco = gattribs->layer[b].gltexco;
                                        
                                }
-                       }*/
+                       }
+                       */
                }
                else if(gattribs->layer[b].type == CD_MCOL) {
                        /* vertex colors */
@@ -2491,3 +2739,84 @@ static DerivedMesh *navmesh_dm_createNavMeshForVisualization(DerivedMesh *dm)
 #endif /* WITH_GAMEENGINE */
 
 /* --- NAVMESH (end) --- */
+
+
+/* derivedmesh info printing function,
+ * to help track down differences DM output */
+
+#ifndef NDEBUG
+#include "BLI_dynstr.h"
+
+static void dm_debug_info_layers(DynStr *dynstr, DerivedMesh *dm, void *(*getElemDataArray)(DerivedMesh *, int))
+{
+       int type;
+
+       for (type = 0; type < CD_NUMTYPES; type++) {
+               /* note: doesnt account for multiple layers */
+               void *pt = getElemDataArray(dm, type);
+               if (pt) {
+                       const char *name = CustomData_layertype_name(type);
+                       const int size = CustomData_sizeof(type);
+                       const char *structname;
+                       int structnum;
+                       CustomData_file_write_info(type, &structname, &structnum);
+                       BLI_dynstr_appendf(dynstr,
+                                          "        dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n",
+                                                          name, structname, type, (void *)pt, size, (int)(MEM_allocN_len(pt) / size));
+               }
+       }
+}
+
+char *DM_debug_info(DerivedMesh *dm)
+{
+       DynStr *dynstr= BLI_dynstr_new();
+       char *ret;
+       const char *tstr;
+
+       BLI_dynstr_appendf(dynstr, "{\n");
+       BLI_dynstr_appendf(dynstr, "    'ptr': '%p',\n", (void *)dm);
+       switch (dm->type) {
+               case DM_TYPE_CDDM:     tstr = "DM_TYPE_CDDM";     break;
+               case DM_TYPE_EDITBMESH: tstr = "DM_TYPE_EDITMESH";  break;
+               case DM_TYPE_CCGDM:    tstr = "DM_TYPE_CCGDM";     break;
+               default:               tstr = "UNKNOWN";           break;
+       }
+       BLI_dynstr_appendf(dynstr, "    'type': '%s',\n", tstr);
+       BLI_dynstr_appendf(dynstr, "    'numVertData': %d,\n", dm->numVertData);
+       BLI_dynstr_appendf(dynstr, "    'numEdgeData': %d,\n", dm->numEdgeData);
+       BLI_dynstr_appendf(dynstr, "    'numTessFaceData': %d,\n", dm->numTessFaceData);
+       BLI_dynstr_appendf(dynstr, "    'numPolyData': %d,\n", dm->numPolyData);
+       BLI_dynstr_appendf(dynstr, "    'deformedOnly': %d,\n", dm->deformedOnly);
+
+       BLI_dynstr_appendf(dynstr, "    'vertexLayers': (\n");
+       dm_debug_info_layers(dynstr, dm, dm->getVertDataArray);
+       BLI_dynstr_appendf(dynstr, "    ),\n");
+
+       BLI_dynstr_appendf(dynstr, "    'edgeLayers': (\n");
+       dm_debug_info_layers(dynstr, dm, dm->getEdgeDataArray);
+       BLI_dynstr_appendf(dynstr, "    ),\n");
+
+       BLI_dynstr_appendf(dynstr, "    'tessFaceLayers': (\n");
+       dm_debug_info_layers(dynstr, dm, dm->getTessFaceDataArray);
+       BLI_dynstr_appendf(dynstr, "    ),\n");
+
+       BLI_dynstr_appendf(dynstr, "    'PolyLayers': (\n");
+       dm_debug_info_layers(dynstr, dm, DM_get_poly_data_layer);
+       BLI_dynstr_appendf(dynstr, "    ),\n");
+
+       BLI_dynstr_appendf(dynstr, "}\n");
+
+       ret = BLI_dynstr_get_cstring(dynstr);
+       BLI_dynstr_free(dynstr);
+       return ret;
+}
+
+void DM_debug_print(DerivedMesh *dm)
+{
+       char *str = DM_debug_info(dm);
+       printf("%s", str);
+       fflush(stdout);
+       MEM_freeN(str);
+}
+
+#endif /* NDEBUG */