Update DerivedMesh for dynamic-topology sculpt mode
[blender.git] / source / blender / blenkernel / intern / DerivedMesh.c
index cca425a63d8fe756f02ac2a5ce37ed9a323b92a9..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 "BKE_pbvh.h"
 #include "BKE_cdderivedmesh.h"
 #include "BKE_displist.h"
 #include "BKE_key.h"
@@ -392,7 +392,7 @@ void DM_ensure_tessface(DerivedMesh *dm)
        }
 
        else if (dm->dirty & DM_DIRTY_TESS_CDLAYERS) {
-               BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX));
+               BLI_assert(CustomData_has_layer(&dm->faceData, CD_ORIGINDEX) || numTessFaces == 0);
                DM_update_tessface_data(dm);
        }
 
@@ -857,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;
 
@@ -889,9 +886,9 @@ 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
@@ -1159,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;
 }
@@ -1398,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));
@@ -1465,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);
 
@@ -1476,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;
                }
 
@@ -1523,9 +1466,14 @@ static void mesh_calc_modifiers(Scene *scene, Object *ob, float (*inputVertexCos
                        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;
 
@@ -1721,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)
@@ -1870,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;
 
-       cos = MEM_mallocN(sizeof(float) * 3 * numVerts, "vertexcos");
+       *numVerts_r = em->bm->totvert;
 
-       eve = BM_iter_new(&iter, em->bm, BM_VERTS_OF_MESH, NULL);
-       for (i = 0; eve; eve = BM_iter_step(&iter), i++) {
+       cos = MEM_mallocN(sizeof(float) * 3 * em->bm->totvert, "vertexcos");
+
+       BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) {
                copy_v3_v3(cos[i], eve->co);
        }
 
@@ -2167,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,
@@ -2365,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);
        }
 }
 
@@ -2387,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);
                }
        }