Fix #24388: multires base mesh
authorSergey Sharybin <sergey.vfx@gmail.com>
Thu, 4 Nov 2010 16:00:28 +0000 (16:00 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Thu, 4 Nov 2010 16:00:28 +0000 (16:00 +0000)
- MDisp should be re-allocated if face changed amount of vertices
- Allocate disps array in layerSwap_mdisps to prevent loosing all highres data

source/blender/blenkernel/BKE_multires.h
source/blender/blenkernel/intern/customdata.c
source/blender/blenkernel/intern/multires.c
source/blender/editors/mesh/editmesh.c

index 4a9b2ec5c0d79bd53b3f5b8970f4a3695959586f..a05dce81fbcafdb8f9b74626fa0149412cf97721 100644 (file)
@@ -37,6 +37,8 @@ struct Multires;
 struct MultiresModifierData;
 struct ModifierData;
 struct Object;
+struct Scene;
+struct MDisps;
 
 void multires_mark_as_modified(struct Object *ob);
 
@@ -74,5 +76,10 @@ void multires_load_old_250(struct Mesh *);
 void multiresModifier_scale_disp(struct Scene *scene, struct Object *ob);
 void multiresModifier_prepare_join(struct Scene *scene, struct Object *ob, struct Object *to_ob);
 
+int multires_mdisp_corners(struct MDisps *s);
+
+/* update multires data after topology changing */
+void multires_topology_changed(struct Object *ob);
+
 #endif
 
index c1aaa8698760bd4ee76f519ac1ab2938225007d2..cd476d8491bebf9feec0bfb849991b609b4bd7a4 100644 (file)
@@ -50,6 +50,7 @@
 #include "BKE_global.h"
 #include "BKE_main.h"
 #include "BKE_utildefines.h"
+#include "BKE_multires.h"
 
 /* number of layers to add when growing a CustomData object */
 #define CUSTOMDATA_GROW 5
@@ -441,19 +442,6 @@ static void mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, fl
 }
 #endif
 
-static int mdisp_corners(MDisps *s)
-{
-       int lvl= 13;
-
-       while(lvl > 0) {
-               int side = (1 << (lvl-1)) + 1;
-               if ((s->totdisp % (side*side)) == 0) return s->totdisp / (side*side);
-               lvl--;
-       }
-
-       return 0;
-}
-
 static void layerSwap_mdisps(void *data, const int *ci)
 {
        MDisps *s = data;
@@ -462,7 +450,7 @@ static void layerSwap_mdisps(void *data, const int *ci)
 
        if(s->disps) {
                int nverts= (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */
-               corners= mdisp_corners(s);
+               corners= multires_mdisp_corners(s);
                cornersize= s->totdisp/corners;
 
                if(corners!=nverts) {
@@ -470,8 +458,8 @@ static void layerSwap_mdisps(void *data, const int *ci)
                           if it happened, just forgot displacement */
 
                        MEM_freeN(s->disps);
-                       s->disps= NULL;
-                       s->totdisp= 0; /* flag to update totdisp */
+                       s->totdisp= (s->totdisp/corners)*nverts;
+                       s->disps= MEM_callocN(s->totdisp*sizeof(float)*3, "mdisp swap");
                        return;
                }
 
index bf1cd9b9994eda804b5ba9f9f21b9832028243b6..23a81e53728204b8bf85655870312b48f72c21a9 100644 (file)
@@ -305,33 +305,45 @@ int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mm
 }
 
 /* reset the multires levels to match the number of mdisps */
-void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *ob)
+static int get_levels_from_disps(Object *ob)
 {
        Mesh *me = ob->data;
        MDisps *mdisp;
-       int i;
+       int i, totlvl= 0;
 
        mdisp = CustomData_get_layer(&me->fdata, CD_MDISPS);
 
-       if(mdisp) {
-               for(i = 0; i < me->totface; ++i, ++mdisp) {
-                       int S = me->mface[i].v4 ? 4 : 3;
-
-                       if(mdisp->totdisp == 0) continue;
-
-                       while(1) {
-                               int side = (1 << (mmd->totlvl-1)) + 1;
-                               int lvl_totdisp = side*side*S;
-                               if(mdisp->totdisp == lvl_totdisp)
-                                       break;
-                               else if(mdisp->totdisp < lvl_totdisp)
-                                       --mmd->totlvl;
-                               else
-                                       ++mmd->totlvl;
-                                       
-                       }
+       for(i = 0; i < me->totface; ++i, ++mdisp) {
+               int S = me->mface[i].v4 ? 4 : 3;
+
+               if(mdisp->totdisp == 0) continue;
+
+               while(1) {
+                       int side = (1 << (totlvl-1)) + 1;
+                       int lvl_totdisp = side*side*S;
+                       if(mdisp->totdisp == lvl_totdisp)
+                               break;
+                       else if(mdisp->totdisp < lvl_totdisp)
+                               --totlvl;
+                       else
+                               ++totlvl;
+
                }
+       }
 
+       return totlvl;
+}
+
+/* reset the multires levels to match the number of mdisps */
+void multiresModifier_set_levels_from_disps(MultiresModifierData *mmd, Object *ob)
+{
+       Mesh *me = ob->data;
+       MDisps *mdisp;
+
+       mdisp = CustomData_get_layer(&me->fdata, CD_MDISPS);
+
+       if(mdisp) {
+               mmd->totlvl = get_levels_from_disps(ob);
                mmd->lvl = MIN2(mmd->sculptlvl, mmd->totlvl);
                mmd->sculptlvl = MIN2(mmd->sculptlvl, mmd->totlvl);
                mmd->renderlvl = MIN2(mmd->renderlvl, mmd->totlvl);
@@ -1555,6 +1567,19 @@ void multires_apply_smat(Scene *scene, Object *ob, float smat[3][3])
        subdm->release(subdm);
 }
 
+int multires_mdisp_corners(MDisps *s)
+{
+       int lvl= 13;
+
+       while(lvl > 0) {
+               int side = (1 << (lvl-1)) + 1;
+               if ((s->totdisp % (side*side)) == 0) return s->totdisp / (side*side);
+               lvl--;
+       }
+
+       return 0;
+}
+
 void multiresModifier_scale_disp(Scene *scene, Object *ob)
 {
        float smat[3][3];
@@ -1578,3 +1603,27 @@ void multiresModifier_prepare_join(Scene *scene, Object *ob, Object *to_ob)
 
        multires_apply_smat(scene, ob, mat);
 }
+
+/* update multires data after topology changing */
+void multires_topology_changed(Object *ob)
+{
+       Mesh *me= (Mesh*)ob->data;
+       MDisps *mdisp= CustomData_get_layer(&me->fdata, CD_MDISPS);
+       int i;
+
+       if(!mdisp) return;
+
+       for(i = 0; i < me->totface; i++, mdisp++) {
+               int corners= multires_mdisp_corners(mdisp);
+               int nvert= me->mface[i].v4 ? 4 : 3;
+
+               if(corners!=nvert) {
+                       mdisp->totdisp= (mdisp->totdisp/corners)*nvert;
+
+                       if(mdisp->disps)
+                               MEM_freeN(mdisp->disps);
+
+                       mdisp->disps= MEM_callocN(mdisp->totdisp*sizeof(float)*3, "mdisp topology");
+               }
+       }
+}
index 6665e82af198ba9943f50d46ed446f661b336e34..d95a2570e808b8348c474c6b54e5d0b3168eaacb 100644 (file)
@@ -54,6 +54,7 @@
 #include "BKE_mesh.h"
 #include "BKE_paint.h"
 #include "BKE_report.h"
+#include "BKE_multires.h"
 
 #include "ED_mesh.h"
 #include "ED_object.h"
@@ -1306,6 +1307,9 @@ void load_editMesh(Scene *scene, Object *ob)
        }
 
        mesh_calc_normals(me->mvert, me->totvert, me->mface, me->totface, NULL);
+
+       /* topology could be changed, ensure mdisps are ok */
+       multires_topology_changed(ob);
 }
 
 void remake_editMesh(Scene *scene, Object *ob)