Fix T63283: Second subdivision modifier does not ignore crease
[blender.git] / source / blender / modifiers / intern / MOD_multires.c
index aca16fe..a8760d0 100644 (file)
 
 #include <stddef.h>
 
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
 #include "DNA_mesh_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
 
-#include "BLI_utildefines.h"
-
 #include "BKE_cdderivedmesh.h"
 #include "BKE_mesh.h"
 #include "BKE_multires.h"
 #include "BKE_modifier.h"
+#include "BKE_paint.h"
 #include "BKE_subdiv.h"
 #include "BKE_subdiv_ccg.h"
 #include "BKE_subdiv_mesh.h"
 
 #include "MOD_modifiertypes.h"
 
+typedef struct MultiresRuntimeData {
+       /* Cached subdivision surface descriptor, with topology and settings. */
+       struct Subdiv *subdiv;
+} MultiresRuntimeData;
+
 static void initData(ModifierData *md)
 {
        MultiresModifierData *mmd = (MultiresModifierData *)md;
@@ -53,23 +61,41 @@ static void initData(ModifierData *md)
        mmd->totlvl = 0;
        mmd->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS;
        mmd->quality = 3;
+       mmd->flags |= eMultiresModifierFlag_UseCrease;
 }
 
 static void copyData(const ModifierData *md_src, ModifierData *md_dst, const int flag)
 {
-       MultiresModifierData *mmd_dst = (MultiresModifierData *)md_dst;
-
        modifier_copyData_generic(md_src, md_dst, flag);
+}
 
-       mmd_dst->subdiv = NULL;
+static void freeRuntimeData(void *runtime_data_v)
+{
+       if (runtime_data_v == NULL) {
+               return;
+       }
+       MultiresRuntimeData *runtime_data = (MultiresRuntimeData *)runtime_data_v;
+       if (runtime_data->subdiv != NULL) {
+               BKE_subdiv_free(runtime_data->subdiv);
+       }
+       MEM_freeN(runtime_data);
 }
 
 static void freeData(ModifierData *md)
 {
        MultiresModifierData *mmd = (MultiresModifierData *) md;
-       if (mmd->subdiv != NULL) {
-               BKE_subdiv_free(mmd->subdiv);
+       freeRuntimeData(mmd->modifier.runtime);
+}
+
+static MultiresRuntimeData *multires_ensure_runtime(MultiresModifierData *mmd)
+{
+       MultiresRuntimeData *runtime_data =
+               (MultiresRuntimeData *)mmd->modifier.runtime;
+       if (runtime_data == NULL) {
+               runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime");
+               mmd->modifier.runtime = runtime_data;
        }
+       return runtime_data;
 }
 
 /* Main goal of this function is to give usable subdivision surface descriptor
@@ -78,9 +104,11 @@ static Subdiv *subdiv_descriptor_ensure(MultiresModifierData *mmd,
                                         const SubdivSettings *subdiv_settings,
                                         const Mesh *mesh)
 {
+       MultiresRuntimeData *runtime_data =
+               (MultiresRuntimeData *)mmd->modifier.runtime;
        Subdiv *subdiv = BKE_subdiv_update_from_mesh(
-               mmd->subdiv, subdiv_settings, mesh);
-       mmd->subdiv = subdiv;
+               runtime_data->subdiv, subdiv_settings, mesh);
+       runtime_data->subdiv = subdiv;
        return subdiv;
 }
 
@@ -98,7 +126,7 @@ static Mesh *multires_as_mesh(MultiresModifierData *mmd,
        Object *object = ctx->object;
        SubdivToMeshSettings mesh_settings;
        BKE_multires_subdiv_mesh_settings_init(
-        &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify);
+               &mesh_settings, scene, object, mmd, use_render_params, ignore_simplify);
        if (mesh_settings.resolution < 3) {
                return result;
        }
@@ -155,6 +183,7 @@ static Mesh *applyModifier(ModifierData *md,
                return result;
        }
        BKE_subdiv_settings_validate_for_mesh(&subdiv_settings, mesh);
+       MultiresRuntimeData *runtime_data = multires_ensure_runtime(mmd);
        Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
        if (subdiv == NULL) {
                /* Happens on bad topology, ut also on empty input mesh. */
@@ -168,16 +197,24 @@ static Mesh *applyModifier(ModifierData *md,
                /* NOTE: CCG takes ownership over Subdiv. */
                result = multires_as_ccg(mmd, ctx, mesh, subdiv);
                result->runtime.subdiv_ccg_tot_level = mmd->totlvl;
+               /* TODO(sergey): Usually it is sculpt stroke's update variants which
+                * takes care of this, but is possible that we need this before the
+                * stroke: i.e. when exiting blender right after stroke is done.
+                * Annoying and not so much black-boxed as far as sculpting goes, and
+                * surely there is a better way of solving this. */
+               if (ctx->object->sculpt != NULL) {
+                       ctx->object->sculpt->subdiv_ccg = result->runtime.subdiv_ccg;
+               }
                /* NOTE: CCG becomes an owner of Subdiv descriptor, so can not share
                 * this pointer. Not sure if it's needed, but might have a second look
                 * on the ownership model here. */
-               mmd->subdiv = NULL;
+               runtime_data->subdiv = NULL;
                // BKE_subdiv_stats_print(&subdiv->stats);
        }
        else {
                result = multires_as_mesh(mmd, ctx, mesh, subdiv);
                // BKE_subdiv_stats_print(&subdiv->stats);
-               if (subdiv != mmd->subdiv) {
+               if (subdiv != runtime_data->subdiv) {
                        BKE_subdiv_free(subdiv);
                }
        }
@@ -195,12 +232,6 @@ ModifierTypeInfo modifierType_Multires = {
 
        /* copyData */          copyData,
 
-       /* deformVerts_DM */    NULL,
-       /* deformMatrices_DM */ NULL,
-       /* deformVertsEM_DM */  NULL,
-       /* deformMatricesEM_DM*/NULL,
-       /* applyModifier_DM */  NULL,
-
        /* deformVerts */       NULL,
        /* deformMatrices */    NULL,
        /* deformVertsEM */     NULL,
@@ -217,4 +248,5 @@ ModifierTypeInfo modifierType_Multires = {
        /* foreachObjectLink */ NULL,
        /* foreachIDLink */     NULL,
        /* foreachTexLink */    NULL,
+       /* freeRuntimeData */   freeRuntimeData,
 };