svn merge ^/trunk/blender -r43482:43524
[blender.git] / source / blender / blenkernel / intern / DerivedMesh.c
index 8405a3922e6b285113db76321a7f265516ab67dc..63605c14f6cb3cb5567bb4f1fb4714eff2d2fadd 100644 (file)
@@ -352,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 */
@@ -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);
@@ -883,67 +903,71 @@ enum {
        CALC_WP_AUTO_NORMALIZE= (1<<1)
 };
 
+static void weightpaint_color(unsigned char r_col[4], ColorBand *coba, const float input)
+{
+       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(
-        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)
+        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)
 {
-       Mesh *me = ob->data;
        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;
-                       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 (dw->def_nr < defbase_tot) {
-                                       if (dg_flags[dw->def_nr]) {
-                                               if (dw->weight) {
-                                                       input += dw->weight;
-                                                       was_a_nonzero= TRUE;
-                                               }
+       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 */
-                       input= defvert_find_weight(dvert, ob->actdef-1);
+               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;
+       else {
+               /* default, non tricky behavior */
+               input= defvert_find_weight(dv, defbase_act);
+       }
+
+       if (make_black) { /* TODO, theme color */
+               r_col[3] = 0;
+               r_col[2] = 0;
+               r_col[1] = 0;
+               r_col[0] = 255;
        }
        else {
-               float colf[4];
                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;
+               weightpaint_color(r_col, coba, input);
        }
 }
 
@@ -954,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_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_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, 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, defbase_tot, 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;
@@ -993,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, defbase_tot, 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);
 }
 
 
@@ -1264,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);
@@ -1419,12 +1488,10 @@ 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 {
@@ -1479,7 +1546,7 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
        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 */
+        * '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          */
@@ -1537,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;
@@ -1548,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);
@@ -1612,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);
@@ -1689,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);
@@ -2392,13 +2460,8 @@ void DM_vertex_attributes_from_gpu(DerivedMesh *dm, GPUVertexAttribs *gattribs,
        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++)
@@ -2676,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 */