Fix T43671: Playing with Mix Factor of Data Transfer Modifier Is Overwritting Data...
authorBastien Montagne <montagne29@wanadoo.fr>
Sun, 15 Feb 2015 17:46:46 +0000 (18:46 +0100)
committerBastien Montagne <montagne29@wanadoo.fr>
Sun, 15 Feb 2015 18:00:06 +0000 (19:00 +0100)
The issue was actually affecting all data types that are not regular CDLayer ones, since by default
DerivedMesh references mesh data (verts, edges, etc. - modifying custom normals often implies
modifying edges' sarpness too).
Modfying edge/face sharpness etc. could directly affect the mesh in this case, **bad**!

So we detect whether we are copying data types that may affect non-CDlayers data, and whether
verts array of org dm is same as mesh one - in which case we copy the DM. This avoids
useless copying in most cases.

Note Edit Normals was quite obviously suffering the same issue.

source/blender/modifiers/intern/MOD_datatransfer.c
source/blender/modifiers/intern/MOD_normal_edit.c

index 2dca3218e411ed0da8e6d3cb89d6ef10860cf288..acb58f6b7671ba039ffb9c4b51fb7e179b2dfd3d 100644 (file)
@@ -37,6 +37,7 @@
 #include "DNA_object_types.h"
 
 #include "BKE_customdata.h"
+#include "BKE_cdderivedmesh.h"
 #include "BKE_data_transfer.h"
 #include "BKE_DerivedMesh.h"
 #include "BKE_library.h"
@@ -152,6 +153,12 @@ static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
 }
 
 #define HIGH_POLY_WARNING 10000
+#define DT_TYPES_AFFECT_MESH ( \
+       DT_TYPE_BWEIGHT_VERT | \
+       DT_TYPE_BWEIGHT_EDGE | DT_TYPE_CREASE | DT_TYPE_SHARP_EDGE | \
+       DT_TYPE_LNOR | \
+       DT_TYPE_SHARP_FACE \
+)
 
 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *derivedData,
                                   ModifierApplyFlag UNUSED(flag))
@@ -160,6 +167,10 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
        DerivedMesh *dm = derivedData;
        ReportList reports;
 
+       /* Only used to check wehther we are operating on org data or not... */
+       Mesh *me = ob->data;
+       MVert *mvert;
+
        const bool invert_vgroup = (dtmd->flags & MOD_DATATRANSFER_INVERT_VGROUP) != 0;
 
        const float max_dist = (dtmd->flags & MOD_DATATRANSFER_MAP_MAXDIST) ? dtmd->map_max_distance : FLT_MAX;
@@ -171,6 +182,13 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
                BLI_SPACE_TRANSFORM_SETUP(space_transform, ob, dtmd->ob_source);
        }
 
+       mvert = dm->getVertArray(dm);
+       if ((me->mvert == mvert) && (dtmd->data_types & DT_TYPES_AFFECT_MESH)) {
+               /* We need to duplicate data here, otherwise setting custom normals, edges' shaprness, etc., could
+                * modify org mesh, see T43671. */
+               dm = CDDM_copy(dm);
+       }
+
        BKE_reports_init(&reports, RPT_STORE);
 
        /* Note: no islands precision for now here. */
@@ -190,6 +208,8 @@ static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *der
        return dm;
 }
 
+#undef HIGH_POLY_WARNING
+#undef DT_TYPES_AFFECT_MESH
 
 ModifierTypeInfo modifierType_DataTransfer = {
        /* name */              "DataTransfer",
index 58ef850bb4f342f80236befbf06e91c712041bae..db20823bf0c78f315c7a2959fddade67fb9fb7cb 100644 (file)
@@ -323,7 +323,7 @@ static bool is_valid_target(NormalEditModifierData *smd)
        return false;
 }
 
-static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, DerivedMesh *dm)
+static DerivedMesh *normalEditModifier_do(NormalEditModifierData *smd, Object *ob, DerivedMesh *dm)
 {
        Mesh *me = ob->data;
 
@@ -331,10 +331,10 @@ static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, Deriv
        const int num_edges = dm->getNumEdges(dm);
        const int num_loops = dm->getNumLoops(dm);
        const int num_polys = dm->getNumPolys(dm);
-       MVert *mvert = dm->getVertArray(dm);
-       MEdge *medge = dm->getEdgeArray(dm);
-       MLoop *mloop = dm->getLoopArray(dm);
-       MPoly *mpoly = dm->getPolyArray(dm);
+       MVert *mvert;
+       MEdge *medge;
+       MLoop *mloop;
+       MPoly *mpoly;
 
        const bool use_invert_vgroup = ((smd->flag & MOD_NORMALEDIT_INVERT_VGROUP) != 0);
        const bool use_current_clnors = !((smd->mix_mode == MOD_NORMALEDIT_MIX_COPY) &&
@@ -352,14 +352,24 @@ static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, Deriv
 
        /* Do not run that modifier at all if autosmooth is disabled! */
        if (!is_valid_target(smd) || !num_loops) {
-               return;
+               return dm;
        }
 
        if (!(me->flag & ME_AUTOSMOOTH)) {
                modifier_setError((ModifierData *)smd, "Enable 'Auto Smooth' option in mesh settings");
-               return;
+               return dm;
        }
 
+       medge = dm->getEdgeArray(dm);
+       if (me->medge == medge) {
+               /* We need to duplicate data here, otherwise setting custom normals (which may also affect sharp edges) could
+                * modify org mesh, see T43671. */
+               dm = CDDM_copy(dm);
+               medge = dm->getEdgeArray(dm);
+       }
+       mvert = dm->getVertArray(dm);
+       mloop = dm->getLoopArray(dm);
+       mpoly = dm->getPolyArray(dm);
 
        if (use_current_clnors) {
                dm->calcLoopNormals(dm, true, me->smoothresh);
@@ -397,6 +407,8 @@ static void normalEditModifier_do(NormalEditModifierData *smd, Object *ob, Deriv
        if (free_polynors) {
                MEM_freeN(polynors);
        }
+
+       return dm;
 }
 
 static void initData(ModifierData *md)
@@ -467,8 +479,7 @@ static void updateDepgraph(ModifierData *md, DagForest *forest, struct Scene *UN
 
 static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag))
 {
-       normalEditModifier_do((NormalEditModifierData *)md, ob, dm);
-       return dm;
+       return normalEditModifier_do((NormalEditModifierData *)md, ob, dm);
 }
 
 ModifierTypeInfo modifierType_NormalEdit = {