svn merge ^/trunk/blender -r42564:42586
[blender.git] / source / blender / blenkernel / intern / DerivedMesh.c
index 6ff3b20049c1ed950bdc108c96545b158705ac34..8405a3922e6b285113db76321a7f265516ab67dc 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,
@@ -424,11 +426,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 +769,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;
@@ -868,40 +868,53 @@ 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 calc_weightpaint_vert_color(
+        Object *ob, const int defbase_tot, ColorBand *coba, int vert, unsigned char *col,
+        const char *dg_flags, int selected, int UNUSED(unselected), const int draw_flag)
 {
        Mesh *me = ob->data;
-       float colf[4], input = 0.0f;
-       int i;
-
+       float input = 0.0f;
        
        int make_black= FALSE;
 
        if (me->dvert) {
+               MDeformVert *dvert= &me->dvert[vert];
+
                if ((selected > 1) && (draw_flag & CALC_WP_MULTIPAINT)) {
-                       
                        int was_a_nonzero= FALSE;
-                       for (i=0; i<me->dvert[vert].totweight; i++) {
+                       int i;
+
+                       MDeformWeight *dw= dvert->dw;
+                       for (i = dvert->totweight; i > 0; i--, dw++) {
                                /* 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;
-                                               was_a_nonzero= TRUE;
+                               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) {
+                       if (was_a_nonzero == FALSE) {
                                make_black = TRUE;
                        }
                        else if ((draw_flag & CALC_WP_AUTO_NORMALIZE) == FALSE) {
@@ -910,11 +923,7 @@ static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, u
                }
                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;
-                               }
-                       }
+                       input= defvert_find_weight(dvert, ob->actdef-1);
                }
        }
        
@@ -923,20 +932,19 @@ static void calc_weightpaint_vert_color(Object *ob, ColorBand *coba, int vert, u
                col[2] = 0;
                col[1] = 0;
                col[0] = 255;
-               return;
        }
+       else {
+               float colf[4];
+               CLAMP(input, 0.0f, 1.0f);
 
-       CLAMP(input, 0.0f, 1.0f);       
+               if(coba) do_colorband(coba, input, colf);
+               else     weight_to_rgb(colf, input);
 
-       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;
+               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;
+       }
 }
 
 static ColorBand *stored_cb= NULL;
@@ -959,10 +967,10 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm, int const draw_flag)
        int i, j, totface=dm->getNumTessFaces(dm), totloop;
        int *origIndex = dm->getVertDataArray(dm, CD_ORIGINDEX);
 
-       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;
+       int defbase_tot = BLI_countlist(&ob->defbase);
+       char *defbase_sel = MEM_mallocN(defbase_tot * sizeof(char), __func__);
+       int selected = get_selected_defgroups(ob, defbase_sel, defbase_tot);
+       int unselected = defbase_tot - selected;
 
        wtcol = MEM_callocN (sizeof (unsigned char) * totface*4*4, "weightmap");
        
@@ -970,11 +978,11 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm, int const draw_flag)
        memset(wtcol, 0x55, sizeof (unsigned char) * totface*4*4);
        for (i=0; i<totface; i++, mf++) {
                /*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);
+               calc_weightpaint_vert_color(ob, defbase_tot, coba, mf->v1, &wtcol[(i*4 + 0)*4], defbase_sel, selected, unselected, draw_flag);
+               calc_weightpaint_vert_color(ob, defbase_tot, coba, mf->v2, &wtcol[(i*4 + 1)*4], defbase_sel, selected, unselected, draw_flag);
+               calc_weightpaint_vert_color(ob, defbase_tot, 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);
+                       calc_weightpaint_vert_color(ob, defbase_tot, coba, mf->v4, &wtcol[(i*4 + 3)*4], defbase_sel, selected, unselected, draw_flag);
        }
        
        CustomData_add_layer(&dm->faceData, CD_WEIGHT_MCOL, CD_ASSIGN, wtcol, totface);
@@ -987,7 +995,7 @@ static void add_weight_mcol_dm(Object *ob, DerivedMesh *dm, int const draw_flag)
                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,
+                       calc_weightpaint_vert_color(ob, defbase_tot, coba, origIndex ? origIndex[ml->v] : ml->v,
                                                                                (unsigned char *)&wlcol[totloop], defbase_sel, selected, unselected, draw_flag);
                }
        }
@@ -1170,7 +1178,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);
                        
@@ -1411,10 +1419,12 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                dm->release(dm);
 
                CDDM_apply_vert_coords(finaldm, deformedVerts);
+
                CDDM_calc_normals(finaldm);
 
                if((dataMask & CD_MASK_WEIGHT_MCOL) && (ob->mode & OB_MODE_WEIGHT_PAINT))
                        add_weight_mcol_dm(ob, finaldm, draw_flag);
+
        } else if(dm) {
                finaldm = dm;
        } else {
@@ -1459,13 +1469,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' 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;
 
@@ -2206,6 +2225,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 +2391,15 @@ 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 0
+       if(dm->auto_bump_scale<=0.0f)
+               DM_calc_auto_bump_scale(dm);
+#else
+       dm->auto_bump_scale = 1.0f; // will revert this after release
+#endif
+
+
        /* add a tangent layer if necessary */
        for(b = 0; b < gattribs->totlayer; b++)
                if(gattribs->layer[b].type == CD_TANGENT)
@@ -2240,7 +2421,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 +2443,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 */