Multires: Prepare for cached topology
authorSergey Sharybin <sergey.vfx@gmail.com>
Wed, 16 Jan 2019 09:58:35 +0000 (10:58 +0100)
committerSergey Sharybin <sergey.vfx@gmail.com>
Wed, 16 Jan 2019 10:00:43 +0000 (11:00 +0100)
Note that the actual caching is still disabled, since
more tests is needed with more production-looking files.

source/blender/blenloader/intern/readfile.c
source/blender/makesdna/DNA_modifier_types.h
source/blender/modifiers/intern/MOD_multires.c

index 0094a6a..ff79ba0 100644 (file)
@@ -5393,6 +5393,10 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb)
                        BevelModifierData *bmd = (BevelModifierData *)md;
                        bmd->clnordata.faceHash = NULL;
                }
+               else if (md->type == eModifierType_Multires) {
+                       MultiresModifierData *mmd = (MultiresModifierData *)md;
+                       mmd->subdiv = NULL;
+               }
        }
 }
 
index 30c093a..101d655 100644 (file)
@@ -949,6 +949,8 @@ typedef struct MultiresModifierData {
        short quality;
        short uv_smooth;
        short pad2[2];
+       struct Subdiv *subdiv;
+       void *pad3;
 } MultiresModifierData;
 
 typedef enum {
index fc8a376..9775a53 100644 (file)
@@ -67,6 +67,28 @@ static void initData(ModifierData *md)
        mmd->quality = 3;
 }
 
+static void freeData(ModifierData *md)
+{
+       MultiresModifierData *mmd = (MultiresModifierData *) md;
+       if (mmd->subdiv != NULL) {
+               BKE_subdiv_free(mmd->subdiv);
+       }
+}
+
+/* Main goal of this function is to give usable subdivision surface descriptor
+ * which matches settings and topology. */
+static Subdiv *subdiv_descriptor_ensure(MultiresModifierData *mmd,
+                                        const SubdivSettings *subdiv_settings,
+                                        const Mesh *mesh)
+{
+       Subdiv *subdiv = BKE_subdiv_update_from_mesh(
+               mmd->subdiv, subdiv_settings, mesh);
+       if (false) {
+               mmd->subdiv = subdiv;
+       }
+       return subdiv;
+}
+
 /* Subdivide into fully qualified mesh. */
 
 static Mesh *multires_as_mesh(MultiresModifierData *mmd,
@@ -137,16 +159,14 @@ static Mesh *applyModifier(ModifierData *md,
        if (subdiv_settings.level == 0) {
                return result;
        }
-       /* TODO(sergey): Try to re-use subdiv when possible. */
-       Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, mesh);
+       Subdiv *subdiv = subdiv_descriptor_ensure(mmd, &subdiv_settings, mesh);
        if (subdiv == NULL) {
                /* Happens on bad topology, ut also on empty input mesh. */
                return result;
        }
        /* NOTE: Orco needs final coordinates on CPU side, which are expected to be
         * accessible via MVert. For this reason we do not evaluate multires to
-        * grids when orco is requested.
-        */
+        * grids when orco is requested. */
        const bool for_orco = (ctx->flag & MOD_APPLY_ORCO) != 0;
        if ((ctx->object->mode & OB_MODE_SCULPT) && !for_orco) {
                /* NOTE: CCG takes ownership over Subdiv. */
@@ -156,9 +176,10 @@ static Mesh *applyModifier(ModifierData *md,
        }
        else {
                result = multires_as_mesh(mmd, ctx, mesh, subdiv);
-               /* TODO(sergey): Cache subdiv somehow. */
                // BKE_subdiv_stats_print(&subdiv->stats);
-               BKE_subdiv_free(subdiv);
+               if (subdiv != mmd->subdiv) {
+                       BKE_subdiv_free(subdiv);
+               }
        }
        return result;
 }
@@ -188,7 +209,7 @@ ModifierTypeInfo modifierType_Multires = {
 
        /* initData */          initData,
        /* requiredDataMask */  NULL,
-       /* freeData */          NULL,
+       /* freeData */          freeData,
        /* isDisabled */        NULL,
        /* updateDepsgraph */   NULL,
        /* dependsOnTime */     NULL,