/WX enabled for MSVC in CMake too.
[blender.git] / source / blender / blenkernel / intern / multires.c
index a709b45..91f15d1 100644 (file)
@@ -15,7 +15,7 @@
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software  Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
  * The Original Code is Copyright (C) 2007 by Nicholas Bishop
  * All rights reserved.
 
 #include "MEM_guardedalloc.h"
 
-#include "DNA_key_types.h"
 #include "DNA_mesh_types.h"
 #include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
 #include "DNA_object_types.h"
 #include "DNA_scene_types.h"
-#include "DNA_view3d_types.h"
 
-#include "BLI_math.h"
 #include "BLI_blenlib.h"
+#include "BLI_math.h"
+#include "BLI_pbvh.h"
 
-#include "BKE_btex.h"
 #include "BKE_cdderivedmesh.h"
-#include "BKE_customdata.h"
-#include "BKE_depsgraph.h"
-#include "BKE_DerivedMesh.h"
-#include "BKE_global.h"
 #include "BKE_mesh.h"
 #include "BKE_modifier.h"
 #include "BKE_multires.h"
-#include "BKE_object.h"
+#include "BKE_paint.h"
+#include "BKE_scene.h"
 #include "BKE_subsurf.h"
 #include "BKE_utildefines.h"
 
 
 /* MULTIRES MODIFIER */
 static const int multires_max_levels = 13;
-static const int multires_grid_tot[] = {1, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
-static const int multires_side_tot[] = {1, 2, 3, 5,  9,  17,  33,   65,   129,   257,   513,    1025,    2049,    4097};
+static const int multires_grid_tot[] = {0, 4, 9, 25, 81, 289, 1089, 4225, 16641, 66049, 263169, 1050625, 4198401, 16785409};
+static const int multires_side_tot[] = {0, 2, 3, 5,  9,  17,  33,   65,   129,   257,   513,    1025,    2049,    4097};
 
+static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert);
 static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int add, DMGridData **oldGridData, int totlvl);
 
-MultiresModifierData *find_multires_modifier(Object *ob)
+DerivedMesh *get_multires_dm(Scene *scene, MultiresModifierData *mmd, Object *ob)
+{
+       ModifierData *md= (ModifierData *)mmd;
+       ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+       DerivedMesh *tdm = mesh_get_derived_deform(scene, ob, CD_MASK_BAREMESH);
+       DerivedMesh *dm;
+
+       dm = mti->applyModifier(md, ob, tdm, 0, 1);
+       if (dm == tdm) {
+               dm = CDDM_copy(tdm);
+       }
+
+       return dm;
+}
+
+MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd)
 {
        ModifierData *md;
-       MultiresModifierData *mmd = NULL;
 
-       for(md = ob->modifiers.first; md; md = md->next) {
+       for(md = lastmd; md; md = md->prev) {
                if(md->type == eModifierType_Multires) {
-                       mmd = (MultiresModifierData*)md;
-                       break;
+                       if (modifier_isEnabled(scene, md, eModifierMode_Realtime))
+                               return (MultiresModifierData*)md;
                }
        }
 
-       return mmd;
+       return NULL;
 }
 
 static int multires_get_level(Object *ob, MultiresModifierData *mmd, int render)
 {
        if(render)
-               return mmd->renderlvl;
+               return (mmd->modifier.scene)? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->renderlvl): mmd->renderlvl;
        else if(ob->mode == OB_MODE_SCULPT)
                return mmd->sculptlvl;
        else
-               return mmd->lvl;
+               return (mmd->modifier.scene)? get_render_subsurf_level(&mmd->modifier.scene->r, mmd->lvl): mmd->lvl;
 }
 
 static void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl)
 {
        mmd->totlvl = lvl;
 
-       if(ob->mode != OB_MODE_SCULPT) {
-               mmd->lvl = MAX2(mmd->lvl, lvl);
-               CLAMP(mmd->lvl, 0, mmd->totlvl);
+       if(ob->mode != OB_MODE_SCULPT)
+               mmd->lvl = CLAMPIS(MAX2(mmd->lvl, lvl), 0, mmd->totlvl);
+
+       mmd->sculptlvl = CLAMPIS(MAX2(mmd->sculptlvl, lvl), 0, mmd->totlvl);
+       mmd->renderlvl = CLAMPIS(MAX2(mmd->renderlvl, lvl), 0, mmd->totlvl);
+}
+
+static void multires_dm_mark_as_modified(DerivedMesh *dm)
+{
+       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
+       ccgdm->multires.modified = 1;
+}
+
+void multires_mark_as_modified(Object *ob)
+{
+       if(ob && ob->derivedFinal)
+               multires_dm_mark_as_modified(ob->derivedFinal);
+}
+
+void multires_force_update(Object *ob)
+{
+       if(ob) {
+               if(ob->derivedFinal) {
+                       ob->derivedFinal->needsFree =1;
+                       ob->derivedFinal->release(ob->derivedFinal);
+                       ob->derivedFinal = NULL;
+               }
+               if(ob->sculpt && ob->sculpt->pbvh) {
+                       BLI_pbvh_free(ob->sculpt->pbvh);
+                       ob->sculpt->pbvh= NULL;
+               }
        }
+}
 
-       mmd->sculptlvl = MAX2(mmd->sculptlvl, lvl);
-       CLAMP(mmd->sculptlvl, 0, mmd->totlvl);
+void multires_force_external_reload(Object *ob)
+{
+       Mesh *me = get_mesh(ob);
 
-       mmd->renderlvl = MAX2(mmd->renderlvl, lvl);
-       CLAMP(mmd->renderlvl, 0, mmd->totlvl);
+       CustomData_external_reload(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
+       multires_force_update(ob);
+}
+
+void multires_force_render_update(Object *ob)
+{
+       if(ob && (ob->mode & OB_MODE_SCULPT) && modifiers_findByType(ob, eModifierType_Multires))
+               multires_force_update(ob);
 }
 
 /* XXX */
@@ -168,30 +213,133 @@ void multiresModifier_join(Object *ob)
 }
 #endif
 
-/* Returns 0 on success, 1 if the src's totvert doesn't match */
-int multiresModifier_reshape(MultiresModifierData *mmd, Object *dst, Object *src)
+int multiresModifier_reshapeFromDM(Scene *scene, MultiresModifierData *mmd,
+                               Object *ob, DerivedMesh *srcdm)
 {
-       /* XXX */
-#if 0
-       Mesh *src_me = get_mesh(src);
-       DerivedMesh *mrdm = dst->derivedFinal;
+       DerivedMesh *mrdm = get_multires_dm (scene, mmd, ob);
 
-       if(mrdm && mrdm->getNumVerts(mrdm) == src_me->totvert) {
-               MVert *mvert = CDDM_get_verts(mrdm);
-               int i;
+       if(mrdm && srcdm && mrdm->getNumVerts(mrdm) == srcdm->getNumVerts(srcdm)) {
+               multires_mvert_to_ss(mrdm, srcdm->getVertArray(srcdm));
+
+               multires_dm_mark_as_modified(mrdm);
+               multires_force_update(ob);
 
-               for(i = 0; i < src_me->totvert; ++i)
-                       copy_v3_v3(mvert[i].co, src_me->mvert[i].co);
-               mrdm->needsFree = 1;
-               MultiresDM_mark_as_modified(mrdm);
                mrdm->release(mrdm);
-               dst->derivedFinal = NULL;
 
+               return 1;
+       }
+
+       mrdm->release(mrdm);
+
+       return 0;
+}
+
+/* Returns 1 on success, 0 if the src's totvert doesn't match */
+int multiresModifier_reshape(Scene *scene, MultiresModifierData *mmd, Object *dst, Object *src)
+{
+       DerivedMesh *srcdm = mesh_get_derived_final(scene, src, CD_MASK_BAREMESH);
+       return multiresModifier_reshapeFromDM(scene, mmd, dst, srcdm);
+}
+
+int multiresModifier_reshapeFromDeformMod(Scene *scene, MultiresModifierData *mmd,
+                               Object *ob, ModifierData *md)
+{
+       ModifierTypeInfo *mti = modifierType_getInfo(md->type);
+       DerivedMesh *dm, *ndm;
+       int numVerts, result;
+       float (*deformedVerts)[3];
+
+       if(multires_get_level(ob, mmd, 0) == 0)
                return 0;
+
+       /* Create DerivedMesh for deformation modifier */
+       dm = get_multires_dm(scene, mmd, ob);
+       numVerts= dm->getNumVerts(dm);
+       deformedVerts= MEM_callocN(sizeof(float)*numVerts*3, "multiresReshape_deformVerts");
+
+       dm->getVertCos(dm, deformedVerts);
+       mti->deformVerts(md, ob, dm, deformedVerts, numVerts, 0, 0);
+
+       ndm= CDDM_copy(dm);
+       CDDM_apply_vert_coords(ndm, deformedVerts);
+
+       MEM_freeN(deformedVerts);
+       dm->release(dm);
+
+       /* Reshaping */
+       result= multiresModifier_reshapeFromDM(scene, mmd, ob, ndm);
+
+       /* Cleanup */
+       ndm->release(ndm);
+
+       return result;
+}
+
+/* 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;
+       int i;
+
+       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;
+                                       
+                       }
+               }
+
+               mmd->lvl = MIN2(mmd->sculptlvl, mmd->totlvl);
+               mmd->sculptlvl = MIN2(mmd->sculptlvl, mmd->totlvl);
+               mmd->renderlvl = MIN2(mmd->renderlvl, mmd->totlvl);
        }
-#endif
+}
+
+static void multires_set_tot_mdisps(Mesh *me, int lvl)
+{
+       MDisps *mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
+       int i;
 
-       return 1;
+       if(mdisps) {
+               for(i = 0; i < me->totface; i++) {
+                       if(mdisps[i].totdisp == 0) {
+                               int nvert = (me->mface[i].v4)? 4: 3;
+                               mdisps[i].totdisp = multires_grid_tot[lvl]*nvert;
+                       }
+               }
+       }
+}
+
+static void multires_reallocate_mdisps(Mesh *me, MDisps *mdisps, int lvl)
+{
+       int i;
+
+       /* reallocate displacements to be filled in */
+       for(i = 0; i < me->totface; ++i) {
+               int nvert = (me->mface[i].v4)? 4: 3;
+               int totdisp = multires_grid_tot[lvl]*nvert;
+               float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
+
+               if(mdisps[i].disps)
+                       MEM_freeN(mdisps[i].disps);
+
+               mdisps[i].disps = disps;
+               mdisps[i].totdisp = totdisp;
+       }
 }
 
 static void column_vectors_to_mat3(float mat[][3], float v1[3], float v2[3], float v3[3])
@@ -242,45 +390,52 @@ static void multires_copy_dm_grid(DMGridData *gridA, DMGridData *gridB, int size
 }
 
 /* direction=1 for delete higher, direction=0 for lower (not implemented yet) */
-void multiresModifier_del_levels(struct MultiresModifierData *mmd, struct Object *ob, int direction)
+void multiresModifier_del_levels(MultiresModifierData *mmd, Object *ob, int direction)
 {
        Mesh *me = get_mesh(ob);
        int lvl = multires_get_level(ob, mmd, 0);
        int levels = mmd->totlvl - lvl;
        MDisps *mdisps;
-       
-       CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface);
+
+       multires_set_tot_mdisps(me, mmd->totlvl);
+       CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
        mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
 
        multires_force_update(ob);
 
        if(mdisps && levels > 0 && direction == 1) {
-               int nsize = multires_side_tot[lvl];
-               int hsize = multires_side_tot[mmd->totlvl];
-               int i;
+               if(lvl > 0) {
+                       int nsize = multires_side_tot[lvl];
+                       int hsize = multires_side_tot[mmd->totlvl];
+                       int i;
 
-               for(i = 0; i < me->totface; ++i) {
-                       MDisps *mdisp= &mdisps[i];
-                       float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
-                       int nvert = (me->mface[i].v4)? 4: 3;
-                       int totdisp = multires_grid_tot[lvl]*nvert;
-                       int S;
+                       for(i = 0; i < me->totface; ++i) {
+                               MDisps *mdisp= &mdisps[i];
+                               float (*disps)[3], (*ndisps)[3], (*hdisps)[3];
+                               int nvert = (me->mface[i].v4)? 4: 3;
+                               int totdisp = multires_grid_tot[lvl]*nvert;
+                               int S;
 
-                       disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
+                               disps = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
 
-                       ndisps = disps;
-                       hdisps = mdisp->disps;
+                               ndisps = disps;
+                               hdisps = mdisp->disps;
 
-                       for(S = 0; S < nvert; S++) {
-                               multires_copy_grid(ndisps, hdisps, nsize, hsize);
+                               for(S = 0; S < nvert; S++) {
+                                       multires_copy_grid(ndisps, hdisps, nsize, hsize);
 
-                               ndisps += nsize*nsize;
-                               hdisps += hsize*hsize;
-                       }
+                                       ndisps += nsize*nsize;
+                                       hdisps += hsize*hsize;
+                               }
 
-                       MEM_freeN(mdisp->disps);
-                       mdisp->disps = disps;
-                       mdisp->totdisp = totdisp;
+                               MEM_freeN(mdisp->disps);
+                               mdisp->disps = disps;
+                               mdisp->totdisp = totdisp;
+                       }
+               }
+               else {
+                       CustomData_external_remove(&me->fdata, &me->id, CD_MDISPS, me->totface);
+                       CustomData_free_layer_active(&me->fdata, CD_MDISPS, me->totface);
                }
        }
 
@@ -301,7 +456,7 @@ static DerivedMesh *multires_dm_create_local(Object *ob, DerivedMesh *dm, int lv
        return multires_dm_create_from_derived(&mmd, 1, dm, ob, 0, 0);
 }
 
-static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl, int simple)
+static DerivedMesh *subsurf_dm_create_local(Object *UNUSED(ob), DerivedMesh *dm, int lvl, int simple, int optimal)
 {
        SubsurfModifierData smd;
 
@@ -310,28 +465,12 @@ static DerivedMesh *subsurf_dm_create_local(Object *ob, DerivedMesh *dm, int lvl
        smd.flags |= eSubsurfModifierFlag_SubsurfUv;
        if(simple)
                smd.subdivType = ME_SIMPLE_SUBSURF;
+       if(optimal)
+               smd.flags |= eSubsurfModifierFlag_ControlEdges;
 
        return subsurf_make_derived_from_derived(dm, &smd, 0, NULL, 0, 0);
 }
 
-static void multires_reallocate_mdisps(Mesh *me, MDisps *mdisps, int lvl)
-{
-       int i;
-
-       /* reallocate displacements to be filled in */
-       for(i = 0; i < me->totface; ++i) {
-               int nvert = (me->mface[i].v4)? 4: 3;
-               int totdisp = multires_grid_tot[lvl]*nvert;
-               float (*disps)[3] = MEM_callocN(sizeof(float) * 3 * totdisp, "multires disps");
-
-               if(mdisps[i].disps)
-                       MEM_freeN(mdisps[i].disps);
-
-               mdisps[i].disps = disps;
-               mdisps[i].totdisp = totdisp;
-       }
-}
-
 void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updateblock, int simple)
 {
        Mesh *me = ob->data;
@@ -357,7 +496,8 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
 
                /* create subsurf DM from original mesh at high level */
                cddm = CDDM_from_mesh(me, NULL);
-               highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple);
+               DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+               highdm = subsurf_dm_create_local(ob, cddm, totlvl, simple, 0);
 
                /* create multires DM from original mesh at low level */
                lowdm = multires_dm_create_local(ob, cddm, lvl, lvl, simple);
@@ -409,105 +549,27 @@ void multiresModifier_subdivide(MultiresModifierData *mmd, Object *ob, int updat
        multires_set_tot_level(ob, mmd, totlvl);
 }
 
-static void grid_adjacent_rotate(int rotation, int gridSize, int *x, int *y)
-{
-       /* we rotate (rotation * 90°) counterclockwise around center */
-       int nx, ny;
-
-       switch(rotation) {
-               case 0: nx = *x; ny = *y; break;
-               case 1: nx = *y; ny = *x; break;
-               case 2: nx = *x; ny = *y; break; //gridSize - 1 - *x; ny = gridSize - 1 - *y; break;
-               case 3: nx = *y; ny = *x; break;
-       }
-
-       *x = nx;
-       *y = ny;
-}
-
-static void grid_adjacent_jump(DMGridAdjacency *adj, int gridSize, int *index, int *x, int *y)
-{
-       if(*x < 0) {
-               if(adj->index[3] == -1) {
-                       /* no adjacent grid, clamp */
-                       *x = 0;
-               }
-               else {
-                       /* jump to adjacent grid */
-                       *index = adj->index[3];
-                       *x += gridSize;
-                       grid_adjacent_rotate(adj->rotation[3], gridSize, x, y);
-               }
-       }
-       else if(*x >= gridSize) {
-               if(adj->index[1] == -1) {
-                       /* no adjacent grid, take a step back */
-                       *x = gridSize - 1;
-               }
-               else {
-                       /* jump to adjacent grid */
-                       *index = adj->index[1];
-                       *x -= gridSize;
-                       grid_adjacent_rotate(adj->rotation[1], gridSize, x, y);
-               }
-       }
-       else if(*y < 0) {
-               if(adj->index[0] == -1) {
-                       /* no adjacent grid, clamp */
-                       *y = 0;
-               }
-               else {
-                       /* jump to adjacent grid */
-                       *index = adj->index[0];
-                       *y += gridSize;
-                       grid_adjacent_rotate(adj->rotation[0], gridSize, x, y);
-               }
-       }
-       else if(*y >= gridSize) {
-               if(adj->index[2] == -1) {
-                       /* no adjacent grid, take a step back */
-                       *y = gridSize - 1;
-               }
-               else {
-                       /* jump to adjacent grid */
-                       *index = adj->index[2];
-                       *y -= gridSize;
-                       grid_adjacent_rotate(adj->rotation[2], gridSize, x, y);
-               }
-       }
-}
-
-static void grid_tangent(DMGridAdjacency *adj, int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
+static void grid_tangent(int gridSize, int index, int x, int y, int axis, DMGridData **gridData, float t[3])
 {
-       int jindex = index, jx = x, jy = y;
-
        if(axis == 0) {
-               if(adj->index[1] == -1 && x == gridSize - 1) {
-                       if(adj->index[2] == -1 && y == gridSize - 1)
+               if(x == gridSize - 1) {
+                       if(y == gridSize - 1)
                                sub_v3_v3v3(t, gridData[index][x + gridSize*(y - 1)].co, gridData[index][x - 1 + gridSize*(y - 1)].co);
                        else
                                sub_v3_v3v3(t, gridData[index][x + gridSize*y].co, gridData[index][x - 1 + gridSize*y].co);
                }
-               else {
-                       jx += 1;
-                       grid_adjacent_jump(adj, gridSize, &jindex, &jx, &jy);
-                       sub_v3_v3v3(t, gridData[jindex][jx + gridSize*jy].co, gridData[index][x + gridSize*y].co);
-               }
+               else
+                       sub_v3_v3v3(t, gridData[index][x + 1 + gridSize*y].co, gridData[index][x + gridSize*y].co);
        }
        else if(axis == 1) {
-               if(adj->index[2] == -1 && y == gridSize - 1) {
-                       if(adj->index[1] == -1 && x == gridSize - 1) {
+               if(y == gridSize - 1) {
+                       if(x == gridSize - 1)
                                sub_v3_v3v3(t, gridData[index][x - 1 + gridSize*y].co, gridData[index][x - 1 + gridSize*(y - 1)].co);
-                       }
-                       else {
+                       else
                                sub_v3_v3v3(t, gridData[index][x + gridSize*y].co, gridData[index][x + gridSize*(y - 1)].co);
-                       }
-               }
-               else {
-                       jy += 1;
-                       grid_adjacent_jump(adj, gridSize, &jindex, &jx, &jy);
-                       sub_v3_v3v3(t, gridData[jindex][jx + gridSize*jy].co, gridData[index][x + gridSize*y].co);
                }
+               else
+                       sub_v3_v3v3(t, gridData[index][x + gridSize*(y + 1)].co, gridData[index][x + gridSize*y].co);
        }
 }
 
@@ -515,28 +577,43 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
 {
        CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)dm;
        DMGridData **gridData, **subGridData;
-       DMGridAdjacency *gridAdjacency;
        MFace *mface = me->mface;
        MDisps *mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
-       int i, S, x, y, numGrids, gIndex, gridSize, dGridSize, dSkip;
+       int *gridOffset;
+       int i, numGrids, gridSize, dGridSize, dSkip;
+
+       if(!mdisps) {
+               if(invert)
+                       mdisps = CustomData_add_layer(&me->fdata, CD_MDISPS, CD_DEFAULT, NULL, me->totface);
+               else
+                       return;
+       }
 
        numGrids = dm->getNumGrids(dm);
        gridSize = dm->getGridSize(dm);
        gridData = dm->getGridData(dm);
-       gridAdjacency = dm->getGridAdjacency(dm);
+       gridOffset = dm->getGridOffset(dm);
        subGridData = (oldGridData)? oldGridData: gridData;
 
        dGridSize = multires_side_tot[totlvl];
        dSkip = (dGridSize-1)/(gridSize-1);
 
-       for(gIndex = 0, i = 0; i < me->totface; ++i) {
+       #pragma omp parallel for private(i) if(me->totface*gridSize*gridSize*4 >= CCG_OMP_LIMIT)
+       for(i = 0; i < me->totface; ++i) {
                const int numVerts = mface[i].v4 ? 4 : 3;
                MDisps *mdisp = &mdisps[i];
+               int S, x, y, gIndex = gridOffset[i];
+
+               /* when adding new faces in edit mode, need to allocate disps */
+               if(!mdisp->disps)
+               #pragma omp critical
+               {
+                       multires_reallocate_mdisps(me, mdisps, totlvl);
+               }
 
                for(S = 0; S < numVerts; ++S, ++gIndex) {
                        DMGridData *grid = gridData[gIndex];
                        DMGridData *subgrid = subGridData[gIndex];
-                       DMGridAdjacency *adj = &gridAdjacency[gIndex];
                        float (*dispgrid)[3] = &mdisp->disps[S*dGridSize*dGridSize];
 
                        for(y = 0; y < gridSize; y++) {
@@ -548,12 +625,16 @@ static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, int invert, int
                                        float mat[3][3], tx[3], ty[3], disp[3], d[3];
 
                                        /* construct tangent space matrix */
-                                       grid_tangent(adj, gridSize, gIndex, x, y, 0, subGridData, tx);
+                                       grid_tangent(gridSize, gIndex, x, y, 0, subGridData, tx);
                                        normalize_v3(tx);
 
-                                       grid_tangent(adj, gridSize, gIndex, x, y, 1, subGridData, ty);
+                                       grid_tangent(gridSize, gIndex, x, y, 1, subGridData, ty);
                                        normalize_v3(ty);
 
+                                       //mul_v3_fl(tx, 1.0f/(gridSize-1));
+                                       //mul_v3_fl(ty, 1.0f/(gridSize-1));
+                                       //cross_v3_v3v3(no, tx, ty);
+
                                        column_vectors_to_mat3(mat, tx, ty, no);
 
                                        if(!invert) {
@@ -595,7 +676,8 @@ static void multiresModifier_update(DerivedMesh *dm)
        ob = ccgdm->multires.ob;
        me = ccgdm->multires.ob->data;
        mmd = ccgdm->multires.mmd;
-       CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface);
+       multires_set_tot_mdisps(me, mmd->totlvl);
+       CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
        mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS);
 
        if(mdisps) {
@@ -610,8 +692,11 @@ static void multiresModifier_update(DerivedMesh *dm)
                        int i, j, numGrids, highGridSize, lowGridSize;
 
                        /* create subsurf DM from original mesh at high level */
-                       cddm = CDDM_from_mesh(me, NULL);
-                       highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple);
+                       if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform);
+                       else cddm = CDDM_from_mesh(me, NULL);
+                       DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+
+                       highdm = subsurf_dm_create_local(ob, cddm, totlvl, mmd->simple, 0);
 
                        /* create multires DM from original mesh and displacements */
                        lowdm = multires_dm_create_local(ob, cddm, lvl, totlvl, mmd->simple);
@@ -661,8 +746,11 @@ static void multiresModifier_update(DerivedMesh *dm)
                else {
                        DerivedMesh *cddm, *subdm;
 
-                       cddm = CDDM_from_mesh(me, NULL);
-                       subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple);
+                       if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform);
+                       else cddm = CDDM_from_mesh(me, NULL);
+                       DM_set_only_copy(cddm, CD_MASK_BAREMESH);
+
+                       subdm = subsurf_dm_create_local(ob, cddm, mmd->totlvl, mmd->simple, 0);
                        cddm->release(cddm);
 
                        multiresModifier_disp_run(dm, me, 1, 0, subdm->getGridData(subdm), mmd->totlvl);
@@ -672,25 +760,27 @@ static void multiresModifier_update(DerivedMesh *dm)
        }
 }
 
-void multires_mark_as_modified(struct Object *ob)
+void multires_stitch_grids(Object *ob)
 {
+       /* utility for smooth brush */
        if(ob && ob->derivedFinal) {
                CCGDerivedMesh *ccgdm = (CCGDerivedMesh*)ob->derivedFinal;
-               ccgdm->multires.modified = 1;
-       }
-}
+               CCGFace **faces;
+               int totface;
 
-void multires_force_update(Object *ob)
-{
-       if(ob && ob->derivedFinal) {
-               ob->derivedFinal->needsFree =1;
-               ob->derivedFinal->release(ob->derivedFinal);
-               ob->derivedFinal = NULL;
+               if(ccgdm->pbvh) {
+                       BLI_pbvh_get_grid_updates(ccgdm->pbvh, 0, (void***)&faces, &totface);
+
+                       if(totface) {
+                               ccgSubSurf_stitchFaces(ccgdm->ss, 0, faces, totface);
+                               MEM_freeN(faces);
+                       }
+               }
        }
 }
 
-struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int local_mmd, DerivedMesh *dm, Object *ob,
-                                                   int useRenderParams, int isFinalCalc)
+DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, int local_mmd, DerivedMesh *dm, Object *ob,
+                                                       int useRenderParams, int UNUSED(isFinalCalc))
 {
        Mesh *me= ob->data;
        DerivedMesh *result;
@@ -702,7 +792,8 @@ struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, i
        if(lvl == 0)
                return dm;
 
-       result = subsurf_dm_create_local(ob, dm, lvl, 0);
+       result = subsurf_dm_create_local(ob, dm, lvl,
+               mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges);
 
        if(!local_mmd) {
                ccgdm = (CCGDerivedMesh*)result;
@@ -727,7 +818,8 @@ struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, i
                memcpy(subGridData[i], gridData[i], sizeof(DMGridData)*gridSize*gridSize);
        }
 
-       CustomData_external_read(&me->fdata, CD_MASK_MDISPS, me->totface);
+       multires_set_tot_mdisps(me, mmd->totlvl);
+       CustomData_external_read(&me->fdata, &me->id, CD_MASK_MDISPS, me->totface);
        multiresModifier_disp_run(result, ob->data, 0, 0, subGridData, mmd->totlvl);
 
        for(i = 0; i < numGrids; i++)
@@ -740,6 +832,106 @@ struct DerivedMesh *multires_dm_create_from_derived(MultiresModifierData *mmd, i
 /**** Old Multires code ****
 ***************************/
 
+/* Adapted from sculptmode.c */
+static void old_mdisps_bilinear(float out[3], float (*disps)[3], int st, float u, float v)
+{
+       int x, y, x2, y2;
+       const int st_max = st - 1;
+       float urat, vrat, uopp;
+       float d[4][3], d2[2][3];
+
+       if(u < 0)
+               u = 0;
+       else if(u >= st)
+               u = st_max;
+       if(v < 0)
+               v = 0;
+       else if(v >= st)
+               v = st_max;
+
+       x = floor(u);
+       y = floor(v);
+       x2 = x + 1;
+       y2 = y + 1;
+
+       if(x2 >= st) x2 = st_max;
+       if(y2 >= st) y2 = st_max;
+       
+       urat = u - x;
+       vrat = v - y;
+       uopp = 1 - urat;
+
+       mul_v3_v3fl(d[0], disps[y * st + x], uopp);
+       mul_v3_v3fl(d[1], disps[y * st + x2], urat);
+       mul_v3_v3fl(d[2], disps[y2 * st + x], uopp);
+       mul_v3_v3fl(d[3], disps[y2 * st + x2], urat);
+
+       add_v3_v3v3(d2[0], d[0], d[1]);
+       add_v3_v3v3(d2[1], d[2], d[3]);
+       mul_v3_fl(d2[0], 1 - vrat);
+       mul_v3_fl(d2[1], vrat);
+
+       add_v3_v3v3(out, d2[0], d2[1]);
+}
+
+static void old_mdisps_rotate(int S, int UNUSED(newside), int oldside, int x, int y, float *u, float *v)
+{
+       float offset = oldside*0.5f - 0.5f;
+
+       if(S == 1) { *u= offset + x; *v = offset - y; }
+       if(S == 2) { *u= offset + y; *v = offset + x; }
+       if(S == 3) { *u= offset - x; *v = offset + y; }
+       if(S == 0) { *u= offset - y; *v = offset - x; }
+}
+
+static void old_mdisps_convert(MFace *mface, MDisps *mdisp)
+{
+       int newlvl = log(sqrt(mdisp->totdisp)-1)/log(2);
+       int oldlvl = newlvl+1;
+       int oldside = multires_side_tot[oldlvl];
+       int newside = multires_side_tot[newlvl];
+       int nvert = (mface->v4)? 4: 3;
+       int newtotdisp = multires_grid_tot[newlvl]*nvert;
+       int x, y, S;
+       float (*disps)[3], (*out)[3], u, v;
+
+       disps = MEM_callocN(sizeof(float) * 3 * newtotdisp, "multires disps");
+
+       out = disps;
+       for(S = 0; S < nvert; S++) {
+               for(y = 0; y < newside; ++y) {
+                       for(x = 0; x < newside; ++x, ++out) {
+                               old_mdisps_rotate(S, newside, oldside, x, y, &u, &v);
+                               old_mdisps_bilinear(*out, mdisp->disps, oldside, u, v);
+
+                               if(S == 1) { (*out)[1]= -(*out)[1]; }
+                               else if(S == 2) { SWAP(float, (*out)[0], (*out)[1]); }
+                               else if(S == 3) { (*out)[0]= -(*out)[0]; }
+                               else if(S == 0) { SWAP(float, (*out)[0], (*out)[1]); (*out)[0]= -(*out)[0]; (*out)[1]= -(*out)[1]; };
+                       }
+               }
+       }
+
+       MEM_freeN(mdisp->disps);
+
+       mdisp->totdisp= newtotdisp;
+       mdisp->disps= disps;
+}
+
+void multires_load_old_250(Mesh *me)
+{
+       MDisps *mdisps;
+       int a;
+
+       mdisps= CustomData_get_layer(&me->fdata, CD_MDISPS);
+
+       if(mdisps) {
+               for(a=0; a<me->totface; a++)
+                       if(mdisps[a].totdisp)
+                               old_mdisps_convert(&me->mface[a], &mdisps[a]);
+       }
+}
+
 /* Does not actually free lvl itself */
 static void multires_free_level(MultiresLevel *lvl)
 {
@@ -779,7 +971,7 @@ void multires_free(Multires *mr)
 }
 
 static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const MultiresFace *mface,
-                                    const int totvert, const int totface)
+                                        const int totvert, const int totface)
 {
        int i,j;
        IndexNode *node = NULL;
@@ -798,7 +990,7 @@ static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const Mult
 }
 
 static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const MultiresEdge *medge,
-                                    const int totvert, const int totedge)
+                                        const int totvert, const int totedge)
 {
        int i,j;
        IndexNode *node = NULL;
@@ -864,7 +1056,7 @@ static void multires_load_old_edges(ListBase **emap, MultiresLevel *lvl, int *vv
 }
 
 static void multires_load_old_faces(ListBase **fmap, ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst,
-                                   int v1, int v2, int v3, int v4, int st2, int st3)
+                                       int v1, int v2, int v3, int v4, int st2, int st3)
 {
        int fmid;
        int emid13, emid14, emid23, emid24;
@@ -900,24 +1092,85 @@ static void multires_load_old_faces(ListBase **fmap, ListBase **emap, MultiresLe
        }
 }
 
+static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert)
+{
+       CCGDerivedMesh *ccgdm = (CCGDerivedMesh*) dm;
+       CCGSubSurf *ss = ccgdm->ss;
+       DMGridData *vd;
+       int index;
+       int totvert, totedge, totface;
+       int gridSize = ccgSubSurf_getGridSize(ss);
+       int edgeSize = ccgSubSurf_getEdgeSize(ss);
+       int i = 0;
+
+       totface = ccgSubSurf_getNumFaces(ss);
+       for(index = 0; index < totface; index++) {
+               CCGFace *f = ccgdm->faceMap[index].face;
+               int x, y, S, numVerts = ccgSubSurf_getFaceNumVerts(f);
+
+               vd= ccgSubSurf_getFaceCenterData(f);
+               copy_v3_v3(vd->co, mvert[i].co);
+               i++;
+               
+               for(S = 0; S < numVerts; S++) {
+                       for(x = 1; x < gridSize - 1; x++, i++) {
+                               vd= ccgSubSurf_getFaceGridEdgeData(ss, f, S, x);
+                               copy_v3_v3(vd->co, mvert[i].co);
+                       }
+               }
+
+               for(S = 0; S < numVerts; S++) {
+                       for(y = 1; y < gridSize - 1; y++) {
+                               for(x = 1; x < gridSize - 1; x++, i++) {
+                                       vd= ccgSubSurf_getFaceGridData(ss, f, S, x, y);
+                                       copy_v3_v3(vd->co, mvert[i].co);
+                               }
+                       }
+               }
+       }
+
+       totedge = ccgSubSurf_getNumEdges(ss);
+       for(index = 0; index < totedge; index++) {
+               CCGEdge *e = ccgdm->edgeMap[index].edge;
+               int x;
+
+               for(x = 1; x < edgeSize - 1; x++, i++) {
+                       vd= ccgSubSurf_getEdgeData(ss, e, x);
+                       copy_v3_v3(vd->co, mvert[i].co);
+               }
+       }
+
+       totvert = ccgSubSurf_getNumVerts(ss);
+       for(index = 0; index < totvert; index++) {
+               CCGVert *v = ccgdm->vertMap[index].vert;
+
+               vd= ccgSubSurf_getVertData(ss, v);
+               copy_v3_v3(vd->co, mvert[i].co);
+               i++;
+       }
+
+       ccgSubSurf_updateToFaces(ss, 0, NULL, 0);
+}
+
 /* Loads a multires object stored in the old Multires struct into the new format */
-void multires_load_old(DerivedMesh *dm, Multires *mr)
+static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl)
 {
        MultiresLevel *lvl, *lvl1;
+       Multires *mr= me->mr;
        MVert *vsrc, *vdst;
-       int src, dst;
-       int totlvl = 2; // XXX MultiresDM_get_totlvl(dm);
+       unsigned int src, dst;
        int st = multires_side_tot[totlvl - 1] - 1;
        int extedgelen = multires_side_tot[totlvl] - 2;
        int *vvmap; // inorder for dst, map to src
        int crossedgelen;
-       int i, j, s, x, totvert, tottri, totquad;
+       int s, x, tottri, totquad;
+       unsigned int i, j, totvert;
 
        src = 0;
        dst = 0;
        vsrc = mr->verts;
-       vdst = CDDM_get_verts(dm);
-       totvert = dm->getNumVerts(dm);
+       vdst = dm->getVertArray(dm);
+       totvert = (unsigned int)dm->getNumVerts(dm);
        vvmap = MEM_callocN(sizeof(int) * totvert, "multires vvmap");
 
        lvl1 = mr->levels.first;
@@ -1008,7 +1261,7 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
                fmem = MEM_callocN(sizeof(IndexNode*) * (mr->level_count-1), "multires fmem");
                emem = MEM_callocN(sizeof(IndexNode*) * (mr->level_count-1), "multires emem");
                lvl = lvl1;
-               for(i = 0; i < mr->level_count - 1; ++i) {
+               for(i = 0; i < (unsigned int)mr->level_count - 1; ++i) {
                        create_old_vert_face_map(fmap + i, fmem + i, lvl->faces, lvl->totvert, lvl->totface);
                        create_old_vert_edge_map(emap + i, emem + i, lvl->edges, lvl->totvert, lvl->totedge);
                        lvl = lvl->next;
@@ -1045,7 +1298,7 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
 
                lvl = lvl->next;
 
-               for(i = 0; i < mr->level_count - 1; ++i) {
+               for(i = 0; i < (unsigned int)(mr->level_count - 1); ++i) {
                        MEM_freeN(fmap[i]);
                        MEM_freeN(fmem[i]);
                        MEM_freeN(emap[i]);
@@ -1063,5 +1316,73 @@ void multires_load_old(DerivedMesh *dm, Multires *mr)
                copy_v3_v3(vdst[i].co, vsrc[vvmap[i]].co);
 
        MEM_freeN(vvmap);
+
+       multires_mvert_to_ss(dm, vdst);
+}
+
+
+void multires_load_old(Object *ob, Mesh *me)
+{
+       MultiresLevel *lvl;
+       ModifierData *md;
+       MultiresModifierData *mmd;
+       DerivedMesh *dm, *orig;
+       CustomDataLayer *l;
+       int i;
+
+       /* Load original level into the mesh */
+       lvl = me->mr->levels.first;
+       CustomData_free_layers(&me->vdata, CD_MVERT, lvl->totvert);
+       CustomData_free_layers(&me->edata, CD_MEDGE, lvl->totedge);
+       CustomData_free_layers(&me->fdata, CD_MFACE, lvl->totface);
+       me->totvert = lvl->totvert;
+       me->totedge = lvl->totedge;
+       me->totface = lvl->totface;
+       me->mvert = CustomData_add_layer(&me->vdata, CD_MVERT, CD_CALLOC, NULL, me->totvert);
+       me->medge = CustomData_add_layer(&me->edata, CD_MEDGE, CD_CALLOC, NULL, me->totedge);
+       me->mface = CustomData_add_layer(&me->fdata, CD_MFACE, CD_CALLOC, NULL, me->totface);
+       memcpy(me->mvert, me->mr->verts, sizeof(MVert) * me->totvert);
+       for(i = 0; i < me->totedge; ++i) {
+               me->medge[i].v1 = lvl->edges[i].v[0];
+               me->medge[i].v2 = lvl->edges[i].v[1];
+       }
+       for(i = 0; i < me->totface; ++i) {
+               me->mface[i].v1 = lvl->faces[i].v[0];
+               me->mface[i].v2 = lvl->faces[i].v[1];
+               me->mface[i].v3 = lvl->faces[i].v[2];
+               me->mface[i].v4 = lvl->faces[i].v[3];
+       }
+
+       /* Add a multires modifier to the object */
+       md = ob->modifiers.first;
+       while(md && modifierType_getInfo(md->type)->type == eModifierTypeType_OnlyDeform)
+               md = md->next;                          
+       mmd = (MultiresModifierData*)modifier_new(eModifierType_Multires);
+       BLI_insertlinkbefore(&ob->modifiers, md, mmd);
+
+       for(i = 0; i < me->mr->level_count - 1; ++i)
+               multiresModifier_subdivide(mmd, ob, 1, 0);
+
+       mmd->lvl = mmd->totlvl;
+       orig = CDDM_from_mesh(me, NULL);
+       dm = multires_dm_create_from_derived(mmd, 0, orig, ob, 0, 0);
+                                          
+       multires_load_old_dm(dm, me, mmd->totlvl+1);
+
+       multires_dm_mark_as_modified(dm);
+       dm->release(dm);
+       orig->release(orig);
+
+       /* Copy the first-level data to the mesh */
+       for(i = 0, l = me->mr->vdata.layers; i < me->mr->vdata.totlayer; ++i, ++l)
+               CustomData_add_layer(&me->vdata, l->type, CD_REFERENCE, l->data, me->totvert);
+       for(i = 0, l = me->mr->fdata.layers; i < me->mr->fdata.totlayer; ++i, ++l)
+               CustomData_add_layer(&me->fdata, l->type, CD_REFERENCE, l->data, me->totface);
+       memset(&me->mr->vdata, 0, sizeof(CustomData));
+       memset(&me->mr->fdata, 0, sizeof(CustomData));
+
+       /* Remove the old multires */
+       multires_free(me->mr);
+       me->mr= NULL;
 }