diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/blenkernel/intern/multires.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/blenkernel/intern/multires.c')
-rw-r--r-- | source/blender/blenkernel/intern/multires.c | 3902 |
1 files changed, 2025 insertions, 1877 deletions
diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index e546119b86d..5e404f7e264 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -21,7 +21,6 @@ * \ingroup bke */ - #include "MEM_guardedalloc.h" /* for reading old multires */ @@ -63,251 +62,241 @@ /* MULTIRES MODIFIER */ static const int multires_max_levels = 13; -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 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}; /* See multiresModifier_disp_run for description of each operation */ typedef enum { - APPLY_DISPLACEMENTS, - CALC_DISPLACEMENTS, - ADD_DISPLACEMENTS, + APPLY_DISPLACEMENTS, + CALC_DISPLACEMENTS, + ADD_DISPLACEMENTS, } DispOp; static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert); -static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl); +static void multiresModifier_disp_run( + DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl); /** Customdata */ void multires_customdata_delete(Mesh *me) { - if (me->edit_mesh) { - BMEditMesh *em = me->edit_mesh; - /* CustomData_external_remove is used here only to mark layer - * as non-external for further free-ing, so zero element count - * looks safer than em->totface */ - CustomData_external_remove(&em->bm->ldata, &me->id, - CD_MDISPS, 0); - BM_data_layer_free(em->bm, &em->bm->ldata, CD_MDISPS); + if (me->edit_mesh) { + BMEditMesh *em = me->edit_mesh; + /* CustomData_external_remove is used here only to mark layer + * as non-external for further free-ing, so zero element count + * looks safer than em->totface */ + CustomData_external_remove(&em->bm->ldata, &me->id, CD_MDISPS, 0); + BM_data_layer_free(em->bm, &em->bm->ldata, CD_MDISPS); - BM_data_layer_free(em->bm, &em->bm->ldata, CD_GRID_PAINT_MASK); - } - else { - CustomData_external_remove(&me->ldata, &me->id, - CD_MDISPS, me->totloop); - CustomData_free_layer_active(&me->ldata, CD_MDISPS, - me->totloop); + BM_data_layer_free(em->bm, &em->bm->ldata, CD_GRID_PAINT_MASK); + } + else { + CustomData_external_remove(&me->ldata, &me->id, CD_MDISPS, me->totloop); + CustomData_free_layer_active(&me->ldata, CD_MDISPS, me->totloop); - CustomData_free_layer_active(&me->ldata, CD_GRID_PAINT_MASK, - me->totloop); - } + CustomData_free_layer_active(&me->ldata, CD_GRID_PAINT_MASK, me->totloop); + } } /** Grid hiding */ -static BLI_bitmap *multires_mdisps_upsample_hidden( - BLI_bitmap *lo_hidden, - int lo_level, int hi_level, - - /* assumed to be at hi_level (or null) */ - const BLI_bitmap *prev_hidden) -{ - BLI_bitmap *subd; - int hi_gridsize = BKE_ccg_gridsize(hi_level); - int lo_gridsize = BKE_ccg_gridsize(lo_level); - int yh, xh, xl, yl, xo, yo, hi_ndx; - int offset, factor; - - BLI_assert(lo_level <= hi_level); - - /* fast case */ - if (lo_level == hi_level) - return MEM_dupallocN(lo_hidden); - - subd = BLI_BITMAP_NEW(SQUARE(hi_gridsize), "MDisps.hidden upsample"); - - factor = BKE_ccg_factor(lo_level, hi_level); - offset = 1 << (hi_level - lo_level - 1); - - /* low-res blocks */ - for (yl = 0; yl < lo_gridsize; yl++) { - for (xl = 0; xl < lo_gridsize; xl++) { - int lo_val = BLI_BITMAP_TEST(lo_hidden, yl * lo_gridsize + xl); - - /* high-res blocks */ - for (yo = -offset; yo <= offset; yo++) { - yh = yl * factor + yo; - if (yh < 0 || yh >= hi_gridsize) - continue; - - for (xo = -offset; xo <= offset; xo++) { - xh = xl * factor + xo; - if (xh < 0 || xh >= hi_gridsize) - continue; - - hi_ndx = yh * hi_gridsize + xh; - - if (prev_hidden) { - /* If prev_hidden is available, copy it to - * subd, except when the equivalent element in - * lo_hidden is different */ - if (lo_val != prev_hidden[hi_ndx]) { - BLI_BITMAP_SET(subd, hi_ndx, lo_val); - } - else { - BLI_BITMAP_SET(subd, hi_ndx, prev_hidden[hi_ndx]); - } - } - else { - BLI_BITMAP_SET(subd, hi_ndx, lo_val); - } - } - } - } - } - - return subd; +static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden, + int lo_level, + int hi_level, + + /* assumed to be at hi_level (or null) */ + const BLI_bitmap *prev_hidden) +{ + BLI_bitmap *subd; + int hi_gridsize = BKE_ccg_gridsize(hi_level); + int lo_gridsize = BKE_ccg_gridsize(lo_level); + int yh, xh, xl, yl, xo, yo, hi_ndx; + int offset, factor; + + BLI_assert(lo_level <= hi_level); + + /* fast case */ + if (lo_level == hi_level) + return MEM_dupallocN(lo_hidden); + + subd = BLI_BITMAP_NEW(SQUARE(hi_gridsize), "MDisps.hidden upsample"); + + factor = BKE_ccg_factor(lo_level, hi_level); + offset = 1 << (hi_level - lo_level - 1); + + /* low-res blocks */ + for (yl = 0; yl < lo_gridsize; yl++) { + for (xl = 0; xl < lo_gridsize; xl++) { + int lo_val = BLI_BITMAP_TEST(lo_hidden, yl * lo_gridsize + xl); + + /* high-res blocks */ + for (yo = -offset; yo <= offset; yo++) { + yh = yl * factor + yo; + if (yh < 0 || yh >= hi_gridsize) + continue; + + for (xo = -offset; xo <= offset; xo++) { + xh = xl * factor + xo; + if (xh < 0 || xh >= hi_gridsize) + continue; + + hi_ndx = yh * hi_gridsize + xh; + + if (prev_hidden) { + /* If prev_hidden is available, copy it to + * subd, except when the equivalent element in + * lo_hidden is different */ + if (lo_val != prev_hidden[hi_ndx]) { + BLI_BITMAP_SET(subd, hi_ndx, lo_val); + } + else { + BLI_BITMAP_SET(subd, hi_ndx, prev_hidden[hi_ndx]); + } + } + else { + BLI_BITMAP_SET(subd, hi_ndx, lo_val); + } + } + } + } + } + + return subd; } static BLI_bitmap *multires_mdisps_downsample_hidden(BLI_bitmap *old_hidden, int old_level, int new_level) { - BLI_bitmap *new_hidden; - int new_gridsize = BKE_ccg_gridsize(new_level); - int old_gridsize = BKE_ccg_gridsize(old_level); - int x, y, factor, old_value; - - BLI_assert(new_level <= old_level); - factor = BKE_ccg_factor(new_level, old_level); - new_hidden = BLI_BITMAP_NEW(SQUARE(new_gridsize), "downsample hidden"); + BLI_bitmap *new_hidden; + int new_gridsize = BKE_ccg_gridsize(new_level); + int old_gridsize = BKE_ccg_gridsize(old_level); + int x, y, factor, old_value; + BLI_assert(new_level <= old_level); + factor = BKE_ccg_factor(new_level, old_level); + new_hidden = BLI_BITMAP_NEW(SQUARE(new_gridsize), "downsample hidden"); - for (y = 0; y < new_gridsize; y++) { - for (x = 0; x < new_gridsize; x++) { - old_value = BLI_BITMAP_TEST(old_hidden, - factor * y * old_gridsize + x * factor); + for (y = 0; y < new_gridsize; y++) { + for (x = 0; x < new_gridsize; x++) { + old_value = BLI_BITMAP_TEST(old_hidden, factor * y * old_gridsize + x * factor); - BLI_BITMAP_SET(new_hidden, y * new_gridsize + x, old_value); - } - } + BLI_BITMAP_SET(new_hidden, y * new_gridsize + x, old_value); + } + } - return new_hidden; + return new_hidden; } -static void multires_output_hidden_to_ccgdm(CCGDerivedMesh *ccgdm, - Mesh *me, int level) +static void multires_output_hidden_to_ccgdm(CCGDerivedMesh *ccgdm, Mesh *me, int level) { - const MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - BLI_bitmap **grid_hidden = ccgdm->gridHidden; - int *gridOffset; - int i, j; + const MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + BLI_bitmap **grid_hidden = ccgdm->gridHidden; + int *gridOffset; + int i, j; - gridOffset = ccgdm->dm.getGridOffset(&ccgdm->dm); + gridOffset = ccgdm->dm.getGridOffset(&ccgdm->dm); - for (i = 0; i < me->totpoly; i++) { - for (j = 0; j < me->mpoly[i].totloop; j++) { - int g = gridOffset[i] + j; - const MDisps *md = &mdisps[g]; - BLI_bitmap *gh = md->hidden; + for (i = 0; i < me->totpoly; i++) { + for (j = 0; j < me->mpoly[i].totloop; j++) { + int g = gridOffset[i] + j; + const MDisps *md = &mdisps[g]; + BLI_bitmap *gh = md->hidden; - if (gh) { - grid_hidden[g] = - multires_mdisps_downsample_hidden(gh, md->level, level); - } - } - } + if (gh) { + grid_hidden[g] = multires_mdisps_downsample_hidden(gh, md->level, level); + } + } + } } /* subdivide mdisps.hidden if needed (assumes that md.level reflects * the current level of md.hidden) */ static void multires_mdisps_subdivide_hidden(MDisps *md, int new_level) { - BLI_bitmap *subd; + BLI_bitmap *subd; - BLI_assert(md->hidden); + BLI_assert(md->hidden); - /* nothing to do if already subdivided enough */ - if (md->level >= new_level) - return; + /* nothing to do if already subdivided enough */ + if (md->level >= new_level) + return; - subd = multires_mdisps_upsample_hidden(md->hidden, - md->level, - new_level, - NULL); + subd = multires_mdisps_upsample_hidden(md->hidden, md->level, new_level, NULL); - /* swap in the subdivided data */ - MEM_freeN(md->hidden); - md->hidden = subd; + /* swap in the subdivided data */ + MEM_freeN(md->hidden); + md->hidden = subd; } static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level) { - MDisps *mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, - CD_CALLOC, NULL, me->totloop); - int gridsize = BKE_ccg_gridsize(level); - int gridarea = SQUARE(gridsize); - int i, j; + MDisps *mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop); + int gridsize = BKE_ccg_gridsize(level); + int gridarea = SQUARE(gridsize); + int i, j; - for (i = 0; i < me->totpoly; i++) { - bool hide = false; + for (i = 0; i < me->totpoly; i++) { + bool hide = false; - for (j = 0; j < me->mpoly[i].totloop; j++) { - if (me->mvert[me->mloop[me->mpoly[i].loopstart + j].v].flag & ME_HIDE) { - hide = true; - break; - } - } + for (j = 0; j < me->mpoly[i].totloop; j++) { + if (me->mvert[me->mloop[me->mpoly[i].loopstart + j].v].flag & ME_HIDE) { + hide = true; + break; + } + } - if (!hide) - continue; + if (!hide) + continue; - for (j = 0; j < me->mpoly[i].totloop; j++) { - MDisps *md = &mdisps[me->mpoly[i].loopstart + j]; + for (j = 0; j < me->mpoly[i].totloop; j++) { + MDisps *md = &mdisps[me->mpoly[i].loopstart + j]; - BLI_assert(!md->hidden); + BLI_assert(!md->hidden); - md->hidden = BLI_BITMAP_NEW(gridarea, "MDisps.hidden initialize"); - BLI_bitmap_set_all(md->hidden, true, gridarea); - } - } + md->hidden = BLI_BITMAP_NEW(gridarea, "MDisps.hidden initialize"); + BLI_bitmap_set_all(md->hidden, true, gridarea); + } + } - return mdisps; + return mdisps; } -Mesh *BKE_multires_create_mesh( - struct Depsgraph *depsgraph, - Scene *scene, - MultiresModifierData *mmd, - Object *ob) +Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, + Scene *scene, + MultiresModifierData *mmd, + Object *ob) { - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); - Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene, ob_eval, &CD_MASK_BAREMESH); - ModifierEvalContext modifier_ctx = { - .depsgraph = depsgraph, - .object = ob_eval, - .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY, - }; + Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene, ob_eval, &CD_MASK_BAREMESH); + ModifierEvalContext modifier_ctx = { + .depsgraph = depsgraph, + .object = ob_eval, + .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY, + }; - const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type); - Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh); + const ModifierTypeInfo *mti = modifierType_getInfo(mmd->modifier.type); + Mesh *result = mti->applyModifier(&mmd->modifier, &modifier_ctx, deformed_mesh); - if (result == deformed_mesh) { - result = BKE_mesh_copy_for_eval(deformed_mesh, true); - } - return result; + if (result == deformed_mesh) { + result = BKE_mesh_copy_for_eval(deformed_mesh, true); + } + return result; } MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd) { - ModifierData *md; + ModifierData *md; - for (md = lastmd; md; md = md->prev) { - if (md->type == eModifierType_Multires) { - if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) - return (MultiresModifierData *)md; - } - } + for (md = lastmd; md; md = md->prev) { + if (md->type == eModifierType_Multires) { + if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) + return (MultiresModifierData *)md; + } + } - return NULL; + return NULL; } /* used for applying scale on mdisps layer and syncing subdivide levels when joining objects @@ -315,1113 +304,1158 @@ MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData * */ MultiresModifierData *get_multires_modifier(Scene *scene, Object *ob, bool use_first) { - ModifierData *md; - MultiresModifierData *mmd = NULL, *firstmmd = NULL; + ModifierData *md; + MultiresModifierData *mmd = NULL, *firstmmd = NULL; - /* find first active multires modifier */ - for (md = ob->modifiers.first; md; md = md->next) { - if (md->type == eModifierType_Multires) { - if (!firstmmd) - firstmmd = (MultiresModifierData *)md; + /* find first active multires modifier */ + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Multires) { + if (!firstmmd) + firstmmd = (MultiresModifierData *)md; - if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { - mmd = (MultiresModifierData *)md; - break; - } - } - } + if (modifier_isEnabled(scene, md, eModifierMode_Realtime)) { + mmd = (MultiresModifierData *)md; + break; + } + } + } - if (!mmd && use_first) { - /* active multires have not been found - * try to use first one */ - return firstmmd; - } + if (!mmd && use_first) { + /* active multires have not been found + * try to use first one */ + return firstmmd; + } - return mmd; + return mmd; } -int multires_get_level(const Scene *scene, const Object *ob, const MultiresModifierData *mmd, - bool render, bool ignore_simplify) +int multires_get_level(const Scene *scene, + const Object *ob, + const MultiresModifierData *mmd, + bool render, + bool ignore_simplify) { - if (render) - return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->renderlvl, true) : mmd->renderlvl; - else if (ob->mode == OB_MODE_SCULPT) - return mmd->sculptlvl; - else if (ignore_simplify) - return mmd->lvl; - else - return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl; + if (render) + return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->renderlvl, true) : + mmd->renderlvl; + else if (ob->mode == OB_MODE_SCULPT) + return mmd->sculptlvl; + else if (ignore_simplify) + return mmd->lvl; + else + return (scene != NULL) ? get_render_subsurf_level(&scene->r, mmd->lvl, false) : mmd->lvl; } void multires_set_tot_level(Object *ob, MultiresModifierData *mmd, int lvl) { - mmd->totlvl = lvl; + mmd->totlvl = lvl; - if (ob->mode != OB_MODE_SCULPT) - mmd->lvl = CLAMPIS(MAX2(mmd->lvl, 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); + 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, MultiresModifiedFlags flags) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - ccgdm->multires.modified_flags |= flags; + CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; + ccgdm->multires.modified_flags |= flags; } -static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg, - MultiresModifiedFlags flags) +static void multires_ccg_mark_as_modified(SubdivCCG *subdiv_ccg, MultiresModifiedFlags flags) { - if (flags & MULTIRES_COORDS_MODIFIED) { - subdiv_ccg->dirty.coords = true; - } - if (flags & MULTIRES_HIDDEN_MODIFIED) { - subdiv_ccg->dirty.hidden = true; - } + if (flags & MULTIRES_COORDS_MODIFIED) { + subdiv_ccg->dirty.coords = true; + } + if (flags & MULTIRES_HIDDEN_MODIFIED) { + subdiv_ccg->dirty.hidden = true; + } } void multires_mark_as_modified(Object *ob, MultiresModifiedFlags flags) { - if (ob == NULL) { - return; - } - Mesh *mesh = ob->data; - SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg; - if (subdiv_ccg == NULL) { - return; - } - multires_ccg_mark_as_modified(subdiv_ccg, flags); + if (ob == NULL) { + return; + } + Mesh *mesh = ob->data; + SubdivCCG *subdiv_ccg = mesh->runtime.subdiv_ccg; + if (subdiv_ccg == NULL) { + return; + } + multires_ccg_mark_as_modified(subdiv_ccg, flags); } void multires_force_update(Object *ob) { - if (ob == NULL) { - return; - } - SculptSession *sculpt_session = ob->sculpt; - if (sculpt_session != NULL && sculpt_session->pbvh != NULL) { - PBVH *pbvh = sculpt_session->pbvh; - if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) { - Mesh *mesh = ob->data; - multiresModifier_reshapeFromCCG( - sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); - } - else { - /* NOTE: Disabled for until OpenSubdiv is enabled by default. */ - // BLI_assert(!"multires_force_update is used on non-grids PBVH"); - } - BKE_pbvh_free(pbvh); - ob->sculpt->pbvh = NULL; - } + if (ob == NULL) { + return; + } + SculptSession *sculpt_session = ob->sculpt; + if (sculpt_session != NULL && sculpt_session->pbvh != NULL) { + PBVH *pbvh = sculpt_session->pbvh; + if (BKE_pbvh_type(pbvh) == PBVH_GRIDS) { + Mesh *mesh = ob->data; + multiresModifier_reshapeFromCCG( + sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); + } + else { + /* NOTE: Disabled for until OpenSubdiv is enabled by default. */ + // BLI_assert(!"multires_force_update is used on non-grids PBVH"); + } + BKE_pbvh_free(pbvh); + ob->sculpt->pbvh = NULL; + } } void multires_force_external_reload(Object *ob) { - Mesh *me = BKE_mesh_from_object(ob); + Mesh *me = BKE_mesh_from_object(ob); - CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - multires_force_update(ob); + CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + 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); + if (ob && (ob->mode & OB_MODE_SCULPT) && modifiers_findByType(ob, eModifierType_Multires)) + multires_force_update(ob); } /* reset the multires levels to match the number of mdisps */ static int get_levels_from_disps(Object *ob) { - Mesh *me = ob->data; - MDisps *mdisp, *md; - int i, j, totlvl = 0; - - mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS); + Mesh *me = ob->data; + MDisps *mdisp, *md; + int i, j, totlvl = 0; - for (i = 0; i < me->totpoly; ++i) { - md = mdisp + me->mpoly[i].loopstart; + mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS); - for (j = 0; j < me->mpoly[i].totloop; j++, md++) { - if (md->totdisp == 0) continue; + for (i = 0; i < me->totpoly; ++i) { + md = mdisp + me->mpoly[i].loopstart; - while (1) { - int side = (1 << (totlvl - 1)) + 1; - int lvl_totdisp = side * side; - if (md->totdisp == lvl_totdisp) - break; - else if (md->totdisp < lvl_totdisp) - totlvl--; - else - totlvl++; + for (j = 0; j < me->mpoly[i].totloop; j++, md++) { + if (md->totdisp == 0) + continue; - } + while (1) { + int side = (1 << (totlvl - 1)) + 1; + int lvl_totdisp = side * side; + if (md->totdisp == lvl_totdisp) + break; + else if (md->totdisp < lvl_totdisp) + totlvl--; + else + totlvl++; + } - break; - } - } + break; + } + } - return 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; + Mesh *me = ob->data; + MDisps *mdisp; - if (me->edit_mesh) - mdisp = CustomData_get_layer(&me->edit_mesh->bm->ldata, CD_MDISPS); - else - mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS); + if (me->edit_mesh) + mdisp = CustomData_get_layer(&me->edit_mesh->bm->ldata, CD_MDISPS); + else + mdisp = CustomData_get_layer(&me->ldata, 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); - } + 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); + } } static void multires_set_tot_mdisps(Mesh *me, int lvl) { - MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - int i; + MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + int i; - if (mdisps) { - for (i = 0; i < me->totloop; i++, mdisps++) { - mdisps->totdisp = multires_grid_tot[lvl]; - mdisps->level = lvl; - } - } + if (mdisps) { + for (i = 0; i < me->totloop; i++, mdisps++) { + mdisps->totdisp = multires_grid_tot[lvl]; + mdisps->level = lvl; + } + } } static void multires_reallocate_mdisps(int totloop, MDisps *mdisps, int lvl) { - int i; + int i; - /* reallocate displacements to be filled in */ - for (i = 0; i < totloop; ++i) { - int totdisp = multires_grid_tot[lvl]; - float (*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); + /* reallocate displacements to be filled in */ + for (i = 0; i < totloop; ++i) { + int totdisp = multires_grid_tot[lvl]; + float(*disps)[3] = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); - if (mdisps[i].disps) - MEM_freeN(mdisps[i].disps); + if (mdisps[i].disps) + MEM_freeN(mdisps[i].disps); - if (mdisps[i].level && mdisps[i].hidden) - multires_mdisps_subdivide_hidden(&mdisps[i], lvl); + if (mdisps[i].level && mdisps[i].hidden) + multires_mdisps_subdivide_hidden(&mdisps[i], lvl); - mdisps[i].disps = disps; - mdisps[i].totdisp = totdisp; - mdisps[i].level = lvl; - } + mdisps[i].disps = disps; + mdisps[i].totdisp = totdisp; + mdisps[i].level = lvl; + } } static void multires_copy_grid(float (*gridA)[3], float (*gridB)[3], int sizeA, int sizeB) { - int x, y, j, skip; + int x, y, j, skip; - if (sizeA > sizeB) { - skip = (sizeA - 1) / (sizeB - 1); + if (sizeA > sizeB) { + skip = (sizeA - 1) / (sizeB - 1); - for (j = 0, y = 0; y < sizeB; y++) - for (x = 0; x < sizeB; x++, j++) - copy_v3_v3(gridA[y * skip * sizeA + x * skip], gridB[j]); - } - else { - skip = (sizeB - 1) / (sizeA - 1); + for (j = 0, y = 0; y < sizeB; y++) + for (x = 0; x < sizeB; x++, j++) + copy_v3_v3(gridA[y * skip * sizeA + x * skip], gridB[j]); + } + else { + skip = (sizeB - 1) / (sizeA - 1); - for (j = 0, y = 0; y < sizeA; y++) - for (x = 0; x < sizeA; x++, j++) - copy_v3_v3(gridA[j], gridB[y * skip * sizeB + x * skip]); - } + for (j = 0, y = 0; y < sizeA; y++) + for (x = 0; x < sizeA; x++, j++) + copy_v3_v3(gridA[j], gridB[y * skip * sizeB + x * skip]); + } } static void multires_copy_dm_grid(CCGElem *gridA, CCGElem *gridB, CCGKey *keyA, CCGKey *keyB) { - int x, y, j, skip; + int x, y, j, skip; - if (keyA->grid_size > keyB->grid_size) { - skip = (keyA->grid_size - 1) / (keyB->grid_size - 1); + if (keyA->grid_size > keyB->grid_size) { + skip = (keyA->grid_size - 1) / (keyB->grid_size - 1); - for (j = 0, y = 0; y < keyB->grid_size; y++) - for (x = 0; x < keyB->grid_size; x++, j++) - memcpy(CCG_elem_offset_co(keyA, gridA, y * skip * keyA->grid_size + x * skip), - CCG_elem_offset_co(keyB, gridB, j), - keyA->elem_size); - } - else { - skip = (keyB->grid_size - 1) / (keyA->grid_size - 1); + for (j = 0, y = 0; y < keyB->grid_size; y++) + for (x = 0; x < keyB->grid_size; x++, j++) + memcpy(CCG_elem_offset_co(keyA, gridA, y * skip * keyA->grid_size + x * skip), + CCG_elem_offset_co(keyB, gridB, j), + keyA->elem_size); + } + else { + skip = (keyB->grid_size - 1) / (keyA->grid_size - 1); - for (j = 0, y = 0; y < keyA->grid_size; y++) - for (x = 0; x < keyA->grid_size; x++, j++) - memcpy(CCG_elem_offset_co(keyA, gridA, j), - CCG_elem_offset_co(keyB, gridB, y * skip * keyB->grid_size + x * skip), - keyA->elem_size); - } + for (j = 0, y = 0; y < keyA->grid_size; y++) + for (x = 0; x < keyA->grid_size; x++, j++) + memcpy(CCG_elem_offset_co(keyA, gridA, j), + CCG_elem_offset_co(keyB, gridB, y * skip * keyB->grid_size + x * skip), + keyA->elem_size); + } } /* Reallocate gpm->data at a lower resolution and copy values over * from the original high-resolution data */ static void multires_grid_paint_mask_downsample(GridPaintMask *gpm, int level) { - if (level < gpm->level) { - int gridsize = BKE_ccg_gridsize(level); - float *data = MEM_calloc_arrayN(SQUARE(gridsize), sizeof(float), - "multires_grid_paint_mask_downsample"); - int x, y; + if (level < gpm->level) { + int gridsize = BKE_ccg_gridsize(level); + float *data = MEM_calloc_arrayN( + SQUARE(gridsize), sizeof(float), "multires_grid_paint_mask_downsample"); + int x, y; - for (y = 0; y < gridsize; y++) { - for (x = 0; x < gridsize; x++) { - data[y * gridsize + x] = - paint_grid_paint_mask(gpm, level, x, y); - } - } + for (y = 0; y < gridsize; y++) { + for (x = 0; x < gridsize; x++) { + data[y * gridsize + x] = paint_grid_paint_mask(gpm, level, x, y); + } + } - MEM_freeN(gpm->data); - gpm->data = data; - gpm->level = level; - } + MEM_freeN(gpm->data); + gpm->data = data; + gpm->level = level; + } } static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) { - Mesh *me = (Mesh *)ob->data; - int levels = mmd->totlvl - lvl; - MDisps *mdisps; - GridPaintMask *gpm; - - multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); - - multires_force_update(ob); - - if (mdisps && levels > 0) { - if (lvl > 0) { - /* MLoop *ml = me->mloop; */ /*UNUSED*/ - int nsize = multires_side_tot[lvl]; - int hsize = multires_side_tot[mmd->totlvl]; - int i, j; - - for (i = 0; i < me->totpoly; ++i) { - for (j = 0; j < me->mpoly[i].totloop; j++) { - int g = me->mpoly[i].loopstart + j; - MDisps *mdisp = &mdisps[g]; - float (*disps)[3], (*ndisps)[3], (*hdisps)[3]; - int totdisp = multires_grid_tot[lvl]; - - disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); - - ndisps = disps; - hdisps = mdisp->disps; - - multires_copy_grid(ndisps, hdisps, nsize, hsize); - if (mdisp->hidden) { - BLI_bitmap *gh = - multires_mdisps_downsample_hidden(mdisp->hidden, - mdisp->level, - lvl); - MEM_freeN(mdisp->hidden); - mdisp->hidden = gh; - } - - ndisps += nsize * nsize; - hdisps += hsize * hsize; - - MEM_freeN(mdisp->disps); - mdisp->disps = disps; - mdisp->totdisp = totdisp; - mdisp->level = lvl; - - if (gpm) { - multires_grid_paint_mask_downsample(&gpm[g], lvl); - } - } - } - } - else { - multires_customdata_delete(me); - } - } - - multires_set_tot_level(ob, mmd, lvl); + Mesh *me = (Mesh *)ob->data; + int levels = mmd->totlvl - lvl; + MDisps *mdisps; + GridPaintMask *gpm; + + multires_set_tot_mdisps(me, mmd->totlvl); + CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); + + multires_force_update(ob); + + if (mdisps && levels > 0) { + if (lvl > 0) { + /* MLoop *ml = me->mloop; */ /*UNUSED*/ + int nsize = multires_side_tot[lvl]; + int hsize = multires_side_tot[mmd->totlvl]; + int i, j; + + for (i = 0; i < me->totpoly; ++i) { + for (j = 0; j < me->mpoly[i].totloop; j++) { + int g = me->mpoly[i].loopstart + j; + MDisps *mdisp = &mdisps[g]; + float(*disps)[3], (*ndisps)[3], (*hdisps)[3]; + int totdisp = multires_grid_tot[lvl]; + + disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disps"); + + ndisps = disps; + hdisps = mdisp->disps; + + multires_copy_grid(ndisps, hdisps, nsize, hsize); + if (mdisp->hidden) { + BLI_bitmap *gh = multires_mdisps_downsample_hidden(mdisp->hidden, mdisp->level, lvl); + MEM_freeN(mdisp->hidden); + mdisp->hidden = gh; + } + + ndisps += nsize * nsize; + hdisps += hsize * hsize; + + MEM_freeN(mdisp->disps); + mdisp->disps = disps; + mdisp->totdisp = totdisp; + mdisp->level = lvl; + + if (gpm) { + multires_grid_paint_mask_downsample(&gpm[g], lvl); + } + } + } + } + else { + multires_customdata_delete(me); + } + } + + multires_set_tot_level(ob, mmd, lvl); } /* (direction = 1) for delete higher, (direction = 0) for lower (not implemented yet) */ -void multiresModifier_del_levels(MultiresModifierData *mmd, Scene *scene, Object *ob, int direction) -{ - Mesh *me = BKE_mesh_from_object(ob); - int lvl = multires_get_level(scene, ob, mmd, false, true); - int levels = mmd->totlvl - lvl; - MDisps *mdisps; - - multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - - multires_force_update(ob); - - if (mdisps && levels > 0 && direction == 1) { - multires_del_higher(mmd, ob, lvl); - } - - multires_set_tot_level(ob, mmd, lvl); -} - -static DerivedMesh *multires_dm_create_local( - Scene *scene, Object *ob, DerivedMesh *dm, - int lvl, int totlvl, int simple, bool alloc_paint_mask, - int flags) -{ - MultiresModifierData mmd = {{NULL}}; - - mmd.lvl = lvl; - mmd.sculptlvl = lvl; - mmd.renderlvl = lvl; - mmd.totlvl = totlvl; - mmd.simple = simple; - - flags |= MULTIRES_USE_LOCAL_MMD; - if (alloc_paint_mask) - flags |= MULTIRES_ALLOC_PAINT_MASK; - - return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags); -} - -static DerivedMesh *subsurf_dm_create_local( - Scene *scene, Object *ob, DerivedMesh *dm, - int lvl, - bool is_simple, bool is_optimal, bool is_plain_uv, bool alloc_paint_mask, - bool for_render, - SubsurfFlags flags) -{ - SubsurfModifierData smd = {{NULL}}; - - smd.levels = smd.renderLevels = lvl; - smd.quality = 3; - if (!is_plain_uv) { - smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; - } - else { - smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE; - } - if (is_simple) { - smd.subdivType = ME_SIMPLE_SUBSURF; - } - if (is_optimal) { - smd.flags |= eSubsurfModifierFlag_ControlEdges; - } - - if (ob->mode & OB_MODE_EDIT) { - flags |= SUBSURF_IN_EDIT_MODE; - } - if (alloc_paint_mask) { - flags |= SUBSURF_ALLOC_PAINT_MASK; - } - if (for_render) { - flags |= SUBSURF_USE_RENDER_PARAMS; - } - - return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags); +void multiresModifier_del_levels(MultiresModifierData *mmd, + Scene *scene, + Object *ob, + int direction) +{ + Mesh *me = BKE_mesh_from_object(ob); + int lvl = multires_get_level(scene, ob, mmd, false, true); + int levels = mmd->totlvl - lvl; + MDisps *mdisps; + + multires_set_tot_mdisps(me, mmd->totlvl); + CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + + multires_force_update(ob); + + if (mdisps && levels > 0 && direction == 1) { + multires_del_higher(mmd, ob, lvl); + } + + multires_set_tot_level(ob, mmd, lvl); +} + +static DerivedMesh *multires_dm_create_local(Scene *scene, + Object *ob, + DerivedMesh *dm, + int lvl, + int totlvl, + int simple, + bool alloc_paint_mask, + int flags) +{ + MultiresModifierData mmd = {{NULL}}; + + mmd.lvl = lvl; + mmd.sculptlvl = lvl; + mmd.renderlvl = lvl; + mmd.totlvl = totlvl; + mmd.simple = simple; + + flags |= MULTIRES_USE_LOCAL_MMD; + if (alloc_paint_mask) + flags |= MULTIRES_ALLOC_PAINT_MASK; + + return multires_make_derived_from_derived(dm, &mmd, scene, ob, flags); +} + +static DerivedMesh *subsurf_dm_create_local(Scene *scene, + Object *ob, + DerivedMesh *dm, + int lvl, + bool is_simple, + bool is_optimal, + bool is_plain_uv, + bool alloc_paint_mask, + bool for_render, + SubsurfFlags flags) +{ + SubsurfModifierData smd = {{NULL}}; + + smd.levels = smd.renderLevels = lvl; + smd.quality = 3; + if (!is_plain_uv) { + smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + } + else { + smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE; + } + if (is_simple) { + smd.subdivType = ME_SIMPLE_SUBSURF; + } + if (is_optimal) { + smd.flags |= eSubsurfModifierFlag_ControlEdges; + } + + if (ob->mode & OB_MODE_EDIT) { + flags |= SUBSURF_IN_EDIT_MODE; + } + if (alloc_paint_mask) { + flags |= SUBSURF_ALLOC_PAINT_MASK; + } + if (for_render) { + flags |= SUBSURF_USE_RENDER_PARAMS; + } + + return subsurf_make_derived_from_derived(dm, &smd, scene, NULL, flags); } - - /* assumes no is normalized; return value's sign is negative if v is on * the other side of the plane */ static float v3_dist_from_plane(float v[3], float center[3], float no[3]) { - float s[3]; - sub_v3_v3v3(s, v, center); - return dot_v3v3(s, no); + float s[3]; + sub_v3_v3v3(s, v, center); + return dot_v3v3(s, no); } void multiresModifier_base_apply(MultiresModifierData *mmd, Scene *scene, Object *ob) { - DerivedMesh *cddm, *dispdm, *origdm; - Mesh *me; - const MeshElemMap *pmap; - float (*origco)[3]; - int i, j, k, offset, totlvl; - - multires_force_update(ob); - - me = BKE_mesh_from_object(ob); - totlvl = mmd->totlvl; - - /* nothing to do */ - if (!totlvl) - return; - - /* XXX - probably not necessary to regenerate the cddm so much? */ - - /* generate highest level with displacements */ - cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - dispdm = multires_dm_create_local(scene, ob, cddm, totlvl, totlvl, 0, 0, MULTIRES_IGNORE_SIMPLIFY); - cddm->release(cddm); - - /* copy the new locations of the base verts into the mesh */ - offset = dispdm->getNumVerts(dispdm) - me->totvert; - for (i = 0; i < me->totvert; ++i) { - dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co); - } - - /* heuristic to produce a better-fitting base mesh */ - - cddm = CDDM_from_mesh(me); - pmap = cddm->getPolyMap(ob, cddm); - origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco"); - for (i = 0; i < me->totvert; ++i) - copy_v3_v3(origco[i], me->mvert[i].co); - - for (i = 0; i < me->totvert; ++i) { - float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3]; - float dist; - int tot = 0; - - /* don't adjust verts not used by at least one poly */ - if (!pmap[i].count) - continue; - - /* find center */ - for (j = 0; j < pmap[i].count; j++) { - const MPoly *p = &me->mpoly[pmap[i].indices[j]]; - - /* this double counts, not sure if that's bad or good */ - for (k = 0; k < p->totloop; ++k) { - int vndx = me->mloop[p->loopstart + k].v; - if (vndx != i) { - add_v3_v3(center, origco[vndx]); - tot++; - } - } - } - mul_v3_fl(center, 1.0f / tot); - - /* find normal */ - for (j = 0; j < pmap[i].count; j++) { - const MPoly *p = &me->mpoly[pmap[i].indices[j]]; - MPoly fake_poly; - MLoop *fake_loops; - float (*fake_co)[3]; - float no[3]; - - /* set up poly, loops, and coords in order to call - * BKE_mesh_calc_poly_normal_coords() */ - fake_poly.totloop = p->totloop; - fake_poly.loopstart = 0; - fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops"); - fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co"); - - for (k = 0; k < p->totloop; ++k) { - int vndx = me->mloop[p->loopstart + k].v; - - fake_loops[k].v = k; - - if (vndx == i) - copy_v3_v3(fake_co[k], center); - else - copy_v3_v3(fake_co[k], origco[vndx]); - } - - BKE_mesh_calc_poly_normal_coords(&fake_poly, fake_loops, - (const float(*)[3])fake_co, no); - MEM_freeN(fake_loops); - MEM_freeN(fake_co); - - add_v3_v3(avg_no, no); - } - normalize_v3(avg_no); - - /* push vertex away from the plane */ - dist = v3_dist_from_plane(me->mvert[i].co, center, avg_no); - copy_v3_v3(push, avg_no); - mul_v3_fl(push, dist); - add_v3_v3(me->mvert[i].co, push); - - } - - MEM_freeN(origco); - cddm->release(cddm); - - /* Vertices were moved around, need to update normals after all the vertices are updated - * Probably this is possible to do in the loop above, but this is rather tricky because - * we don't know all needed vertices' coordinates there yet. - */ - BKE_mesh_calc_normals(me); - - /* subdivide the mesh to highest level without displacements */ - cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - origdm = subsurf_dm_create_local( - scene, ob, cddm, totlvl, 0, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, - 0, false, SUBSURF_IGNORE_SIMPLIFY); - cddm->release(cddm); - - /* calc disps */ - multiresModifier_disp_run(dispdm, me, NULL, CALC_DISPLACEMENTS, origdm->getGridData(origdm), totlvl); - - origdm->release(origdm); - dispdm->release(dispdm); + DerivedMesh *cddm, *dispdm, *origdm; + Mesh *me; + const MeshElemMap *pmap; + float(*origco)[3]; + int i, j, k, offset, totlvl; + + multires_force_update(ob); + + me = BKE_mesh_from_object(ob); + totlvl = mmd->totlvl; + + /* nothing to do */ + if (!totlvl) + return; + + /* XXX - probably not necessary to regenerate the cddm so much? */ + + /* generate highest level with displacements */ + cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + dispdm = multires_dm_create_local( + scene, ob, cddm, totlvl, totlvl, 0, 0, MULTIRES_IGNORE_SIMPLIFY); + cddm->release(cddm); + + /* copy the new locations of the base verts into the mesh */ + offset = dispdm->getNumVerts(dispdm) - me->totvert; + for (i = 0; i < me->totvert; ++i) { + dispdm->getVertCo(dispdm, offset + i, me->mvert[i].co); + } + + /* heuristic to produce a better-fitting base mesh */ + + cddm = CDDM_from_mesh(me); + pmap = cddm->getPolyMap(ob, cddm); + origco = MEM_calloc_arrayN(me->totvert, 3 * sizeof(float), "multires apply base origco"); + for (i = 0; i < me->totvert; ++i) + copy_v3_v3(origco[i], me->mvert[i].co); + + for (i = 0; i < me->totvert; ++i) { + float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3]; + float dist; + int tot = 0; + + /* don't adjust verts not used by at least one poly */ + if (!pmap[i].count) + continue; + + /* find center */ + for (j = 0; j < pmap[i].count; j++) { + const MPoly *p = &me->mpoly[pmap[i].indices[j]]; + + /* this double counts, not sure if that's bad or good */ + for (k = 0; k < p->totloop; ++k) { + int vndx = me->mloop[p->loopstart + k].v; + if (vndx != i) { + add_v3_v3(center, origco[vndx]); + tot++; + } + } + } + mul_v3_fl(center, 1.0f / tot); + + /* find normal */ + for (j = 0; j < pmap[i].count; j++) { + const MPoly *p = &me->mpoly[pmap[i].indices[j]]; + MPoly fake_poly; + MLoop *fake_loops; + float(*fake_co)[3]; + float no[3]; + + /* set up poly, loops, and coords in order to call + * BKE_mesh_calc_poly_normal_coords() */ + fake_poly.totloop = p->totloop; + fake_poly.loopstart = 0; + fake_loops = MEM_malloc_arrayN(p->totloop, sizeof(MLoop), "fake_loops"); + fake_co = MEM_malloc_arrayN(p->totloop, 3 * sizeof(float), "fake_co"); + + for (k = 0; k < p->totloop; ++k) { + int vndx = me->mloop[p->loopstart + k].v; + + fake_loops[k].v = k; + + if (vndx == i) + copy_v3_v3(fake_co[k], center); + else + copy_v3_v3(fake_co[k], origco[vndx]); + } + + BKE_mesh_calc_poly_normal_coords(&fake_poly, fake_loops, (const float(*)[3])fake_co, no); + MEM_freeN(fake_loops); + MEM_freeN(fake_co); + + add_v3_v3(avg_no, no); + } + normalize_v3(avg_no); + + /* push vertex away from the plane */ + dist = v3_dist_from_plane(me->mvert[i].co, center, avg_no); + copy_v3_v3(push, avg_no); + mul_v3_fl(push, dist); + add_v3_v3(me->mvert[i].co, push); + } + + MEM_freeN(origco); + cddm->release(cddm); + + /* Vertices were moved around, need to update normals after all the vertices are updated + * Probably this is possible to do in the loop above, but this is rather tricky because + * we don't know all needed vertices' coordinates there yet. + */ + BKE_mesh_calc_normals(me); + + /* subdivide the mesh to highest level without displacements */ + cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + origdm = subsurf_dm_create_local(scene, + ob, + cddm, + totlvl, + 0, + 0, + mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, + 0, + false, + SUBSURF_IGNORE_SIMPLIFY); + cddm->release(cddm); + + /* calc disps */ + multiresModifier_disp_run( + dispdm, me, NULL, CALC_DISPLACEMENTS, origdm->getGridData(origdm), totlvl); + + origdm->release(origdm); + dispdm->release(dispdm); } static void multires_subdivide( - MultiresModifierData *mmd, Scene *scene, Object *ob, - int totlvl, int updateblock, int simple) -{ - Mesh *me = ob->data; - MDisps *mdisps; - const int lvl = mmd->totlvl; - - if ((totlvl > multires_max_levels) || (me->totpoly == 0)) - return; - - BLI_assert(totlvl > lvl); - - multires_force_update(ob); - - mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - if (!mdisps) - mdisps = multires_mdisps_initialize_hidden(me, totlvl); - - if (mdisps->disps && !updateblock && lvl != 0) { - /* upsample */ - DerivedMesh *lowdm, *cddm, *highdm; - CCGElem **highGridData, **lowGridData, **subGridData; - CCGKey highGridKey, lowGridKey; - CCGSubSurf *ss; - int i, numGrids, highGridSize; - const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); - - /* create subsurf DM from original mesh at high level */ - cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - highdm = subsurf_dm_create_local( - NULL, ob, cddm, totlvl, simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, - has_mask, false, SUBSURF_IGNORE_SIMPLIFY); - ss = ((CCGDerivedMesh *)highdm)->ss; - - /* create multires DM from original mesh at low level */ - lowdm = multires_dm_create_local(scene, ob, cddm, lvl, lvl, simple, has_mask, MULTIRES_IGNORE_SIMPLIFY); - BLI_assert(lowdm != cddm); - cddm->release(cddm); - - /* copy subsurf grids and replace them with low displaced grids */ - numGrids = highdm->getNumGrids(highdm); - highGridSize = highdm->getGridSize(highdm); - highGridData = highdm->getGridData(highdm); - highdm->getGridKey(highdm, &highGridKey); - lowGridData = lowdm->getGridData(lowdm); - lowdm->getGridKey(lowdm, &lowGridKey); - - subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*"); - - for (i = 0; i < numGrids; ++i) { - /* backup subsurf grids */ - subGridData[i] = MEM_calloc_arrayN(highGridKey.elem_size, highGridSize * highGridSize, "subGridData"); - memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize); - - /* overwrite with current displaced grids */ - multires_copy_dm_grid(highGridData[i], lowGridData[i], &highGridKey, &lowGridKey); - } - - /* low lower level dm no longer needed at this point */ - lowdm->release(lowdm); - - /* subsurf higher levels again with displaced data */ - ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0); - ccgSubSurf_updateLevels(ss, lvl, NULL, 0); - - /* reallocate displacements */ - multires_reallocate_mdisps(me->totloop, mdisps, totlvl); - - /* compute displacements */ - multiresModifier_disp_run(highdm, me, NULL, CALC_DISPLACEMENTS, subGridData, totlvl); - - /* free */ - highdm->release(highdm); - for (i = 0; i < numGrids; ++i) - MEM_freeN(subGridData[i]); - MEM_freeN(subGridData); - } - else { - /* only reallocate, nothing to upsample */ - multires_reallocate_mdisps(me->totloop, mdisps, totlvl); - } - - multires_set_tot_level(ob, mmd, totlvl); -} - -void multiresModifier_subdivide(MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple) -{ - multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple); + MultiresModifierData *mmd, Scene *scene, Object *ob, int totlvl, int updateblock, int simple) +{ + Mesh *me = ob->data; + MDisps *mdisps; + const int lvl = mmd->totlvl; + + if ((totlvl > multires_max_levels) || (me->totpoly == 0)) + return; + + BLI_assert(totlvl > lvl); + + multires_force_update(ob); + + mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + if (!mdisps) + mdisps = multires_mdisps_initialize_hidden(me, totlvl); + + if (mdisps->disps && !updateblock && lvl != 0) { + /* upsample */ + DerivedMesh *lowdm, *cddm, *highdm; + CCGElem **highGridData, **lowGridData, **subGridData; + CCGKey highGridKey, lowGridKey; + CCGSubSurf *ss; + int i, numGrids, highGridSize; + const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); + + /* create subsurf DM from original mesh at high level */ + cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + highdm = subsurf_dm_create_local(NULL, + ob, + cddm, + totlvl, + simple, + 0, + mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, + has_mask, + false, + SUBSURF_IGNORE_SIMPLIFY); + ss = ((CCGDerivedMesh *)highdm)->ss; + + /* create multires DM from original mesh at low level */ + lowdm = multires_dm_create_local( + scene, ob, cddm, lvl, lvl, simple, has_mask, MULTIRES_IGNORE_SIMPLIFY); + BLI_assert(lowdm != cddm); + cddm->release(cddm); + + /* copy subsurf grids and replace them with low displaced grids */ + numGrids = highdm->getNumGrids(highdm); + highGridSize = highdm->getGridSize(highdm); + highGridData = highdm->getGridData(highdm); + highdm->getGridKey(highdm, &highGridKey); + lowGridData = lowdm->getGridData(lowdm); + lowdm->getGridKey(lowdm, &lowGridKey); + + subGridData = MEM_calloc_arrayN(numGrids, sizeof(float *), "subGridData*"); + + for (i = 0; i < numGrids; ++i) { + /* backup subsurf grids */ + subGridData[i] = MEM_calloc_arrayN( + highGridKey.elem_size, highGridSize * highGridSize, "subGridData"); + memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize); + + /* overwrite with current displaced grids */ + multires_copy_dm_grid(highGridData[i], lowGridData[i], &highGridKey, &lowGridKey); + } + + /* low lower level dm no longer needed at this point */ + lowdm->release(lowdm); + + /* subsurf higher levels again with displaced data */ + ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0); + ccgSubSurf_updateLevels(ss, lvl, NULL, 0); + + /* reallocate displacements */ + multires_reallocate_mdisps(me->totloop, mdisps, totlvl); + + /* compute displacements */ + multiresModifier_disp_run(highdm, me, NULL, CALC_DISPLACEMENTS, subGridData, totlvl); + + /* free */ + highdm->release(highdm); + for (i = 0; i < numGrids; ++i) + MEM_freeN(subGridData[i]); + MEM_freeN(subGridData); + } + else { + /* only reallocate, nothing to upsample */ + multires_reallocate_mdisps(me->totloop, mdisps, totlvl); + } + + multires_set_tot_level(ob, mmd, totlvl); +} + +void multiresModifier_subdivide( + MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple) +{ + multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple); } static void grid_tangent(const CCGKey *key, int x, int y, int axis, CCGElem *grid, float t[3]) { - if (axis == 0) { - if (x == key->grid_size - 1) { - if (y == key->grid_size - 1) - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y - 1), CCG_grid_elem_co(key, grid, x - 1, y - 1)); - else - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x - 1, y)); - } - else - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x + 1, y), CCG_grid_elem_co(key, grid, x, y)); - } - else if (axis == 1) { - if (y == key->grid_size - 1) { - if (x == key->grid_size - 1) - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x - 1, y), CCG_grid_elem_co(key, grid, x - 1, (y - 1))); - else - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x, (y - 1))); - } - else - sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, (y + 1)), CCG_grid_elem_co(key, grid, x, y)); - } + if (axis == 0) { + if (x == key->grid_size - 1) { + if (y == key->grid_size - 1) + sub_v3_v3v3( + t, CCG_grid_elem_co(key, grid, x, y - 1), CCG_grid_elem_co(key, grid, x - 1, y - 1)); + else + sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x - 1, y)); + } + else + sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x + 1, y), CCG_grid_elem_co(key, grid, x, y)); + } + else if (axis == 1) { + if (y == key->grid_size - 1) { + if (x == key->grid_size - 1) + sub_v3_v3v3( + t, CCG_grid_elem_co(key, grid, x - 1, y), CCG_grid_elem_co(key, grid, x - 1, (y - 1))); + else + sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, y), CCG_grid_elem_co(key, grid, x, (y - 1))); + } + else + sub_v3_v3v3(t, CCG_grid_elem_co(key, grid, x, (y + 1)), CCG_grid_elem_co(key, grid, x, y)); + } } /* Construct 3x3 tangent-space matrix in 'mat' */ -static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, - int x, int y, CCGElem *grid) +static void grid_tangent_matrix(float mat[3][3], const CCGKey *key, int x, int y, CCGElem *grid) { - grid_tangent(key, x, y, 0, grid, mat[0]); - normalize_v3(mat[0]); + grid_tangent(key, x, y, 0, grid, mat[0]); + normalize_v3(mat[0]); - grid_tangent(key, x, y, 1, grid, mat[1]); - normalize_v3(mat[1]); + grid_tangent(key, x, y, 1, grid, mat[1]); + normalize_v3(mat[1]); - copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y)); + copy_v3_v3(mat[2], CCG_grid_elem_no(key, grid, x, y)); } - typedef struct MultiresThreadedData { - DispOp op; - CCGElem **gridData, **subGridData; - CCGKey *key; - CCGKey *sub_key; - MPoly *mpoly; - MDisps *mdisps; - GridPaintMask *grid_paint_mask; - int *gridOffset; - int gridSize, dGridSize, dSkip; - float (*smat)[3]; + DispOp op; + CCGElem **gridData, **subGridData; + CCGKey *key; + CCGKey *sub_key; + MPoly *mpoly; + MDisps *mdisps; + GridPaintMask *grid_paint_mask; + int *gridOffset; + int gridSize, dGridSize, dSkip; + float (*smat)[3]; } MultiresThreadedData; -static void multires_disp_run_cb( - void *__restrict userdata, - const int pidx, - const ParallelRangeTLS *__restrict UNUSED(tls)) -{ - MultiresThreadedData *tdata = userdata; - - DispOp op = tdata->op; - CCGElem **gridData = tdata->gridData; - CCGElem **subGridData = tdata->subGridData; - CCGKey *key = tdata->key; - MPoly *mpoly = tdata->mpoly; - MDisps *mdisps = tdata->mdisps; - GridPaintMask *grid_paint_mask = tdata->grid_paint_mask; - int *gridOffset = tdata->gridOffset; - int gridSize = tdata->gridSize; - int dGridSize = tdata->dGridSize; - int dSkip = tdata->dSkip; - - const int numVerts = mpoly[pidx].totloop; - int S, x, y, gIndex = gridOffset[pidx]; - - for (S = 0; S < numVerts; ++S, ++gIndex) { - GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL; - MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S]; - CCGElem *grid = gridData[gIndex]; - CCGElem *subgrid = subGridData[gIndex]; - float (*dispgrid)[3] = NULL; - - dispgrid = mdisp->disps; - - /* if needed, reallocate multires paint mask */ - if (gpm && gpm->level < key->level) { - gpm->level = key->level; - if (gpm->data) { - MEM_freeN(gpm->data); - } - gpm->data = MEM_calloc_arrayN(key->grid_area, sizeof(float), "gpm.data"); - } - - for (y = 0; y < gridSize; y++) { - for (x = 0; x < gridSize; x++) { - float *co = CCG_grid_elem_co(key, grid, x, y); - float *sco = CCG_grid_elem_co(key, subgrid, x, y); - float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; - float mat[3][3], disp[3], d[3], mask; - - /* construct tangent space matrix */ - grid_tangent_matrix(mat, key, x, y, subgrid); - - switch (op) { - case APPLY_DISPLACEMENTS: - /* Convert displacement to object space - * and add to grid points */ - mul_v3_m3v3(disp, mat, data); - add_v3_v3v3(co, sco, disp); - break; - case CALC_DISPLACEMENTS: - /* Calculate displacement between new and old - * grid points and convert to tangent space */ - sub_v3_v3v3(disp, co, sco); - invert_m3(mat); - mul_v3_m3v3(data, mat, disp); - break; - case ADD_DISPLACEMENTS: - /* Convert subdivided displacements to tangent - * space and add to the original displacements */ - invert_m3(mat); - mul_v3_m3v3(d, mat, co); - add_v3_v3(data, d); - break; - } - - if (gpm) { - switch (op) { - case APPLY_DISPLACEMENTS: - /* Copy mask from gpm to DM */ - *CCG_grid_elem_mask(key, grid, x, y) = - paint_grid_paint_mask(gpm, key->level, x, y); - break; - case CALC_DISPLACEMENTS: - /* Copy mask from DM to gpm */ - mask = *CCG_grid_elem_mask(key, grid, x, y); - gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1); - break; - case ADD_DISPLACEMENTS: - /* Add mask displacement to gpm */ - gpm->data[y * gridSize + x] += - *CCG_grid_elem_mask(key, grid, x, y); - break; - } - } - } - } - } +static void multires_disp_run_cb(void *__restrict userdata, + const int pidx, + const ParallelRangeTLS *__restrict UNUSED(tls)) +{ + MultiresThreadedData *tdata = userdata; + + DispOp op = tdata->op; + CCGElem **gridData = tdata->gridData; + CCGElem **subGridData = tdata->subGridData; + CCGKey *key = tdata->key; + MPoly *mpoly = tdata->mpoly; + MDisps *mdisps = tdata->mdisps; + GridPaintMask *grid_paint_mask = tdata->grid_paint_mask; + int *gridOffset = tdata->gridOffset; + int gridSize = tdata->gridSize; + int dGridSize = tdata->dGridSize; + int dSkip = tdata->dSkip; + + const int numVerts = mpoly[pidx].totloop; + int S, x, y, gIndex = gridOffset[pidx]; + + for (S = 0; S < numVerts; ++S, ++gIndex) { + GridPaintMask *gpm = grid_paint_mask ? &grid_paint_mask[gIndex] : NULL; + MDisps *mdisp = &mdisps[mpoly[pidx].loopstart + S]; + CCGElem *grid = gridData[gIndex]; + CCGElem *subgrid = subGridData[gIndex]; + float(*dispgrid)[3] = NULL; + + dispgrid = mdisp->disps; + + /* if needed, reallocate multires paint mask */ + if (gpm && gpm->level < key->level) { + gpm->level = key->level; + if (gpm->data) { + MEM_freeN(gpm->data); + } + gpm->data = MEM_calloc_arrayN(key->grid_area, sizeof(float), "gpm.data"); + } + + for (y = 0; y < gridSize; y++) { + for (x = 0; x < gridSize; x++) { + float *co = CCG_grid_elem_co(key, grid, x, y); + float *sco = CCG_grid_elem_co(key, subgrid, x, y); + float *data = dispgrid[dGridSize * y * dSkip + x * dSkip]; + float mat[3][3], disp[3], d[3], mask; + + /* construct tangent space matrix */ + grid_tangent_matrix(mat, key, x, y, subgrid); + + switch (op) { + case APPLY_DISPLACEMENTS: + /* Convert displacement to object space + * and add to grid points */ + mul_v3_m3v3(disp, mat, data); + add_v3_v3v3(co, sco, disp); + break; + case CALC_DISPLACEMENTS: + /* Calculate displacement between new and old + * grid points and convert to tangent space */ + sub_v3_v3v3(disp, co, sco); + invert_m3(mat); + mul_v3_m3v3(data, mat, disp); + break; + case ADD_DISPLACEMENTS: + /* Convert subdivided displacements to tangent + * space and add to the original displacements */ + invert_m3(mat); + mul_v3_m3v3(d, mat, co); + add_v3_v3(data, d); + break; + } + + if (gpm) { + switch (op) { + case APPLY_DISPLACEMENTS: + /* Copy mask from gpm to DM */ + *CCG_grid_elem_mask(key, grid, x, y) = paint_grid_paint_mask(gpm, key->level, x, y); + break; + case CALC_DISPLACEMENTS: + /* Copy mask from DM to gpm */ + mask = *CCG_grid_elem_mask(key, grid, x, y); + gpm->data[y * gridSize + x] = CLAMPIS(mask, 0, 1); + break; + case ADD_DISPLACEMENTS: + /* Add mask displacement to gpm */ + gpm->data[y * gridSize + x] += *CCG_grid_elem_mask(key, grid, x, y); + break; + } + } + } + } + } } /* XXX WARNING: subsurf elements from dm and oldGridData *must* be of the same format (size), * because this code uses CCGKey's info from dm to access oldGridData's normals * (through the call to grid_tangent_matrix())! */ -static void multiresModifier_disp_run(DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl) -{ - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - CCGElem **gridData, **subGridData; - CCGKey key; - MPoly *mpoly = me->mpoly; - MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - GridPaintMask *grid_paint_mask = NULL; - int *gridOffset; - int i, gridSize, dGridSize, dSkip; - int totloop, totpoly; - - /* this happens in the dm made by bmesh_mdisps_space_set */ - if (dm2 && CustomData_has_layer(&dm2->loopData, CD_MDISPS)) { - mpoly = CustomData_get_layer(&dm2->polyData, CD_MPOLY); - mdisps = CustomData_get_layer(&dm2->loopData, CD_MDISPS); - totloop = dm2->numLoopData; - totpoly = dm2->numPolyData; - } - else { - totloop = me->totloop; - totpoly = me->totpoly; - } - - if (!mdisps) { - if (op == CALC_DISPLACEMENTS) - mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop); - else - return; - } - - /*numGrids = dm->getNumGrids(dm);*/ /*UNUSED*/ - gridSize = dm->getGridSize(dm); - gridData = dm->getGridData(dm); - gridOffset = dm->getGridOffset(dm); - dm->getGridKey(dm, &key); - subGridData = (oldGridData) ? oldGridData : gridData; - - dGridSize = multires_side_tot[totlvl]; - dSkip = (dGridSize - 1) / (gridSize - 1); - - /* multires paint masks */ - if (key.has_mask) - grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); - - /* when adding new faces in edit mode, need to allocate disps */ - for (i = 0; i < totloop; ++i) { - if (mdisps[i].disps == NULL) { - multires_reallocate_mdisps(totloop, mdisps, totlvl); - break; - } - } - - ParallelRangeSettings settings; - BLI_parallel_range_settings_defaults(&settings); - settings.min_iter_per_thread = CCG_TASK_LIMIT; - - MultiresThreadedData data = { - .op = op, - .gridData = gridData, - .subGridData = subGridData, - .key = &key, - .mpoly = mpoly, - .mdisps = mdisps, - .grid_paint_mask = grid_paint_mask, - .gridOffset = gridOffset, - .gridSize = gridSize, - .dGridSize = dGridSize, - .dSkip = dSkip, - }; - - BLI_task_parallel_range(0, totpoly, &data, multires_disp_run_cb, &settings); - - if (op == APPLY_DISPLACEMENTS) { - ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0); - ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0); - } +static void multiresModifier_disp_run( + DerivedMesh *dm, Mesh *me, DerivedMesh *dm2, DispOp op, CCGElem **oldGridData, int totlvl) +{ + CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; + CCGElem **gridData, **subGridData; + CCGKey key; + MPoly *mpoly = me->mpoly; + MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + GridPaintMask *grid_paint_mask = NULL; + int *gridOffset; + int i, gridSize, dGridSize, dSkip; + int totloop, totpoly; + + /* this happens in the dm made by bmesh_mdisps_space_set */ + if (dm2 && CustomData_has_layer(&dm2->loopData, CD_MDISPS)) { + mpoly = CustomData_get_layer(&dm2->polyData, CD_MPOLY); + mdisps = CustomData_get_layer(&dm2->loopData, CD_MDISPS); + totloop = dm2->numLoopData; + totpoly = dm2->numPolyData; + } + else { + totloop = me->totloop; + totpoly = me->totpoly; + } + + if (!mdisps) { + if (op == CALC_DISPLACEMENTS) + mdisps = CustomData_add_layer(&me->ldata, CD_MDISPS, CD_DEFAULT, NULL, me->totloop); + else + return; + } + + /*numGrids = dm->getNumGrids(dm);*/ /*UNUSED*/ + gridSize = dm->getGridSize(dm); + gridData = dm->getGridData(dm); + gridOffset = dm->getGridOffset(dm); + dm->getGridKey(dm, &key); + subGridData = (oldGridData) ? oldGridData : gridData; + + dGridSize = multires_side_tot[totlvl]; + dSkip = (dGridSize - 1) / (gridSize - 1); + + /* multires paint masks */ + if (key.has_mask) + grid_paint_mask = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); + + /* when adding new faces in edit mode, need to allocate disps */ + for (i = 0; i < totloop; ++i) { + if (mdisps[i].disps == NULL) { + multires_reallocate_mdisps(totloop, mdisps, totlvl); + break; + } + } + + ParallelRangeSettings settings; + BLI_parallel_range_settings_defaults(&settings); + settings.min_iter_per_thread = CCG_TASK_LIMIT; + + MultiresThreadedData data = { + .op = op, + .gridData = gridData, + .subGridData = subGridData, + .key = &key, + .mpoly = mpoly, + .mdisps = mdisps, + .grid_paint_mask = grid_paint_mask, + .gridOffset = gridOffset, + .gridSize = gridSize, + .dGridSize = dGridSize, + .dSkip = dSkip, + }; + + BLI_task_parallel_range(0, totpoly, &data, multires_disp_run_cb, &settings); + + if (op == APPLY_DISPLACEMENTS) { + ccgSubSurf_stitchFaces(ccgdm->ss, 0, NULL, 0); + ccgSubSurf_updateNormals(ccgdm->ss, NULL, 0); + } } void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - Object *ob; - Mesh *me; - MDisps *mdisps; - MultiresModifierData *mmd; - - ob = ccgdm->multires.ob; - me = ccgdm->multires.ob->data; - mmd = ccgdm->multires.mmd; - multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - - if (mdisps) { - int lvl = ccgdm->multires.lvl; - int totlvl = ccgdm->multires.totlvl; - - if (lvl < totlvl) { - DerivedMesh *lowdm, *cddm, *highdm; - CCGElem **highGridData, **lowGridData, **subGridData, **gridData, *diffGrid; - CCGKey highGridKey, lowGridKey; - CCGSubSurf *ss; - int i, j, numGrids, highGridSize, lowGridSize; - const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); - - /* create subsurf DM from original mesh at high level */ - if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform); - else cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - - highdm = subsurf_dm_create_local( - scene, ob, cddm, totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, - has_mask, false, SUBSURF_IGNORE_SIMPLIFY); - ss = ((CCGDerivedMesh *)highdm)->ss; - - /* create multires DM from original mesh and displacements */ - lowdm = multires_dm_create_local(scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask, MULTIRES_IGNORE_SIMPLIFY); - cddm->release(cddm); - - /* gather grid data */ - numGrids = highdm->getNumGrids(highdm); - highGridSize = highdm->getGridSize(highdm); - highGridData = highdm->getGridData(highdm); - highdm->getGridKey(highdm, &highGridKey); - lowGridSize = lowdm->getGridSize(lowdm); - lowGridData = lowdm->getGridData(lowdm); - lowdm->getGridKey(lowdm, &lowGridKey); - gridData = dm->getGridData(dm); - - BLI_assert(highGridKey.elem_size == lowGridKey.elem_size); - - subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); - diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff"); - - for (i = 0; i < numGrids; ++i) { - /* backup subsurf grids */ - subGridData[i] = MEM_calloc_arrayN(highGridKey.elem_size, highGridSize * highGridSize, "subGridData"); - memcpy(subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize); - - /* write difference of subsurf and displaced low level into high subsurf */ - for (j = 0; j < lowGridSize * lowGridSize; ++j) { - sub_v4_v4v4(CCG_elem_offset_co(&lowGridKey, diffGrid, j), - CCG_elem_offset_co(&lowGridKey, gridData[i], j), - CCG_elem_offset_co(&lowGridKey, lowGridData[i], j)); - } - - multires_copy_dm_grid(highGridData[i], diffGrid, &highGridKey, &lowGridKey); - } - - /* lower level dm no longer needed at this point */ - MEM_freeN(diffGrid); - lowdm->release(lowdm); - - /* subsurf higher levels again with difference of coordinates */ - ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0); - ccgSubSurf_updateLevels(ss, lvl, NULL, 0); - - /* add to displacements */ - multiresModifier_disp_run(highdm, me, NULL, ADD_DISPLACEMENTS, subGridData, mmd->totlvl); - - /* free */ - highdm->release(highdm); - for (i = 0; i < numGrids; ++i) - MEM_freeN(subGridData[i]); - MEM_freeN(subGridData); - } - else { - DerivedMesh *cddm, *subdm; - const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); - - if (ob->derivedDeform) cddm = CDDM_copy(ob->derivedDeform); - else cddm = CDDM_from_mesh(me); - DM_set_only_copy(cddm, &CD_MASK_BAREMESH); - - subdm = subsurf_dm_create_local( - scene, ob, cddm, mmd->totlvl, mmd->simple, 0, mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, - has_mask, false, SUBSURF_IGNORE_SIMPLIFY); - cddm->release(cddm); - - multiresModifier_disp_run(dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl); - - subdm->release(subdm); - } - } + CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; + Object *ob; + Mesh *me; + MDisps *mdisps; + MultiresModifierData *mmd; + + ob = ccgdm->multires.ob; + me = ccgdm->multires.ob->data; + mmd = ccgdm->multires.mmd; + multires_set_tot_mdisps(me, mmd->totlvl); + CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + + if (mdisps) { + int lvl = ccgdm->multires.lvl; + int totlvl = ccgdm->multires.totlvl; + + if (lvl < totlvl) { + DerivedMesh *lowdm, *cddm, *highdm; + CCGElem **highGridData, **lowGridData, **subGridData, **gridData, *diffGrid; + CCGKey highGridKey, lowGridKey; + CCGSubSurf *ss; + int i, j, numGrids, highGridSize, lowGridSize; + const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); + + /* create subsurf DM from original mesh at high level */ + if (ob->derivedDeform) + cddm = CDDM_copy(ob->derivedDeform); + else + cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + + highdm = subsurf_dm_create_local(scene, + ob, + cddm, + totlvl, + mmd->simple, + 0, + mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, + has_mask, + false, + SUBSURF_IGNORE_SIMPLIFY); + ss = ((CCGDerivedMesh *)highdm)->ss; + + /* create multires DM from original mesh and displacements */ + lowdm = multires_dm_create_local( + scene, ob, cddm, lvl, totlvl, mmd->simple, has_mask, MULTIRES_IGNORE_SIMPLIFY); + cddm->release(cddm); + + /* gather grid data */ + numGrids = highdm->getNumGrids(highdm); + highGridSize = highdm->getGridSize(highdm); + highGridData = highdm->getGridData(highdm); + highdm->getGridKey(highdm, &highGridKey); + lowGridSize = lowdm->getGridSize(lowdm); + lowGridData = lowdm->getGridData(lowdm); + lowdm->getGridKey(lowdm, &lowGridKey); + gridData = dm->getGridData(dm); + + BLI_assert(highGridKey.elem_size == lowGridKey.elem_size); + + subGridData = MEM_calloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); + diffGrid = MEM_calloc_arrayN(lowGridKey.elem_size, lowGridSize * lowGridSize, "diff"); + + for (i = 0; i < numGrids; ++i) { + /* backup subsurf grids */ + subGridData[i] = MEM_calloc_arrayN( + highGridKey.elem_size, highGridSize * highGridSize, "subGridData"); + memcpy( + subGridData[i], highGridData[i], highGridKey.elem_size * highGridSize * highGridSize); + + /* write difference of subsurf and displaced low level into high subsurf */ + for (j = 0; j < lowGridSize * lowGridSize; ++j) { + sub_v4_v4v4(CCG_elem_offset_co(&lowGridKey, diffGrid, j), + CCG_elem_offset_co(&lowGridKey, gridData[i], j), + CCG_elem_offset_co(&lowGridKey, lowGridData[i], j)); + } + + multires_copy_dm_grid(highGridData[i], diffGrid, &highGridKey, &lowGridKey); + } + + /* lower level dm no longer needed at this point */ + MEM_freeN(diffGrid); + lowdm->release(lowdm); + + /* subsurf higher levels again with difference of coordinates */ + ccgSubSurf_updateFromFaces(ss, lvl, NULL, 0); + ccgSubSurf_updateLevels(ss, lvl, NULL, 0); + + /* add to displacements */ + multiresModifier_disp_run(highdm, me, NULL, ADD_DISPLACEMENTS, subGridData, mmd->totlvl); + + /* free */ + highdm->release(highdm); + for (i = 0; i < numGrids; ++i) + MEM_freeN(subGridData[i]); + MEM_freeN(subGridData); + } + else { + DerivedMesh *cddm, *subdm; + const bool has_mask = CustomData_has_layer(&me->ldata, CD_GRID_PAINT_MASK); + + if (ob->derivedDeform) + cddm = CDDM_copy(ob->derivedDeform); + else + cddm = CDDM_from_mesh(me); + DM_set_only_copy(cddm, &CD_MASK_BAREMESH); + + subdm = subsurf_dm_create_local(scene, + ob, + cddm, + mmd->totlvl, + mmd->simple, + 0, + mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, + has_mask, + false, + SUBSURF_IGNORE_SIMPLIFY); + cddm->release(cddm); + + multiresModifier_disp_run( + dm, me, NULL, CALC_DISPLACEMENTS, subdm->getGridData(subdm), mmd->totlvl); + + subdm->release(subdm); + } + } } void multires_modifier_update_hidden(DerivedMesh *dm) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; - BLI_bitmap **grid_hidden = ccgdm->gridHidden; - Mesh *me = ccgdm->multires.ob->data; - MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); - int totlvl = ccgdm->multires.totlvl; - int lvl = ccgdm->multires.lvl; + CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; + BLI_bitmap **grid_hidden = ccgdm->gridHidden; + Mesh *me = ccgdm->multires.ob->data; + MDisps *mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); + int totlvl = ccgdm->multires.totlvl; + int lvl = ccgdm->multires.lvl; - if (mdisps) { - int i; + if (mdisps) { + int i; - for (i = 0; i < me->totloop; i++) { - MDisps *md = &mdisps[i]; - BLI_bitmap *gh = grid_hidden[i]; + for (i = 0; i < me->totloop; i++) { + MDisps *md = &mdisps[i]; + BLI_bitmap *gh = grid_hidden[i]; - if (!gh && md->hidden) { - MEM_freeN(md->hidden); - md->hidden = NULL; - } - else if (gh) { - gh = multires_mdisps_upsample_hidden(gh, lvl, totlvl, - md->hidden); - if (md->hidden) - MEM_freeN(md->hidden); + if (!gh && md->hidden) { + MEM_freeN(md->hidden); + md->hidden = NULL; + } + else if (gh) { + gh = multires_mdisps_upsample_hidden(gh, lvl, totlvl, md->hidden); + if (md->hidden) + MEM_freeN(md->hidden); - md->hidden = gh; - } - } - } + md->hidden = gh; + } + } + } } void multires_stitch_grids(Object *ob) { - if (ob == NULL) { - return; - } - SculptSession *sculpt_session = ob->sculpt; - if (sculpt_session == NULL) { - return; - } - PBVH *pbvh = sculpt_session->pbvh; - SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg; - if (pbvh == NULL || subdiv_ccg == NULL) { - return; - } - BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS); - /* NOTE: Currently CCG does not keep track of faces, making it impossible - * to use BKE_pbvh_get_grid_updates(). - */ - CCGFace **faces; - int num_faces; - BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces); - if (num_faces) { - BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces); - MEM_freeN(faces); - } -} - -DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm, - MultiresModifierData *mmd, - Scene *scene, - Object *ob, - MultiresFlags flags) -{ - Mesh *me = ob->data; - DerivedMesh *result; - CCGDerivedMesh *ccgdm = NULL; - CCGElem **gridData, **subGridData; - CCGKey key; - const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0; - const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0; - int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify); - int i, gridSize, numGrids; - - if (lvl == 0) - return dm; - - const int subsurf_flags = ignore_simplify ? SUBSURF_IGNORE_SIMPLIFY : 0; - - result = subsurf_dm_create_local(scene, ob, dm, lvl, - mmd->simple, mmd->flags & eMultiresModifierFlag_ControlEdges, - mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, - flags & MULTIRES_ALLOC_PAINT_MASK, - render, subsurf_flags); - - if (!(flags & MULTIRES_USE_LOCAL_MMD)) { - ccgdm = (CCGDerivedMesh *)result; - - ccgdm->multires.ob = ob; - ccgdm->multires.mmd = mmd; - ccgdm->multires.local_mmd = 0; - ccgdm->multires.lvl = lvl; - ccgdm->multires.totlvl = mmd->totlvl; - ccgdm->multires.modified_flags = 0; - } - - numGrids = result->getNumGrids(result); - gridSize = result->getGridSize(result); - gridData = result->getGridData(result); - result->getGridKey(result, &key); - - subGridData = MEM_malloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); - - for (i = 0; i < numGrids; i++) { - subGridData[i] = MEM_malloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData"); - memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize); - } - - multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - - /*run displacement*/ - multiresModifier_disp_run(result, ob->data, dm, APPLY_DISPLACEMENTS, subGridData, mmd->totlvl); - - /* copy hidden elements for this level */ - if (ccgdm) - multires_output_hidden_to_ccgdm(ccgdm, me, lvl); - - for (i = 0; i < numGrids; i++) - MEM_freeN(subGridData[i]); - MEM_freeN(subGridData); - - return result; + if (ob == NULL) { + return; + } + SculptSession *sculpt_session = ob->sculpt; + if (sculpt_session == NULL) { + return; + } + PBVH *pbvh = sculpt_session->pbvh; + SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg; + if (pbvh == NULL || subdiv_ccg == NULL) { + return; + } + BLI_assert(BKE_pbvh_type(pbvh) == PBVH_GRIDS); + /* NOTE: Currently CCG does not keep track of faces, making it impossible + * to use BKE_pbvh_get_grid_updates(). + */ + CCGFace **faces; + int num_faces; + BKE_pbvh_get_grid_updates(pbvh, false, (void ***)&faces, &num_faces); + if (num_faces) { + BKE_subdiv_ccg_average_stitch_faces(subdiv_ccg, faces, num_faces); + MEM_freeN(faces); + } +} + +DerivedMesh *multires_make_derived_from_derived( + DerivedMesh *dm, MultiresModifierData *mmd, Scene *scene, Object *ob, MultiresFlags flags) +{ + Mesh *me = ob->data; + DerivedMesh *result; + CCGDerivedMesh *ccgdm = NULL; + CCGElem **gridData, **subGridData; + CCGKey key; + const bool render = (flags & MULTIRES_USE_RENDER_PARAMS) != 0; + const bool ignore_simplify = (flags & MULTIRES_IGNORE_SIMPLIFY) != 0; + int lvl = multires_get_level(scene, ob, mmd, render, ignore_simplify); + int i, gridSize, numGrids; + + if (lvl == 0) + return dm; + + const int subsurf_flags = ignore_simplify ? SUBSURF_IGNORE_SIMPLIFY : 0; + + result = subsurf_dm_create_local(scene, + ob, + dm, + lvl, + mmd->simple, + mmd->flags & eMultiresModifierFlag_ControlEdges, + mmd->uv_smooth == SUBSURF_UV_SMOOTH_NONE, + flags & MULTIRES_ALLOC_PAINT_MASK, + render, + subsurf_flags); + + if (!(flags & MULTIRES_USE_LOCAL_MMD)) { + ccgdm = (CCGDerivedMesh *)result; + + ccgdm->multires.ob = ob; + ccgdm->multires.mmd = mmd; + ccgdm->multires.local_mmd = 0; + ccgdm->multires.lvl = lvl; + ccgdm->multires.totlvl = mmd->totlvl; + ccgdm->multires.modified_flags = 0; + } + + numGrids = result->getNumGrids(result); + gridSize = result->getGridSize(result); + gridData = result->getGridData(result); + result->getGridKey(result, &key); + + subGridData = MEM_malloc_arrayN(numGrids, sizeof(CCGElem *), "subGridData*"); + + for (i = 0; i < numGrids; i++) { + subGridData[i] = MEM_malloc_arrayN(key.elem_size, gridSize * gridSize, "subGridData"); + memcpy(subGridData[i], gridData[i], key.elem_size * gridSize * gridSize); + } + + multires_set_tot_mdisps(me, mmd->totlvl); + CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + + /*run displacement*/ + multiresModifier_disp_run(result, ob->data, dm, APPLY_DISPLACEMENTS, subGridData, mmd->totlvl); + + /* copy hidden elements for this level */ + if (ccgdm) + multires_output_hidden_to_ccgdm(ccgdm, me, lvl); + + for (i = 0; i < numGrids; i++) + MEM_freeN(subGridData[i]); + MEM_freeN(subGridData); + + return result; } /**** Old Multires code **** @@ -1430,874 +1464,988 @@ DerivedMesh *multires_make_derived_from_derived(DerivedMesh *dm, /* Adapted from sculptmode.c */ void old_mdisps_bilinear(float out[3], float (*disps)[3], const 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 (!disps || isnan(u) || isnan(v)) - return; - - 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; } + int x, y, x2, y2; + const int st_max = st - 1; + float urat, vrat, uopp; + float d[4][3], d2[2][3]; + + if (!disps || isnan(u) || isnan(v)) + return; + + 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) / M_LN2; - 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 = 0.0f, v = 0.0f; /* Quite gcc barking. */ - - disps = MEM_calloc_arrayN(newtotdisp, 3 * sizeof(float), "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->level = newlvl; - mdisp->disps = disps; + int newlvl = log(sqrt(mdisp->totdisp) - 1) / M_LN2; + 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 = 0.0f, v = 0.0f; /* Quite gcc barking. */ + + disps = MEM_calloc_arrayN(newtotdisp, 3 * sizeof(float), "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->level = newlvl; + mdisp->disps = disps; } void multires_load_old_250(Mesh *me) { - MDisps *mdisps, *mdisps2; - MFace *mf; - int i, j, k; - - mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS); + MDisps *mdisps, *mdisps2; + MFace *mf; + int i, j, k; - if (mdisps) { - for (i = 0; i < me->totface; i++) - if (mdisps[i].totdisp) - old_mdisps_convert(&me->mface[i], &mdisps[i]); + mdisps = CustomData_get_layer(&me->fdata, CD_MDISPS); - CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop); - mdisps2 = CustomData_get_layer(&me->ldata, CD_MDISPS); + if (mdisps) { + for (i = 0; i < me->totface; i++) + if (mdisps[i].totdisp) + old_mdisps_convert(&me->mface[i], &mdisps[i]); - k = 0; - mf = me->mface; - for (i = 0; i < me->totface; i++, mf++) { - int nvert = mf->v4 ? 4 : 3; - int totdisp = mdisps[i].totdisp / nvert; + CustomData_add_layer(&me->ldata, CD_MDISPS, CD_CALLOC, NULL, me->totloop); + mdisps2 = CustomData_get_layer(&me->ldata, CD_MDISPS); - for (j = 0; j < nvert; j++, k++) { - mdisps2[k].disps = MEM_calloc_arrayN(totdisp, 3 * sizeof(float), "multires disp in conversion"); - mdisps2[k].totdisp = totdisp; - mdisps2[k].level = mdisps[i].level; - memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp * j, totdisp); - } + k = 0; + mf = me->mface; + for (i = 0; i < me->totface; i++, mf++) { + int nvert = mf->v4 ? 4 : 3; + int totdisp = mdisps[i].totdisp / nvert; - } - } + for (j = 0; j < nvert; j++, k++) { + mdisps2[k].disps = MEM_calloc_arrayN( + totdisp, 3 * sizeof(float), "multires disp in conversion"); + mdisps2[k].totdisp = totdisp; + mdisps2[k].level = mdisps[i].level; + memcpy(mdisps2[k].disps, mdisps[i].disps + totdisp * j, totdisp); + } + } + } } /* Does not actually free lvl itself */ static void multires_free_level(MultiresLevel *lvl) { - if (lvl) { - if (lvl->faces) MEM_freeN(lvl->faces); - if (lvl->edges) MEM_freeN(lvl->edges); - if (lvl->colfaces) MEM_freeN(lvl->colfaces); - } + if (lvl) { + if (lvl->faces) + MEM_freeN(lvl->faces); + if (lvl->edges) + MEM_freeN(lvl->edges); + if (lvl->colfaces) + MEM_freeN(lvl->colfaces); + } } void multires_free(Multires *mr) { - if (mr) { - MultiresLevel *lvl = mr->levels.first; + if (mr) { + MultiresLevel *lvl = mr->levels.first; - /* Free the first-level data */ - if (lvl) { - CustomData_free(&mr->vdata, lvl->totvert); - CustomData_free(&mr->fdata, lvl->totface); - if (mr->edge_flags) - MEM_freeN(mr->edge_flags); - if (mr->edge_creases) - MEM_freeN(mr->edge_creases); - } + /* Free the first-level data */ + if (lvl) { + CustomData_free(&mr->vdata, lvl->totvert); + CustomData_free(&mr->fdata, lvl->totface); + if (mr->edge_flags) + MEM_freeN(mr->edge_flags); + if (mr->edge_creases) + MEM_freeN(mr->edge_creases); + } - while (lvl) { - multires_free_level(lvl); - lvl = lvl->next; - } + while (lvl) { + multires_free_level(lvl); + lvl = lvl->next; + } - /* mr->verts may be NULL when loading old files, see direct_link_mesh() in readfile.c, and T43560. */ - MEM_SAFE_FREE(mr->verts); + /* mr->verts may be NULL when loading old files, see direct_link_mesh() in readfile.c, and T43560. */ + MEM_SAFE_FREE(mr->verts); - BLI_freelistN(&mr->levels); + BLI_freelistN(&mr->levels); - MEM_freeN(mr); - } + MEM_freeN(mr); + } } typedef struct IndexNode { - struct IndexNode *next, *prev; - int index; + struct IndexNode *next, *prev; + int index; } IndexNode; -static void create_old_vert_face_map(ListBase **map, IndexNode **mem, const MultiresFace *mface, - const int totvert, const int totface) +static void create_old_vert_face_map(ListBase **map, + IndexNode **mem, + const MultiresFace *mface, + const int totvert, + const int totface) { - int i, j; - IndexNode *node = NULL; + int i, j; + IndexNode *node = NULL; - (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert face map"); - (*mem) = MEM_calloc_arrayN(totface, 4 * sizeof(IndexNode), "vert face map mem"); - node = *mem; + (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert face map"); + (*mem) = MEM_calloc_arrayN(totface, 4 * sizeof(IndexNode), "vert face map mem"); + node = *mem; - /* Find the users */ - for (i = 0; i < totface; ++i) { - for (j = 0; j < (mface[i].v[3] ? 4 : 3); ++j, ++node) { - node->index = i; - BLI_addtail(&(*map)[mface[i].v[j]], node); - } - } + /* Find the users */ + for (i = 0; i < totface; ++i) { + for (j = 0; j < (mface[i].v[3] ? 4 : 3); ++j, ++node) { + node->index = i; + BLI_addtail(&(*map)[mface[i].v[j]], node); + } + } } -static void create_old_vert_edge_map(ListBase **map, IndexNode **mem, const MultiresEdge *medge, - const int totvert, const int totedge) +static void create_old_vert_edge_map(ListBase **map, + IndexNode **mem, + const MultiresEdge *medge, + const int totvert, + const int totedge) { - int i, j; - IndexNode *node = NULL; + int i, j; + IndexNode *node = NULL; - (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert edge map"); - (*mem) = MEM_calloc_arrayN(totedge, 2 * sizeof(IndexNode), "vert edge map mem"); - node = *mem; + (*map) = MEM_calloc_arrayN(totvert, sizeof(ListBase), "vert edge map"); + (*mem) = MEM_calloc_arrayN(totedge, 2 * sizeof(IndexNode), "vert edge map mem"); + node = *mem; - /* Find the users */ - for (i = 0; i < totedge; ++i) { - for (j = 0; j < 2; ++j, ++node) { - node->index = i; - BLI_addtail(&(*map)[medge[i].v[j]], node); - } - } + /* Find the users */ + for (i = 0; i < totedge; ++i) { + for (j = 0; j < 2; ++j, ++node) { + node->index = i; + BLI_addtail(&(*map)[medge[i].v[j]], node); + } + } } -static MultiresFace *find_old_face(ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4) +static MultiresFace *find_old_face( + ListBase *map, MultiresFace *faces, int v1, int v2, int v3, int v4) { - IndexNode *n1; - int v[4], i, j; + IndexNode *n1; + int v[4], i, j; - v[0] = v1; - v[1] = v2; - v[2] = v3; - v[3] = v4; + v[0] = v1; + v[1] = v2; + v[2] = v3; + v[3] = v4; - for (n1 = map[v1].first; n1; n1 = n1->next) { - int fnd[4] = {0, 0, 0, 0}; + for (n1 = map[v1].first; n1; n1 = n1->next) { + int fnd[4] = {0, 0, 0, 0}; - for (i = 0; i < 4; ++i) { - for (j = 0; j < 4; ++j) { - if (v[i] == faces[n1->index].v[j]) - fnd[i] = 1; - } - } + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + if (v[i] == faces[n1->index].v[j]) + fnd[i] = 1; + } + } - if (fnd[0] && fnd[1] && fnd[2] && fnd[3]) - return &faces[n1->index]; - } + if (fnd[0] && fnd[1] && fnd[2] && fnd[3]) + return &faces[n1->index]; + } - return NULL; + return NULL; } static MultiresEdge *find_old_edge(ListBase *map, MultiresEdge *edges, int v1, int v2) { - IndexNode *n1, *n2; - - for (n1 = map[v1].first; n1; n1 = n1->next) { - for (n2 = map[v2].first; n2; n2 = n2->next) { - if (n1->index == n2->index) - return &edges[n1->index]; - } - } - - return NULL; -} - -static void multires_load_old_edges(ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov) -{ - int emid = find_old_edge(emap[2], lvl->edges, v1, v2)->mid; - vvmap[dst + mov] = emid; - - if (lvl->next->next) { - multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v1, emid, mov / 2); - multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v2, emid, -mov / 2); - } -} - -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 fmid; - int emid13, emid14, emid23, emid24; - - if (lvl && lvl->next) { - fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid; - vvmap[dst] = fmid; - - emid13 = find_old_edge(emap[1], lvl->edges, v1, v3)->mid; - emid14 = find_old_edge(emap[1], lvl->edges, v1, v4)->mid; - emid23 = find_old_edge(emap[1], lvl->edges, v2, v3)->mid; - emid24 = find_old_edge(emap[1], lvl->edges, v2, v4)->mid; - - - multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 + st3, - fmid, v2, emid23, emid24, st2, st3 / 2); - - multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 + st3, - emid14, emid24, fmid, v4, st2, st3 / 2); - - multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst + st2 * st3 - st3, - emid13, emid23, v3, fmid, st2, st3 / 2); - - multires_load_old_faces(fmap + 1, emap + 1, lvl->next, vvmap, dst - st2 * st3 - st3, - v1, fmid, emid13, emid14, st2, st3 / 2); - - if (lvl->next->next) { - multires_load_old_edges(emap, lvl->next, vvmap, dst, emid24, fmid, st3); - multires_load_old_edges(emap, lvl->next, vvmap, dst, emid13, fmid, -st3); - multires_load_old_edges(emap, lvl->next, vvmap, dst, emid14, fmid, -st2 * st3); - multires_load_old_edges(emap, lvl->next, vvmap, dst, emid23, fmid, st2 * st3); - } - } + IndexNode *n1, *n2; + + for (n1 = map[v1].first; n1; n1 = n1->next) { + for (n2 = map[v2].first; n2; n2 = n2->next) { + if (n1->index == n2->index) + return &edges[n1->index]; + } + } + + return NULL; +} + +static void multires_load_old_edges( + ListBase **emap, MultiresLevel *lvl, int *vvmap, int dst, int v1, int v2, int mov) +{ + int emid = find_old_edge(emap[2], lvl->edges, v1, v2)->mid; + vvmap[dst + mov] = emid; + + if (lvl->next->next) { + multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v1, emid, mov / 2); + multires_load_old_edges(emap + 1, lvl->next, vvmap, dst + mov, v2, emid, -mov / 2); + } +} + +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 fmid; + int emid13, emid14, emid23, emid24; + + if (lvl && lvl->next) { + fmid = find_old_face(fmap[1], lvl->faces, v1, v2, v3, v4)->mid; + vvmap[dst] = fmid; + + emid13 = find_old_edge(emap[1], lvl->edges, v1, v3)->mid; + emid14 = find_old_edge(emap[1], lvl->edges, v1, v4)->mid; + emid23 = find_old_edge(emap[1], lvl->edges, v2, v3)->mid; + emid24 = find_old_edge(emap[1], lvl->edges, v2, v4)->mid; + + multires_load_old_faces(fmap + 1, + emap + 1, + lvl->next, + vvmap, + dst + st2 * st3 + st3, + fmid, + v2, + emid23, + emid24, + st2, + st3 / 2); + + multires_load_old_faces(fmap + 1, + emap + 1, + lvl->next, + vvmap, + dst - st2 * st3 + st3, + emid14, + emid24, + fmid, + v4, + st2, + st3 / 2); + + multires_load_old_faces(fmap + 1, + emap + 1, + lvl->next, + vvmap, + dst + st2 * st3 - st3, + emid13, + emid23, + v3, + fmid, + st2, + st3 / 2); + + multires_load_old_faces(fmap + 1, + emap + 1, + lvl->next, + vvmap, + dst - st2 * st3 - st3, + v1, + fmid, + emid13, + emid14, + st2, + st3 / 2); + + if (lvl->next->next) { + multires_load_old_edges(emap, lvl->next, vvmap, dst, emid24, fmid, st3); + multires_load_old_edges(emap, lvl->next, vvmap, dst, emid13, fmid, -st3); + multires_load_old_edges(emap, lvl->next, vvmap, dst, emid14, fmid, -st2 * st3); + multires_load_old_edges(emap, lvl->next, vvmap, dst, emid23, fmid, st2 * st3); + } + } } static void multires_mvert_to_ss(DerivedMesh *dm, MVert *mvert) { - CCGDerivedMesh *ccgdm = (CCGDerivedMesh *) dm; - CCGSubSurf *ss = ccgdm->ss; - CCGElem *vd; - CCGKey key; - int index; - int totvert, totedge, totface; - int gridSize = ccgSubSurf_getGridSize(ss); - int edgeSize = ccgSubSurf_getEdgeSize(ss); - int i = 0; - - dm->getGridKey(dm, &key); - - 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(CCG_elem_co(&key, vd), 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(CCG_elem_co(&key, vd), 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(CCG_elem_co(&key, vd), 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(CCG_elem_co(&key, vd), 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(CCG_elem_co(&key, vd), mvert[i].co); - i++; - } - - ccgSubSurf_updateToFaces(ss, 0, NULL, 0); + CCGDerivedMesh *ccgdm = (CCGDerivedMesh *)dm; + CCGSubSurf *ss = ccgdm->ss; + CCGElem *vd; + CCGKey key; + int index; + int totvert, totedge, totface; + int gridSize = ccgSubSurf_getGridSize(ss); + int edgeSize = ccgSubSurf_getEdgeSize(ss); + int i = 0; + + dm->getGridKey(dm, &key); + + 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(CCG_elem_co(&key, vd), 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(CCG_elem_co(&key, vd), 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(CCG_elem_co(&key, vd), 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(CCG_elem_co(&key, vd), 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(CCG_elem_co(&key, vd), mvert[i].co); + i++; + } + + ccgSubSurf_updateToFaces(ss, 0, NULL, 0); } /* Loads a multires object stored in the old Multires struct into the new format */ static void multires_load_old_dm(DerivedMesh *dm, Mesh *me, int totlvl) { - MultiresLevel *lvl, *lvl1; - Multires *mr = me->mr; - MVert *vsrc, *vdst; - unsigned int src, dst; - int st_last = multires_side_tot[totlvl - 1] - 1; - int extedgelen = multires_side_tot[totlvl] - 2; - int *vvmap; // inorder for dst, map to src - int crossedgelen; - int s, x, tottri, totquad; - unsigned int i, j, totvert; - - src = 0; - vsrc = mr->verts; - vdst = dm->getVertArray(dm); - totvert = (unsigned int)dm->getNumVerts(dm); - vvmap = MEM_calloc_arrayN(totvert, sizeof(int), "multires vvmap"); - - if (!vvmap) { - return; - } - - lvl1 = mr->levels.first; - /* Load base verts */ - for (i = 0; i < lvl1->totvert; ++i) { - vvmap[totvert - lvl1->totvert + i] = src; - src++; - } - - /* Original edges */ - dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge; - for (i = 0; i < lvl1->totedge; ++i) { - int ldst = dst + extedgelen * i; - int lsrc = src; - lvl = lvl1->next; - - for (j = 2; j <= mr->level_count; ++j) { - int base = multires_side_tot[totlvl - j + 1] - 2; - int skip = multires_side_tot[totlvl - j + 2] - 1; - int st = multires_side_tot[j - 1] - 1; - - for (x = 0; x < st; ++x) - vvmap[ldst + base + x * skip] = lsrc + st * i + x; - - lsrc += lvl->totvert - lvl->prev->totvert; - lvl = lvl->next; - } - } - - /* Center points */ - dst = 0; - for (i = 0; i < lvl1->totface; ++i) { - int sides = lvl1->faces[i].v[3] ? 4 : 3; - - vvmap[dst] = src + lvl1->totedge + i; - dst += 1 + sides * (st_last - 1) * st_last; - } - - - /* The rest is only for level 3 and up */ - if (lvl1->next && lvl1->next->next) { - ListBase **fmap, **emap; - IndexNode **fmem, **emem; - - /* Face edge cross */ - tottri = totquad = 0; - crossedgelen = multires_side_tot[totlvl - 1] - 2; - dst = 0; - for (i = 0; i < lvl1->totface; ++i) { - int sides = lvl1->faces[i].v[3] ? 4 : 3; - - lvl = lvl1->next->next; - dst++; - - for (j = 3; j <= mr->level_count; ++j) { - int base = multires_side_tot[totlvl - j + 1] - 2; - int skip = multires_side_tot[totlvl - j + 2] - 1; - int st = pow(2, j - 2); - int st2 = pow(2, j - 3); - int lsrc = lvl->prev->totvert; - - /* Skip exterior edge verts */ - lsrc += lvl1->totedge * st; - - /* Skip earlier face edge crosses */ - lsrc += st2 * (tottri * 3 + totquad * 4); - - for (s = 0; s < sides; ++s) { - for (x = 0; x < st2; ++x) { - vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc; - lsrc++; - } - } - - lvl = lvl->next; - } - - dst += sides * (st_last - 1) * st_last; - - if (sides == 4) ++totquad; - else ++tottri; - - } - - /* calculate vert to edge/face maps for each level (except the last) */ - fmap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires fmap"); - emap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires emap"); - fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem"); - emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem"); - lvl = lvl1; - 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; - } - - /* Interior face verts */ - /* lvl = lvl1->next->next; */ /* UNUSED */ - dst = 0; - for (j = 0; j < lvl1->totface; ++j) { - int sides = lvl1->faces[j].v[3] ? 4 : 3; - int ldst = dst + 1 + sides * (st_last - 1); - - for (s = 0; s < sides; ++s) { - int st2 = multires_side_tot[totlvl - 1] - 2; - int st3 = multires_side_tot[totlvl - 2] - 2; - int st4 = st3 == 0 ? 1 : (st3 + 1) / 2; - int mid = ldst + st2 * st3 + st3; - int cv = lvl1->faces[j].v[s]; - int nv = lvl1->faces[j].v[s == sides - 1 ? 0 : s + 1]; - int pv = lvl1->faces[j].v[s == 0 ? sides - 1 : s - 1]; - - multires_load_old_faces(fmap, emap, lvl1->next, vvmap, mid, - vvmap[dst], cv, - find_old_edge(emap[0], lvl1->edges, pv, cv)->mid, - find_old_edge(emap[0], lvl1->edges, cv, nv)->mid, - st2, st4); - - ldst += (st_last - 1) * (st_last - 1); - } - - - dst = ldst; - } - - /*lvl = lvl->next;*/ /*UNUSED*/ - - for (i = 0; i < (unsigned int)(mr->level_count - 1); ++i) { - MEM_freeN(fmap[i]); - MEM_freeN(fmem[i]); - MEM_freeN(emap[i]); - MEM_freeN(emem[i]); - } - - MEM_freeN(fmap); - MEM_freeN(emap); - MEM_freeN(fmem); - MEM_freeN(emem); - } - - /* Transfer verts */ - for (i = 0; i < totvert; ++i) - copy_v3_v3(vdst[i].co, vsrc[vvmap[i]].co); - - MEM_freeN(vvmap); - - multires_mvert_to_ss(dm, vdst); + MultiresLevel *lvl, *lvl1; + Multires *mr = me->mr; + MVert *vsrc, *vdst; + unsigned int src, dst; + int st_last = multires_side_tot[totlvl - 1] - 1; + int extedgelen = multires_side_tot[totlvl] - 2; + int *vvmap; // inorder for dst, map to src + int crossedgelen; + int s, x, tottri, totquad; + unsigned int i, j, totvert; + + src = 0; + vsrc = mr->verts; + vdst = dm->getVertArray(dm); + totvert = (unsigned int)dm->getNumVerts(dm); + vvmap = MEM_calloc_arrayN(totvert, sizeof(int), "multires vvmap"); + + if (!vvmap) { + return; + } + + lvl1 = mr->levels.first; + /* Load base verts */ + for (i = 0; i < lvl1->totvert; ++i) { + vvmap[totvert - lvl1->totvert + i] = src; + src++; + } + + /* Original edges */ + dst = totvert - lvl1->totvert - extedgelen * lvl1->totedge; + for (i = 0; i < lvl1->totedge; ++i) { + int ldst = dst + extedgelen * i; + int lsrc = src; + lvl = lvl1->next; + + for (j = 2; j <= mr->level_count; ++j) { + int base = multires_side_tot[totlvl - j + 1] - 2; + int skip = multires_side_tot[totlvl - j + 2] - 1; + int st = multires_side_tot[j - 1] - 1; + + for (x = 0; x < st; ++x) + vvmap[ldst + base + x * skip] = lsrc + st * i + x; + + lsrc += lvl->totvert - lvl->prev->totvert; + lvl = lvl->next; + } + } + + /* Center points */ + dst = 0; + for (i = 0; i < lvl1->totface; ++i) { + int sides = lvl1->faces[i].v[3] ? 4 : 3; + + vvmap[dst] = src + lvl1->totedge + i; + dst += 1 + sides * (st_last - 1) * st_last; + } + + /* The rest is only for level 3 and up */ + if (lvl1->next && lvl1->next->next) { + ListBase **fmap, **emap; + IndexNode **fmem, **emem; + + /* Face edge cross */ + tottri = totquad = 0; + crossedgelen = multires_side_tot[totlvl - 1] - 2; + dst = 0; + for (i = 0; i < lvl1->totface; ++i) { + int sides = lvl1->faces[i].v[3] ? 4 : 3; + + lvl = lvl1->next->next; + dst++; + + for (j = 3; j <= mr->level_count; ++j) { + int base = multires_side_tot[totlvl - j + 1] - 2; + int skip = multires_side_tot[totlvl - j + 2] - 1; + int st = pow(2, j - 2); + int st2 = pow(2, j - 3); + int lsrc = lvl->prev->totvert; + + /* Skip exterior edge verts */ + lsrc += lvl1->totedge * st; + + /* Skip earlier face edge crosses */ + lsrc += st2 * (tottri * 3 + totquad * 4); + + for (s = 0; s < sides; ++s) { + for (x = 0; x < st2; ++x) { + vvmap[dst + crossedgelen * (s + 1) - base - x * skip - 1] = lsrc; + lsrc++; + } + } + + lvl = lvl->next; + } + + dst += sides * (st_last - 1) * st_last; + + if (sides == 4) + ++totquad; + else + ++tottri; + } + + /* calculate vert to edge/face maps for each level (except the last) */ + fmap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires fmap"); + emap = MEM_calloc_arrayN((mr->level_count - 1), sizeof(ListBase *), "multires emap"); + fmem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires fmem"); + emem = MEM_calloc_arrayN((mr->level_count - 1), sizeof(IndexNode *), "multires emem"); + lvl = lvl1; + 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; + } + + /* Interior face verts */ + /* lvl = lvl1->next->next; */ /* UNUSED */ + dst = 0; + for (j = 0; j < lvl1->totface; ++j) { + int sides = lvl1->faces[j].v[3] ? 4 : 3; + int ldst = dst + 1 + sides * (st_last - 1); + + for (s = 0; s < sides; ++s) { + int st2 = multires_side_tot[totlvl - 1] - 2; + int st3 = multires_side_tot[totlvl - 2] - 2; + int st4 = st3 == 0 ? 1 : (st3 + 1) / 2; + int mid = ldst + st2 * st3 + st3; + int cv = lvl1->faces[j].v[s]; + int nv = lvl1->faces[j].v[s == sides - 1 ? 0 : s + 1]; + int pv = lvl1->faces[j].v[s == 0 ? sides - 1 : s - 1]; + + multires_load_old_faces(fmap, + emap, + lvl1->next, + vvmap, + mid, + vvmap[dst], + cv, + find_old_edge(emap[0], lvl1->edges, pv, cv)->mid, + find_old_edge(emap[0], lvl1->edges, cv, nv)->mid, + st2, + st4); + + ldst += (st_last - 1) * (st_last - 1); + } + + dst = ldst; + } + + /*lvl = lvl->next;*/ /*UNUSED*/ + + for (i = 0; i < (unsigned int)(mr->level_count - 1); ++i) { + MEM_freeN(fmap[i]); + MEM_freeN(fmem[i]); + MEM_freeN(emap[i]); + MEM_freeN(emem[i]); + } + + MEM_freeN(fmap); + MEM_freeN(emap); + MEM_freeN(fmem); + MEM_freeN(emem); + } + + /* Transfer verts */ + for (i = 0; i < totvert; ++i) + copy_v3_v3(vdst[i].co, vsrc[vvmap[i]].co); + + MEM_freeN(vvmap); + + multires_mvert_to_ss(dm, vdst); } /* Copy the first-level vcol data to the mesh, if it exists */ /* Warning: higher-level vcol data will be lost */ static void multires_load_old_vcols(Mesh *me) { - MultiresLevel *lvl; - MultiresColFace *colface; - MCol *mcol; - int i, j; + MultiresLevel *lvl; + MultiresColFace *colface; + MCol *mcol; + int i, j; - if (!(lvl = me->mr->levels.first)) - return; + if (!(lvl = me->mr->levels.first)) + return; - if (!(colface = lvl->colfaces)) - return; + if (!(colface = lvl->colfaces)) + return; - /* older multires format never supported multiple vcol layers, - * so we can assume the active vcol layer is the correct one */ - if (!(mcol = CustomData_get_layer(&me->fdata, CD_MCOL))) - return; + /* older multires format never supported multiple vcol layers, + * so we can assume the active vcol layer is the correct one */ + if (!(mcol = CustomData_get_layer(&me->fdata, CD_MCOL))) + return; - for (i = 0; i < me->totface; ++i) { - for (j = 0; j < 4; ++j) { - mcol[i * 4 + j].a = colface[i].col[j].a; - mcol[i * 4 + j].r = colface[i].col[j].r; - mcol[i * 4 + j].g = colface[i].col[j].g; - mcol[i * 4 + j].b = colface[i].col[j].b; - } - } + for (i = 0; i < me->totface; ++i) { + for (j = 0; j < 4; ++j) { + mcol[i * 4 + j].a = colface[i].col[j].a; + mcol[i * 4 + j].r = colface[i].col[j].r; + mcol[i * 4 + j].g = colface[i].col[j].g; + mcol[i * 4 + j].b = colface[i].col[j].b; + } + } } /* Copy the first-level face-flag data to the mesh */ static void multires_load_old_face_flags(Mesh *me) { - MultiresLevel *lvl; - MultiresFace *faces; - int i; + MultiresLevel *lvl; + MultiresFace *faces; + int i; - if (!(lvl = me->mr->levels.first)) - return; + if (!(lvl = me->mr->levels.first)) + return; - if (!(faces = lvl->faces)) - return; + if (!(faces = lvl->faces)) + return; - for (i = 0; i < me->totface; ++i) - me->mface[i].flag = faces[i].flag; + for (i = 0; i < me->totface; ++i) + me->mface[i].flag = faces[i].flag; } 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]; - me->mface[i].mat_nr = lvl->faces[i].mat_nr; - } - - /* Copy the first-level data to the mesh */ - /* XXX We must do this before converting tessfaces to polys/lopps! */ - 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); - CustomData_reset(&me->mr->vdata); - CustomData_reset(&me->mr->fdata); - - multires_load_old_vcols(me); - multires_load_old_face_flags(me); - - /* multiresModifier_subdivide (actually, multires_subdivide) expects polys, not tessfaces! */ - BKE_mesh_convert_mfaces_to_mpolys(me); - - /* 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, NULL, ob, 1, 0); - - mmd->lvl = mmd->totlvl; - orig = CDDM_from_mesh(me); - /* XXX We *must* alloc paint mask here, else we have some kind of mismatch in - * multires_modifier_update_mdisps() (called by dm->release(dm)), which always creates the - * reference subsurfed dm with this option, before calling multiresModifier_disp_run(), - * which implicitly expects both subsurfs from its first dm and oldGridData parameters to - * be of the same "format"! */ - dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0); - - multires_load_old_dm(dm, me, mmd->totlvl + 1); - - multires_dm_mark_as_modified(dm, MULTIRES_COORDS_MODIFIED); - dm->release(dm); - orig->release(orig); - - /* Remove the old multires */ - multires_free(me->mr); - me->mr = NULL; + 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]; + me->mface[i].mat_nr = lvl->faces[i].mat_nr; + } + + /* Copy the first-level data to the mesh */ + /* XXX We must do this before converting tessfaces to polys/lopps! */ + 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); + CustomData_reset(&me->mr->vdata); + CustomData_reset(&me->mr->fdata); + + multires_load_old_vcols(me); + multires_load_old_face_flags(me); + + /* multiresModifier_subdivide (actually, multires_subdivide) expects polys, not tessfaces! */ + BKE_mesh_convert_mfaces_to_mpolys(me); + + /* 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, NULL, ob, 1, 0); + + mmd->lvl = mmd->totlvl; + orig = CDDM_from_mesh(me); + /* XXX We *must* alloc paint mask here, else we have some kind of mismatch in + * multires_modifier_update_mdisps() (called by dm->release(dm)), which always creates the + * reference subsurfed dm with this option, before calling multiresModifier_disp_run(), + * which implicitly expects both subsurfs from its first dm and oldGridData parameters to + * be of the same "format"! */ + dm = multires_make_derived_from_derived(orig, mmd, NULL, ob, 0); + + multires_load_old_dm(dm, me, mmd->totlvl + 1); + + multires_dm_mark_as_modified(dm, MULTIRES_COORDS_MODIFIED); + dm->release(dm); + orig->release(orig); + + /* Remove the old multires */ + multires_free(me->mr); + me->mr = NULL; } /* If 'ob_src' and 'ob_dst' both have multires modifiers, synchronize them * such that 'ob_dst' has the same total number of levels as 'ob_src'. */ -void multiresModifier_sync_levels_ex(Scene *scene, Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst) +void multiresModifier_sync_levels_ex(Scene *scene, + Object *ob_dst, + MultiresModifierData *mmd_src, + MultiresModifierData *mmd_dst) { - if (mmd_src->totlvl == mmd_dst->totlvl) { - return; - } + if (mmd_src->totlvl == mmd_dst->totlvl) { + return; + } - if (mmd_src->totlvl > mmd_dst->totlvl) { - multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple); - } - else { - multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); - } + if (mmd_src->totlvl > mmd_dst->totlvl) { + multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple); + } + else { + multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); + } } static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst) { - MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true); - MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true); + MultiresModifierData *mmd_src = get_multires_modifier(scene, ob_src, true); + MultiresModifierData *mmd_dst = get_multires_modifier(scene, ob_dst, true); - if (!mmd_src) { - /* object could have MDISP even when there is no multires modifier - * this could lead to troubles due to i've got no idea how mdisp could be - * upsampled correct without modifier data. - * just remove mdisps if no multires present (nazgul) */ + if (!mmd_src) { + /* object could have MDISP even when there is no multires modifier + * this could lead to troubles due to i've got no idea how mdisp could be + * upsampled correct without modifier data. + * just remove mdisps if no multires present (nazgul) */ - multires_customdata_delete(ob_src->data); - } + multires_customdata_delete(ob_src->data); + } - if (mmd_src && mmd_dst) { - multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst); - } + if (mmd_src && mmd_dst) { + multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst); + } } static void multires_apply_uniform_scale(Object *object, const float scale) { - Mesh *mesh = (Mesh *)object->data; - MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); - for (int i = 0; i < mesh->totloop; ++i) { - MDisps *grid = &mdisps[i]; - for (int j = 0; j < grid->totdisp; ++j) { - mul_v3_fl(grid->disps[j], scale); - } - } -} - -static void multires_apply_smat( - struct Depsgraph *UNUSED(depsgraph), - Scene *scene, - Object *object, - float smat[3][3]) -{ - const MultiresModifierData *mmd = get_multires_modifier(scene, object, true); - if (mmd == NULL || mmd->totlvl == 0) { - return; - } - /* Make sure layer present. */ - Mesh *mesh = (Mesh *)object->data; - CustomData_external_read( - &mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); - if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) { - return; - } - if (is_uniform_scaled_m3(smat)) { - const float scale = mat3_to_scale(smat); - multires_apply_uniform_scale(object, scale); - } - else { - /* TODO(sergey): This branch of code actually requires more work to - * preserve all the details. - */ - const float scale = mat3_to_scale(smat); - multires_apply_uniform_scale(object, scale); - } + Mesh *mesh = (Mesh *)object->data; + MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + for (int i = 0; i < mesh->totloop; ++i) { + MDisps *grid = &mdisps[i]; + for (int j = 0; j < grid->totdisp; ++j) { + mul_v3_fl(grid->disps[j], scale); + } + } +} + +static void multires_apply_smat(struct Depsgraph *UNUSED(depsgraph), + Scene *scene, + Object *object, + float smat[3][3]) +{ + const MultiresModifierData *mmd = get_multires_modifier(scene, object, true); + if (mmd == NULL || mmd->totlvl == 0) { + return; + } + /* Make sure layer present. */ + Mesh *mesh = (Mesh *)object->data; + CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); + if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) { + return; + } + if (is_uniform_scaled_m3(smat)) { + const float scale = mat3_to_scale(smat); + multires_apply_uniform_scale(object, scale); + } + else { + /* TODO(sergey): This branch of code actually requires more work to + * preserve all the details. + */ + const float scale = mat3_to_scale(smat); + multires_apply_uniform_scale(object, scale); + } } int multires_mdisp_corners(MDisps *s) { - int lvl = 13; + int lvl = 13; - while (lvl > 0) { - int side = (1 << (lvl - 1)) + 1; - if ((s->totdisp % (side * side)) == 0) return s->totdisp / (side * side); - lvl--; - } + while (lvl > 0) { + int side = (1 << (lvl - 1)) + 1; + if ((s->totdisp % (side * side)) == 0) + return s->totdisp / (side * side); + lvl--; + } - return 0; + return 0; } void multiresModifier_scale_disp(struct Depsgraph *depsgraph, Scene *scene, Object *ob) { - float smat[3][3]; + float smat[3][3]; - /* object's scale matrix */ - BKE_object_scale_to_mat3(ob, smat); + /* object's scale matrix */ + BKE_object_scale_to_mat3(ob, smat); - multires_apply_smat(depsgraph, scene, ob, smat); + multires_apply_smat(depsgraph, scene, ob, smat); } -void multiresModifier_prepare_join(struct Depsgraph *depsgraph, Scene *scene, Object *ob, Object *to_ob) +void multiresModifier_prepare_join(struct Depsgraph *depsgraph, + Scene *scene, + Object *ob, + Object *to_ob) { - float smat[3][3], tmat[3][3], mat[3][3]; - multires_sync_levels(scene, to_ob, ob); + float smat[3][3], tmat[3][3], mat[3][3]; + multires_sync_levels(scene, to_ob, ob); - /* construct scale matrix for displacement */ - BKE_object_scale_to_mat3(to_ob, tmat); - invert_m3(tmat); - BKE_object_scale_to_mat3(ob, smat); - mul_m3_m3m3(mat, smat, tmat); + /* construct scale matrix for displacement */ + BKE_object_scale_to_mat3(to_ob, tmat); + invert_m3(tmat); + BKE_object_scale_to_mat3(ob, smat); + mul_m3_m3m3(mat, smat, tmat); - multires_apply_smat(depsgraph, scene, ob, mat); + multires_apply_smat(depsgraph, scene, ob, mat); } /* update multires data after topology changing */ void multires_topology_changed(Mesh *me) { - MDisps *mdisp = NULL, *cur = NULL; - int i, grid = 0; + MDisps *mdisp = NULL, *cur = NULL; + int i, grid = 0; - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS); + CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + mdisp = CustomData_get_layer(&me->ldata, CD_MDISPS); - if (!mdisp) - return; + if (!mdisp) + return; - cur = mdisp; - for (i = 0; i < me->totloop; i++, cur++) { - if (cur->totdisp) { - grid = mdisp->totdisp; + cur = mdisp; + for (i = 0; i < me->totloop; i++, cur++) { + if (cur->totdisp) { + grid = mdisp->totdisp; - break; - } - } + break; + } + } - for (i = 0; i < me->totloop; i++, mdisp++) { - /* allocate memory for mdisp, the whole disp layer would be erased otherwise */ - if (!mdisp->totdisp || !mdisp->disps) { - if (grid) { - mdisp->totdisp = grid; - mdisp->disps = MEM_calloc_arrayN(3 * sizeof(float), mdisp->totdisp, "mdisp topology"); - } + for (i = 0; i < me->totloop; i++, mdisp++) { + /* allocate memory for mdisp, the whole disp layer would be erased otherwise */ + if (!mdisp->totdisp || !mdisp->disps) { + if (grid) { + mdisp->totdisp = grid; + mdisp->disps = MEM_calloc_arrayN(3 * sizeof(float), mdisp->totdisp, "mdisp topology"); + } - continue; - } - } + continue; + } + } } /***************** Multires interpolation stuff *****************/ /* Find per-corner coordinate with given per-face UV coord */ -int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert), struct MPoly *mpoly, struct MLoop *UNUSED(mloop), const struct MLoopTri *UNUSED(lt), const int face_side, const float u, const float v, float *x, float *y) -{ - const float offset = face_side * 0.5f - 0.5f; - int S = 0; - - if (mpoly->totloop == 4) { - if (u <= offset && v <= offset) S = 0; - else if (u > offset && v <= offset) S = 1; - else if (u > offset && v > offset) S = 2; - else if (u <= offset && v >= offset) S = 3; - - if (S == 0) { - *y = offset - u; - *x = offset - v; - } - else if (S == 1) { - *x = u - offset; - *y = offset - v; - } - else if (S == 2) { - *y = u - offset; - *x = v - offset; - } - else if (S == 3) { - *x = offset - u; - *y = v - offset; - } - } - else if (mpoly->totloop == 3) { - int grid_size = offset; - float w = (face_side - 1) - u - v; - float W1, W2; - - if (u >= v && u >= w) {S = 0; W1 = w; W2 = v; } - else if (v >= u && v >= w) {S = 1; W1 = u; W2 = w; } - else {S = 2; W1 = v; W2 = u; } - - W1 /= (face_side - 1); - W2 /= (face_side - 1); - - *x = (1 - (2 * W1) / (1 - W2)) * grid_size; - *y = (1 - (2 * W2) / (1 - W1)) * grid_size; - } - else { - /* the complicated ngon case: find the actual coordinate from - * the barycentric coordinates and finally find the closest vertex - * should work reliably for convex cases only but better than nothing */ +int mdisp_rot_face_to_crn(struct MVert *UNUSED(mvert), + struct MPoly *mpoly, + struct MLoop *UNUSED(mloop), + const struct MLoopTri *UNUSED(lt), + const int face_side, + const float u, + const float v, + float *x, + float *y) +{ + const float offset = face_side * 0.5f - 0.5f; + int S = 0; + + if (mpoly->totloop == 4) { + if (u <= offset && v <= offset) + S = 0; + else if (u > offset && v <= offset) + S = 1; + else if (u > offset && v > offset) + S = 2; + else if (u <= offset && v >= offset) + S = 3; + + if (S == 0) { + *y = offset - u; + *x = offset - v; + } + else if (S == 1) { + *x = u - offset; + *y = offset - v; + } + else if (S == 2) { + *y = u - offset; + *x = v - offset; + } + else if (S == 3) { + *x = offset - u; + *y = v - offset; + } + } + else if (mpoly->totloop == 3) { + int grid_size = offset; + float w = (face_side - 1) - u - v; + float W1, W2; + + if (u >= v && u >= w) { + S = 0; + W1 = w; + W2 = v; + } + else if (v >= u && v >= w) { + S = 1; + W1 = u; + W2 = w; + } + else { + S = 2; + W1 = v; + W2 = u; + } + + W1 /= (face_side - 1); + W2 /= (face_side - 1); + + *x = (1 - (2 * W1) / (1 - W2)) * grid_size; + *y = (1 - (2 * W2) / (1 - W1)) * grid_size; + } + else { + /* the complicated ngon case: find the actual coordinate from + * the barycentric coordinates and finally find the closest vertex + * should work reliably for convex cases only but better than nothing */ #if 0 - int minS, i; - float mindist = FLT_MAX; - - for (i = 0; i < mpoly->totloop; i++) { - float len = len_v3v3(NULL, mvert[mloop[mpoly->loopstart + i].v].co); - if (len < mindist) { - mindist = len; - minS = i; - } - } - S = minS; + int minS, i; + float mindist = FLT_MAX; + + for (i = 0; i < mpoly->totloop; i++) { + float len = len_v3v3(NULL, mvert[mloop[mpoly->loopstart + i].v].co); + if (len < mindist) { + mindist = len; + minS = i; + } + } + S = minS; #endif - /* temp not implemented yet and also not working properly in current master. - * (was worked around by subdividing once) */ - S = 0; - *x = 0; - *y = 0; - } - - return S; + /* temp not implemented yet and also not working properly in current master. + * (was worked around by subdividing once) */ + S = 0; + *x = 0; + *y = 0; + } + + return S; } |