Tweak behavior of object.to_mesh()
[blender.git] / source / blender / blenkernel / intern / mesh_convert.c
index f02f1c20abaa7e62f43cc23172e5116a27e7a5f6..f9ab61f1a31989a8bfecc91f5cbc5d42b48d1d15 100644 (file)
@@ -837,7 +837,25 @@ void BKE_mesh_to_curve(Main *bmain, Depsgraph *depsgraph, Scene *UNUSED(scene),
        }
 }
 
        }
 }
 
-/* settings: 1 - preview, 2 - render */
+/* settings: 1 - preview, 2 - render
+ *
+ * The convention goes as following:
+ *
+ * - Passing original object with apply_modifiers=false will give a
+ *   non-modified non-deformed mesh.
+ *   The result mesh will point to datablocks from the original "domain". For
+ *   example, materials will be original.
+ *
+ * - Passing original object with apply_modifiers=true will give a mesh which
+ *   has all modifiers applied.
+ *   The result mesh will point to datablocks from the original "domain". For
+ *   example, materials will be original.
+ *
+ * - Passing evaluated object will ignore apply_modifiers argument, and the
+ *   result always contains all modifiers applied.
+ *   The result mesh will point to an evaluated datablocks. For example,
+ *   materials will be an evaluated IDs from the dependency graph.
+ */
 Mesh *BKE_mesh_new_from_object(
         Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob,
         const bool apply_modifiers, const bool calc_undeformed)
 Mesh *BKE_mesh_new_from_object(
         Depsgraph *depsgraph, Main *bmain, Scene *sce, Object *ob,
         const bool apply_modifiers, const bool calc_undeformed)
@@ -846,11 +864,28 @@ Mesh *BKE_mesh_new_from_object(
        Curve *tmpcu = NULL, *copycu;
        int i;
        const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
        Curve *tmpcu = NULL, *copycu;
        int i;
        const bool render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER);
-       const bool cage = !apply_modifiers;
+       bool effective_apply_modifiers = apply_modifiers;
        bool do_mat_id_data_us = true;
 
        bool do_mat_id_data_us = true;
 
+       Object *object_input = ob;
+       Object *object_eval = DEG_get_evaluated_object(depsgraph, object_input);
+       Object object_for_eval = *object_eval;
+
+       if (object_eval == object_input) {
+               effective_apply_modifiers = false;
+       }
+       else {
+               if (apply_modifiers) {
+                       if (object_for_eval.runtime.mesh_orig != NULL) {
+                               object_for_eval.data = object_for_eval.runtime.mesh_orig;
+                       }
+               }
+       }
+
+       const bool cage = !effective_apply_modifiers;
+
        /* perform the mesh extraction based on type */
        /* perform the mesh extraction based on type */
-       switch (ob->type) {
+       switch (object_for_eval.type) {
                case OB_FONT:
                case OB_CURVE:
                case OB_SURF:
                case OB_FONT:
                case OB_CURVE:
                case OB_SURF:
@@ -861,7 +896,7 @@ Mesh *BKE_mesh_new_from_object(
 
                        /* copies object and modifiers (but not the data) */
                        Object *tmpobj;
 
                        /* copies object and modifiers (but not the data) */
                        Object *tmpobj;
-                       BKE_id_copy_ex(NULL, &ob->id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE);
+                       BKE_id_copy_ex(NULL, &object_for_eval.id, (ID **)&tmpobj, LIB_ID_COPY_LOCALIZE);
                        tmpcu = (Curve *)tmpobj->data;
 
                        /* Copy cached display list, it might be needed by the stack evaluation.
                        tmpcu = (Curve *)tmpobj->data;
 
                        /* Copy cached display list, it might be needed by the stack evaluation.
@@ -870,11 +905,11 @@ Mesh *BKE_mesh_new_from_object(
                         *
                         * TODO(sergey): Look into more proper solution.
                         */
                         *
                         * TODO(sergey): Look into more proper solution.
                         */
-                       if (ob->runtime.curve_cache != NULL) {
+                       if (object_for_eval.runtime.curve_cache != NULL) {
                                if (tmpobj->runtime.curve_cache == NULL) {
                                        tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
                                }
                                if (tmpobj->runtime.curve_cache == NULL) {
                                        tmpobj->runtime.curve_cache = MEM_callocN(sizeof(CurveCache), "CurveCache for curve types");
                                }
-                               BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &ob->runtime.curve_cache->disp);
+                               BKE_displist_copy(&tmpobj->runtime.curve_cache->disp, &object_for_eval.runtime.curve_cache->disp);
                        }
 
                        /* if getting the original caged mesh, delete object modifiers */
                        }
 
                        /* if getting the original caged mesh, delete object modifiers */
@@ -882,7 +917,7 @@ Mesh *BKE_mesh_new_from_object(
                                BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT);
 
                        /* copies the data, but *not* the shapekeys. */
                                BKE_object_free_modifiers(tmpobj, LIB_ID_CREATE_NO_USER_REFCOUNT);
 
                        /* copies the data, but *not* the shapekeys. */
-                       BKE_id_copy_ex(NULL, ob->data, (ID **)&copycu, LIB_ID_COPY_LOCALIZE);
+                       BKE_id_copy_ex(NULL, object_for_eval.data, (ID **)&copycu, LIB_ID_COPY_LOCALIZE);
                        tmpobj->data = copycu;
 
                        /* make sure texture space is calculated for a copy of curve,
                        tmpobj->data = copycu;
 
                        /* make sure texture space is calculated for a copy of curve,
@@ -938,32 +973,34 @@ Mesh *BKE_mesh_new_from_object(
                case OB_MBALL:
                {
                        /* metaballs don't have modifiers, so just convert to mesh */
                case OB_MBALL:
                {
                        /* metaballs don't have modifiers, so just convert to mesh */
-                       Object *basis_ob = BKE_mball_basis_find(sce, ob);
+                       Object *basis_ob = BKE_mball_basis_find(sce, object_input);
                        /* todo, re-generatre for render-res */
                        /* metaball_polygonize(scene, ob) */
 
                        /* todo, re-generatre for render-res */
                        /* metaball_polygonize(scene, ob) */
 
-                       if (ob != basis_ob)
-                               return NULL;  /* only do basis metaball */
+                       if (basis_ob != object_input) {
+                               /* Only do basis metaball. */
+                               return NULL;
+                       }
 
 
-                       tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
+                       tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
                        /* BKE_mesh_add gives us a user count we don't need */
                        id_us_min(&tmpmesh->id);
 
                        if (render) {
                                ListBase disp = {NULL, NULL};
                        /* BKE_mesh_add gives us a user count we don't need */
                        id_us_min(&tmpmesh->id);
 
                        if (render) {
                                ListBase disp = {NULL, NULL};
-                               BKE_displist_make_mball_forRender(depsgraph, sce, ob, &disp);
+                               BKE_displist_make_mball_forRender(depsgraph, sce, &object_for_eval, &disp);
                                BKE_mesh_from_metaball(&disp, tmpmesh);
                                BKE_displist_free(&disp);
                        }
                        else {
                                ListBase disp = {NULL, NULL};
                                BKE_mesh_from_metaball(&disp, tmpmesh);
                                BKE_displist_free(&disp);
                        }
                        else {
                                ListBase disp = {NULL, NULL};
-                               if (ob->runtime.curve_cache) {
-                                       disp = ob->runtime.curve_cache->disp;
+                               if (object_for_eval.runtime.curve_cache) {
+                                       disp = object_for_eval.runtime.curve_cache->disp;
                                }
                                BKE_mesh_from_metaball(&disp, tmpmesh);
                        }
 
                                }
                                BKE_mesh_from_metaball(&disp, tmpmesh);
                        }
 
-                       BKE_mesh_texspace_copy_from_object(tmpmesh, ob);
+                       BKE_mesh_texspace_copy_from_object(tmpmesh, &object_for_eval);
 
                        break;
 
 
                        break;
 
@@ -972,7 +1009,7 @@ Mesh *BKE_mesh_new_from_object(
                        /* copies object and modifiers (but not the data) */
                        if (cage) {
                                /* copies the data (but *not* the shapekeys). */
                        /* copies object and modifiers (but not the data) */
                        if (cage) {
                                /* copies the data (but *not* the shapekeys). */
-                               Mesh *mesh = ob->data;
+                               Mesh *mesh = object_for_eval.data;
                                BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0);
                                /* XXX BKE_mesh_copy() already handles materials usercount. */
                                do_mat_id_data_us = false;
                                BKE_id_copy_ex(bmain, &mesh->id, (ID **)&tmpmesh, 0);
                                /* XXX BKE_mesh_copy() already handles materials usercount. */
                                do_mat_id_data_us = false;
@@ -982,24 +1019,24 @@ Mesh *BKE_mesh_new_from_object(
                                /* Make a dummy mesh, saves copying */
                                Mesh *me_eval;
                                CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter,
                                /* Make a dummy mesh, saves copying */
                                Mesh *me_eval;
                                CustomData_MeshMasks mask = CD_MASK_MESH; /* this seems more suitable, exporter,
-                                                                      * for example, needs CD_MASK_MDEFORMVERT */
+                                                                          * for example, needs CD_MASK_MDEFORMVERT */
 
                                if (calc_undeformed) {
                                        mask.vmask |= CD_MASK_ORCO;
                                }
 
                                if (render) {
 
                                if (calc_undeformed) {
                                        mask.vmask |= CD_MASK_ORCO;
                                }
 
                                if (render) {
-                                       me_eval = mesh_create_eval_final_render(depsgraph, sce, ob, &mask);
+                                       me_eval = mesh_create_eval_final_render(depsgraph, sce, &object_for_eval, &mask);
                                }
                                else {
                                }
                                else {
-                                       me_eval = mesh_create_eval_final_view(depsgraph, sce, ob, &mask);
+                                       me_eval = mesh_create_eval_final_view(depsgraph, sce, &object_for_eval, &mask);
                                }
 
                                }
 
-                               tmpmesh = BKE_mesh_add(bmain, ((ID *)ob->data)->name + 2);
-                               BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, ob, &mask, true);
+                               tmpmesh = BKE_mesh_add(bmain, ((ID *)object_for_eval.data)->name + 2);
+                               BKE_mesh_nomain_to_mesh(me_eval, tmpmesh, &object_for_eval, &mask, true);
 
                                /* Copy autosmooth settings from original mesh. */
 
                                /* Copy autosmooth settings from original mesh. */
-                               Mesh *me = (Mesh *)ob->data;
+                               Mesh *me = (Mesh *)object_for_eval.data;
                                tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
                                tmpmesh->smoothresh = me->smoothresh;
                        }
                                tmpmesh->flag |= (me->flag & ME_AUTOSMOOTH);
                                tmpmesh->smoothresh = me->smoothresh;
                        }
@@ -1014,7 +1051,7 @@ Mesh *BKE_mesh_new_from_object(
        }
 
        /* Copy materials to new mesh */
        }
 
        /* Copy materials to new mesh */
-       switch (ob->type) {
+       switch (object_for_eval.type) {
                case OB_SURF:
                case OB_FONT:
                case OB_CURVE:
                case OB_SURF:
                case OB_FONT:
                case OB_CURVE:
@@ -1024,9 +1061,9 @@ Mesh *BKE_mesh_new_from_object(
                        if (tmpcu->mat) {
                                for (i = tmpcu->totcol; i-- > 0; ) {
                                        /* are we an object material or data based? */
                        if (tmpcu->mat) {
                                for (i = tmpcu->totcol; i-- > 0; ) {
                                        /* are we an object material or data based? */
-                                       tmpmesh->mat[i] = give_current_material(ob, i + 1);
+                                       tmpmesh->mat[i] = give_current_material(object_input, i + 1);
 
 
-                                       if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us)  && tmpmesh->mat[i]) {
+                                       if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us)  && tmpmesh->mat[i]) {
                                                id_us_plus(&tmpmesh->mat[i]->id);
                                        }
                                }
                                                id_us_plus(&tmpmesh->mat[i]->id);
                                        }
                                }
@@ -1035,7 +1072,7 @@ Mesh *BKE_mesh_new_from_object(
 
                case OB_MBALL:
                {
 
                case OB_MBALL:
                {
-                       MetaBall *tmpmb = (MetaBall *)ob->data;
+                       MetaBall *tmpmb = (MetaBall *)object_for_eval.data;
                        tmpmesh->mat = MEM_dupallocN(tmpmb->mat);
                        tmpmesh->totcol = tmpmb->totcol;
 
                        tmpmesh->mat = MEM_dupallocN(tmpmb->mat);
                        tmpmesh->totcol = tmpmb->totcol;
 
@@ -1043,9 +1080,9 @@ Mesh *BKE_mesh_new_from_object(
                        if (tmpmb->mat) {
                                for (i = tmpmb->totcol; i-- > 0; ) {
                                        /* are we an object material or data based? */
                        if (tmpmb->mat) {
                                for (i = tmpmb->totcol; i-- > 0; ) {
                                        /* are we an object material or data based? */
-                                       tmpmesh->mat[i] = give_current_material(ob, i + 1);
+                                       tmpmesh->mat[i] = give_current_material(object_input, i + 1);
 
 
-                                       if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
+                                       if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
                                                id_us_plus(&tmpmesh->mat[i]->id);
                                        }
                                }
                                                id_us_plus(&tmpmesh->mat[i]->id);
                                        }
                                }
@@ -1055,7 +1092,7 @@ Mesh *BKE_mesh_new_from_object(
 
                case OB_MESH:
                        if (!cage) {
 
                case OB_MESH:
                        if (!cage) {
-                               Mesh *origmesh = ob->data;
+                               Mesh *origmesh = object_for_eval.data;
                                tmpmesh->flag = origmesh->flag;
                                tmpmesh->mat = MEM_dupallocN(origmesh->mat);
                                tmpmesh->totcol = origmesh->totcol;
                                tmpmesh->flag = origmesh->flag;
                                tmpmesh->mat = MEM_dupallocN(origmesh->mat);
                                tmpmesh->totcol = origmesh->totcol;
@@ -1063,9 +1100,9 @@ Mesh *BKE_mesh_new_from_object(
                                if (origmesh->mat) {
                                        for (i = origmesh->totcol; i-- > 0; ) {
                                                /* are we an object material or data based? */
                                if (origmesh->mat) {
                                        for (i = origmesh->totcol; i-- > 0; ) {
                                                /* are we an object material or data based? */
-                                               tmpmesh->mat[i] = give_current_material(ob, i + 1);
+                                               tmpmesh->mat[i] = give_current_material(object_input, i + 1);
 
 
-                                               if (((ob->matbits && ob->matbits[i]) || do_mat_id_data_us)  && tmpmesh->mat[i]) {
+                                               if (((object_for_eval.matbits && object_for_eval.matbits[i]) || do_mat_id_data_us) && tmpmesh->mat[i]) {
                                                        id_us_plus(&tmpmesh->mat[i]->id);
                                                }
                                        }
                                                        id_us_plus(&tmpmesh->mat[i]->id);
                                                }
                                        }