From af6ba4dce51136759d27d67a826eafdb421c2c74 Mon Sep 17 00:00:00 2001 From: Pablo Dobarro Date: Mon, 10 Feb 2020 18:41:03 +0100 Subject: Fix T73706: Crash after disabling dyntopo with multires modifier ss->multires is set in sculpt_update_object, which is not called just after disabling dyntopo, so it needs to be checked before running reshapeFromCCG Reviewed By: campbellbarton, brecht Maniphest Tasks: T73706 Differential Revision: https://developer.blender.org/D6801 --- source/blender/blenkernel/intern/multires.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 23fa8dd60d5..96608a931ab 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -410,7 +410,7 @@ void multires_flush_sculpt_updates(Object *ob) { if (ob && ob->sculpt && ob->sculpt->pbvh != NULL) { SculptSession *sculpt_session = ob->sculpt; - if (BKE_pbvh_type(sculpt_session->pbvh) == PBVH_GRIDS) { + if (BKE_pbvh_type(sculpt_session->pbvh) == PBVH_GRIDS && sculpt_session->multires) { Mesh *mesh = ob->data; multiresModifier_reshapeFromCCG( sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); -- cgit v1.2.3 From feead324fd70289d7dbcbe2b797cc960d6be99ca Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 28 Feb 2020 12:05:48 +0100 Subject: Multires: Cleanup, naming --- source/blender/blenkernel/intern/multires.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 96608a931ab..35de0d19d95 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -406,27 +406,27 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod multires_ccg_mark_as_modified(subdiv_ccg, flags); } -void multires_flush_sculpt_updates(Object *ob) +void multires_flush_sculpt_updates(Object *object) { - if (ob && ob->sculpt && ob->sculpt->pbvh != NULL) { - SculptSession *sculpt_session = ob->sculpt; + if (object && object->sculpt && object->sculpt->pbvh != NULL) { + SculptSession *sculpt_session = object->sculpt; if (BKE_pbvh_type(sculpt_session->pbvh) == PBVH_GRIDS && sculpt_session->multires) { - Mesh *mesh = ob->data; + Mesh *mesh = object->data; multiresModifier_reshapeFromCCG( sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); } } } -void multires_force_sculpt_rebuild(Object *ob) +void multires_force_sculpt_rebuild(Object *object) { - multires_flush_sculpt_updates(ob); + multires_flush_sculpt_updates(object); - if (ob && ob->sculpt) { - SculptSession *ss = ob->sculpt; + if (object && object->sculpt) { + SculptSession *ss = object->sculpt; if (ss->pbvh) { BKE_pbvh_free(ss->pbvh); - ob->sculpt->pbvh = NULL; + object->sculpt->pbvh = NULL; } if (ss->pmap) { @@ -441,12 +441,12 @@ void multires_force_sculpt_rebuild(Object *ob) } } -void multires_force_external_reload(Object *ob) +void multires_force_external_reload(Object *object) { - Mesh *me = BKE_mesh_from_object(ob); + Mesh *mesh = BKE_mesh_from_object(object); - CustomData_external_reload(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); - multires_force_sculpt_rebuild(ob); + CustomData_external_reload(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); + multires_force_sculpt_rebuild(object); } /* reset the multires levels to match the number of mdisps */ -- cgit v1.2.3 From 944da82eafeb88ecfebfa5c302aaea97150c49eb Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 28 Feb 2020 12:08:15 +0100 Subject: Multires: Cleanup, use early return --- source/blender/blenkernel/intern/multires.c | 49 ++++++++++++++++------------- 1 file changed, 28 insertions(+), 21 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 35de0d19d95..ad33fd9b2e0 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -408,36 +408,43 @@ void multires_mark_as_modified(Depsgraph *depsgraph, Object *object, MultiresMod void multires_flush_sculpt_updates(Object *object) { - if (object && object->sculpt && object->sculpt->pbvh != NULL) { - SculptSession *sculpt_session = object->sculpt; - if (BKE_pbvh_type(sculpt_session->pbvh) == PBVH_GRIDS && sculpt_session->multires) { - Mesh *mesh = object->data; - multiresModifier_reshapeFromCCG( - sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); - } + if (object == NULL || object->sculpt == NULL || object->sculpt->pbvh == NULL) { + return; + } + + SculptSession *sculpt_session = object->sculpt; + if (BKE_pbvh_type(sculpt_session->pbvh) != PBVH_GRIDS || sculpt_session->multires == NULL) { + return; } + + Mesh *mesh = object->data; + multiresModifier_reshapeFromCCG( + sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); } void multires_force_sculpt_rebuild(Object *object) { multires_flush_sculpt_updates(object); - if (object && object->sculpt) { - SculptSession *ss = object->sculpt; - if (ss->pbvh) { - BKE_pbvh_free(ss->pbvh); - object->sculpt->pbvh = NULL; - } + if (object == NULL || object->sculpt == NULL) { + return; + } - if (ss->pmap) { - MEM_freeN(ss->pmap); - ss->pmap = NULL; - } + SculptSession *ss = object->sculpt; - if (ss->pmap_mem) { - MEM_freeN(ss->pmap_mem); - ss->pmap_mem = NULL; - } + if (ss->pbvh != NULL) { + BKE_pbvh_free(ss->pbvh); + object->sculpt->pbvh = NULL; + } + + if (ss->pmap != NULL) { + MEM_freeN(ss->pmap); + ss->pmap = NULL; + } + + if (ss->pmap_mem != NULL) { + MEM_freeN(ss->pmap_mem); + ss->pmap_mem = NULL; } } -- cgit v1.2.3 From 1eb73d1596485f5dc00cdc2e5cf8ff9b8a17f503 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 28 Feb 2020 12:21:42 +0100 Subject: Multires: Fix CCG->MDISPS conversion happens twice Was happening when leaving sculpt mode, introducing unnecessary lag to the operation. --- source/blender/blenkernel/intern/multires.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index ad33fd9b2e0..3447d37f1ab 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -417,9 +417,21 @@ void multires_flush_sculpt_updates(Object *object) return; } + SubdivCCG *subdiv_ccg = sculpt_session->subdiv_ccg; + if (subdiv_ccg == NULL) { + return; + } + + if (!subdiv_ccg->dirty.coords && !subdiv_ccg->dirty.hidden) { + return; + } + Mesh *mesh = object->data; multiresModifier_reshapeFromCCG( sculpt_session->multires->totlvl, mesh, sculpt_session->subdiv_ccg); + + subdiv_ccg->dirty.coords = false; + subdiv_ccg->dirty.hidden = false; } void multires_force_sculpt_rebuild(Object *object) -- cgit v1.2.3 From 598ab525da3df3fef2033c159c570688c7282a8f Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 6 Mar 2020 17:18:10 +0100 Subject: Cleanup: Replace ABS/SQUARE/CUBE with function calls While it might be handy to have type-less functionality which is similar to how C++ math is implemented it can not be easily achieved with just preprocessor in a way which does not have side-effects on wrong usage. There macros where often used on a non-trivial expression, and there was at least one usage where it was causing an actual side effect/bug on Windows (see change around square_f(sh[index++]) in studiolight.c). For such cases it is handy to have a function which is guaranteed to have zero side-effects. The motivation behind actually removing the macros is that there is already a way to do similar calculation. Also, not having such macros is a way to guarantee that its usage is not changed in a way which have side-effects and that it's not used as an inspiration for cases where it should not be used. Differential Revision: https://developer.blender.org/D7051 --- source/blender/blenkernel/intern/multires.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 3447d37f1ab..f3d65f584d1 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -121,7 +121,7 @@ static BLI_bitmap *multires_mdisps_upsample_hidden(BLI_bitmap *lo_hidden, return MEM_dupallocN(lo_hidden); } - subd = BLI_BITMAP_NEW(SQUARE(hi_gridsize), "MDisps.hidden upsample"); + subd = BLI_BITMAP_NEW(square_i(hi_gridsize), "MDisps.hidden upsample"); factor = BKE_ccg_factor(lo_level, hi_level); offset = 1 << (hi_level - lo_level - 1); @@ -179,7 +179,7 @@ static BLI_bitmap *multires_mdisps_downsample_hidden(BLI_bitmap *old_hidden, BLI_assert(new_level <= old_level); factor = BKE_ccg_factor(new_level, old_level); - new_hidden = BLI_BITMAP_NEW(SQUARE(new_gridsize), "downsample hidden"); + new_hidden = BLI_BITMAP_NEW(square_i(new_gridsize), "downsample hidden"); for (y = 0; y < new_gridsize; y++) { for (x = 0; x < new_gridsize; x++) { @@ -238,7 +238,7 @@ 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 gridarea = square_i(gridsize); int i, j; for (i = 0; i < me->totpoly; i++) { @@ -622,7 +622,7 @@ 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"); + square_i(gridsize), sizeof(float), "multires_grid_paint_mask_downsample"); int x, y; for (y = 0; y < gridsize; y++) { -- cgit v1.2.3 From bc0a0cdf171037cba4076c796e9adb2769382561 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 3 Mar 2020 12:35:51 +0100 Subject: Multires: Fix Subdivide, Reshape and Apply Base This change fixes artifacts produced by these operations. On a technical aspect this is done by porting all of the operations to the new subdivision surface implementation which ensures that tangent space used to evaluate modifier and those operations is exactly the same (before modifier will use new code and the operations will still use an old one). The next step is to get sculpting on a non-top level to work, and that actually requires fixes in the undo system. --- source/blender/blenkernel/intern/multires.c | 171 ++-------------------------- 1 file changed, 11 insertions(+), 160 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index f3d65f584d1..70061c155d3 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -57,6 +57,8 @@ #include "DEG_depsgraph_query.h" +#include "multires_reshape.h" + #include #include @@ -789,158 +791,7 @@ static DerivedMesh *subsurf_dm_create_local(Scene *scene, 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); -} - -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_sculpt_rebuild(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( +static void multires_subdivide_legacy( MultiresModifierData *mmd, Scene *scene, Object *ob, int totlvl, int updateblock, int simple) { Mesh *me = ob->data; @@ -1038,10 +889,10 @@ static void multires_subdivide( multires_set_tot_level(ob, mmd, totlvl); } -void multiresModifier_subdivide( +void multiresModifier_subdivide_legacy( MultiresModifierData *mmd, Scene *scene, Object *ob, int updateblock, int simple) { - multires_subdivide(mmd, scene, ob, mmd->totlvl + 1, updateblock, simple); + multires_subdivide_legacy(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]) @@ -2277,7 +2128,8 @@ void multires_load_old(Object *ob, Mesh *me) multires_load_old_vcols(me); multires_load_old_face_flags(me); - /* multiresModifier_subdivide (actually, multires_subdivide) expects polys, not tessfaces! */ + /* multiresModifier_subdivide_legacy (actually, multires_subdivide_legacy) expects polys, not + * tessfaces! */ BKE_mesh_convert_mfaces_to_mpolys(me); /* Add a multires modifier to the object */ @@ -2289,7 +2141,7 @@ void multires_load_old(Object *ob, Mesh *me) BLI_insertlinkbefore(&ob->modifiers, md, mmd); for (i = 0; i < me->mr->level_count - 1; i++) { - multiresModifier_subdivide(mmd, NULL, ob, 1, 0); + multiresModifier_subdivide_legacy(mmd, NULL, ob, 1, 0); } mmd->lvl = mmd->totlvl; @@ -2314,8 +2166,7 @@ void multires_load_old(Object *ob, Mesh *me) /* 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, +void multiresModifier_sync_levels_ex(Object *ob_dst, MultiresModifierData *mmd_src, MultiresModifierData *mmd_dst) { @@ -2324,7 +2175,7 @@ void multiresModifier_sync_levels_ex(Scene *scene, } if (mmd_src->totlvl > mmd_dst->totlvl) { - multires_subdivide(mmd_dst, scene, ob_dst, mmd_src->totlvl, false, mmd_dst->simple); + multiresModifier_subdivide_to_level(ob_dst, mmd_dst, mmd_src->totlvl); } else { multires_del_higher(mmd_dst, ob_dst, mmd_src->totlvl); @@ -2346,7 +2197,7 @@ static void multires_sync_levels(Scene *scene, Object *ob_src, Object *ob_dst) } if (mmd_src && mmd_dst) { - multiresModifier_sync_levels_ex(scene, ob_dst, mmd_src, mmd_dst); + multiresModifier_sync_levels_ex(ob_dst, mmd_src, mmd_dst); } } -- cgit v1.2.3 From de30fda04e8d84a173e929a0f3d9d8c71bcc4bbf Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 13 Mar 2020 16:13:32 +0100 Subject: Fix T74686: Loading btx file in multires modifier is not working Was happening when object does not have CD_MDISPS allocated yet. Need to make sure totdisp and level is specified on CD_MDISPS data prior to loading (as the load expects them to be properly set). --- source/blender/blenkernel/intern/multires.c | 48 ++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 5 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 70061c155d3..4e97d0fc05c 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -647,7 +647,7 @@ static void multires_del_higher(MultiresModifierData *mmd, Object *ob, int lvl) GridPaintMask *gpm; multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + multiresModifier_ensure_external_read(me, mmd); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); gpm = CustomData_get_layer(&me->ldata, CD_GRID_PAINT_MASK); @@ -713,7 +713,7 @@ void multiresModifier_del_levels(MultiresModifierData *mmd, MDisps *mdisps; multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + multiresModifier_ensure_external_read(me, mmd); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); multires_force_sculpt_rebuild(ob); @@ -1144,7 +1144,7 @@ void multires_modifier_update_mdisps(struct DerivedMesh *dm, Scene *scene) 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); + multiresModifier_ensure_external_read(me, mmd); mdisps = CustomData_get_layer(&me->ldata, CD_MDISPS); if (mdisps) { @@ -1372,7 +1372,7 @@ DerivedMesh *multires_make_derived_from_derived( } multires_set_tot_mdisps(me, mmd->totlvl); - CustomData_external_read(&me->ldata, &me->id, CD_MASK_MDISPS, me->totloop); + multiresModifier_ensure_external_read(me, mmd); /*run displacement*/ multiresModifier_disp_run(result, ob->data, dm, APPLY_DISPLACEMENTS, subGridData, mmd->totlvl); @@ -2224,7 +2224,7 @@ static void multires_apply_smat(struct Depsgraph *UNUSED(depsgraph), } /* Make sure layer present. */ Mesh *mesh = (Mesh *)object->data; - CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); + multiresModifier_ensure_external_read(mesh, mmd); if (!CustomData_get_layer(&mesh->ldata, CD_MDISPS)) { return; } @@ -2318,6 +2318,44 @@ void multires_topology_changed(Mesh *me) } } +/* Makes sure data from an external file is fully read. + * + * Since the multires data files only contain displacement vectors without knowledge about + * subdivision level some extra work is needed. Namely make is to all displacement grids have + * proper level and number of displacement vectors set. */ +void multires_ensure_external_read(struct Mesh *mesh, int top_level) +{ + if (!CustomData_external_test(&mesh->ldata, CD_MDISPS)) { + return; + } + + MDisps *mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); + if (mdisps == NULL) { + mdisps = CustomData_add_layer(&mesh->ldata, CD_MDISPS, CD_DEFAULT, NULL, mesh->totloop); + } + + const int totloop = mesh->totloop; + + for (int i = 0; i < totloop; ++i) { + if (mdisps[i].level != top_level) { + MEM_SAFE_FREE(mdisps[i].disps); + } + + /* NOTE: CustomData_external_read will take care of allocation of displacement vectors if + * they are missing. */ + + const int totdisp = multires_grid_tot[top_level]; + mdisps[i].totdisp = totdisp; + mdisps[i].level = top_level; + } + + CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); +} +void multiresModifier_ensure_external_read(struct Mesh *mesh, const MultiresModifierData *mmd) +{ + multires_ensure_external_read(mesh, mmd->totlvl); +} + /***************** Multires interpolation stuff *****************/ /* Find per-corner coordinate with given per-face UV coord */ -- cgit v1.2.3 From 17abae45f131a8e97871c0738ec1bac8f836679c Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Mar 2020 14:18:27 +0100 Subject: Multires: Cleanup, remove redundant argument Scene can be queried from the dependency graph. --- source/blender/blenkernel/intern/multires.c | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 4e97d0fc05c..290bed02913 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -270,13 +270,11 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level) return mdisps; } -Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, - Scene *scene, - MultiresModifierData *mmd, - Object *ob) +Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, 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); + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); ModifierEvalContext modifier_ctx = { .depsgraph = depsgraph, .object = ob_eval, -- cgit v1.2.3 From a45c34ae8eb73448726a92d0b4d79b632dc69d9e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Mar 2020 14:20:14 +0100 Subject: Multires: Cleanup, argument naming and order Use full argument name. Also order arguments in the generosity order: from depsgraph (which has everything) to object (which contains multires) specific multires modifier. --- source/blender/blenkernel/intern/multires.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 290bed02913..b8464bf02c0 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -270,14 +270,17 @@ static MDisps *multires_mdisps_initialize_hidden(Mesh *me, int level) return mdisps; } -Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, MultiresModifierData *mmd, Object *ob) +Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, + Object *object, + MultiresModifierData *mmd) { - Object *ob_eval = DEG_get_evaluated_object(depsgraph, ob); + Object *object_eval = DEG_get_evaluated_object(depsgraph, object); Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - Mesh *deformed_mesh = mesh_get_eval_deform(depsgraph, scene_eval, ob_eval, &CD_MASK_BAREMESH); + Mesh *deformed_mesh = mesh_get_eval_deform( + depsgraph, scene_eval, object_eval, &CD_MASK_BAREMESH); ModifierEvalContext modifier_ctx = { .depsgraph = depsgraph, - .object = ob_eval, + .object = object_eval, .flag = MOD_APPLY_USECACHE | MOD_APPLY_IGNORE_SIMPLIFY, }; -- cgit v1.2.3 From 628d799c85965191d5f6231b3433bbae425e59f0 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Mar 2020 15:55:59 +0100 Subject: Multires: Add utility to create deformed base mesh The new function will use original object as a starting point and apply all enabled deformation modifiers prior to the multires. --- source/blender/blenkernel/intern/multires.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index b8464bf02c0..fd91f80b047 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -293,6 +293,25 @@ Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, return result; } +Mesh *BKE_multires_create_deformed_base_mesh(struct Depsgraph *depsgraph, + Object *object, + MultiresModifierData *mmd) +{ + Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); + Object *object_eval = DEG_get_evaluated_object(depsgraph, object); + + const int mmd_index = BLI_findindex(&object->modifiers, &mmd->modifier); + BLI_assert(mmd_index != -1); + + Object object_for_eval = *object_eval; + object_for_eval.data = object->data; + + Mesh *base_mesh = mesh_create_eval_final_view_index( + depsgraph, scene_eval, object, &CD_MASK_BAREMESH, mmd_index - 1); + + return base_mesh; +} + MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd) { ModifierData *md; -- cgit v1.2.3 From f958560a990a8974446c2c63def7ba387dcfb275 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 17 Mar 2020 17:34:04 +0100 Subject: Multires: Properly support virtual modifiers for Apply Base The initial code from earlier from today didn't really work reliable since it is not possible to apply virtual modifiers but not the real multires one (in a situation like mesh with shapekeys and multires). New code uses less memory and has better performance for the case when there are actual modifiers leading the multires. The case when there is only multires will not be as performant as possible at this moment. --- source/blender/blenkernel/intern/multires.c | 50 +++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 9 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index fd91f80b047..234273b5158 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -293,23 +293,55 @@ Mesh *BKE_multires_create_mesh(struct Depsgraph *depsgraph, return result; } -Mesh *BKE_multires_create_deformed_base_mesh(struct Depsgraph *depsgraph, - Object *object, - MultiresModifierData *mmd) +float (*BKE_multires_create_deformed_base_mesh_vert_coords(struct Depsgraph *depsgraph, + struct Object *object, + struct MultiresModifierData *mmd, + int *r_num_deformed_verts))[3] { Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Object *object_eval = DEG_get_evaluated_object(depsgraph, object); - const int mmd_index = BLI_findindex(&object->modifiers, &mmd->modifier); - BLI_assert(mmd_index != -1); - Object object_for_eval = *object_eval; object_for_eval.data = object->data; - Mesh *base_mesh = mesh_create_eval_final_view_index( - depsgraph, scene_eval, object, &CD_MASK_BAREMESH, mmd_index - 1); + const bool use_render = (DEG_get_mode(depsgraph) == DAG_EVAL_RENDER); + ModifierEvalContext mesh_eval_context = {depsgraph, &object_for_eval, 0}; + if (use_render) { + mesh_eval_context.flag |= MOD_APPLY_RENDER; + } + const int required_mode = use_render ? eModifierMode_Render : eModifierMode_Realtime; + + VirtualModifierData virtual_modifier_data; + ModifierData *first_md = modifiers_getVirtualModifierList(&object_for_eval, + &virtual_modifier_data); + + Mesh *base_mesh = object->data; + + int num_deformed_verts; + float(*deformed_verts)[3] = BKE_mesh_vert_coords_alloc(base_mesh, &num_deformed_verts); + + for (ModifierData *md = first_md; md != NULL; md = md->next) { + const ModifierTypeInfo *mti = modifierType_getInfo(md->type); + + if (md == &mmd->modifier) { + break; + } + + if (!modifier_isEnabled(scene_eval, md, required_mode)) { + continue; + } - return base_mesh; + if (mti->type != eModifierTypeType_OnlyDeform) { + break; + } + + modwrap_deformVerts(md, &mesh_eval_context, base_mesh, deformed_verts, num_deformed_verts); + } + + if (r_num_deformed_verts != NULL) { + *r_num_deformed_verts = num_deformed_verts; + } + return deformed_verts; } MultiresModifierData *find_multires_modifier_before(Scene *scene, ModifierData *lastmd) -- cgit v1.2.3 From 2d1cce8331f3ecdfb8cb0c651e111ffac5dc7153 Mon Sep 17 00:00:00 2001 From: Dalai Felinto Date: Thu, 19 Mar 2020 09:33:03 +0100 Subject: Cleanup: `make format` after SortedIncludes change --- source/blender/blenkernel/intern/multires.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 234273b5158..f7a3489f02e 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -34,22 +34,22 @@ #include "BLI_bitmap.h" #include "BLI_blenlib.h" #include "BLI_math.h" -#include "BLI_utildefines.h" #include "BLI_task.h" +#include "BLI_utildefines.h" -#include "BKE_pbvh.h" #include "BKE_ccg.h" #include "BKE_cdderivedmesh.h" +#include "BKE_editmesh.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" #include "BKE_mesh_runtime.h" #include "BKE_modifier.h" #include "BKE_multires.h" #include "BKE_paint.h" +#include "BKE_pbvh.h" #include "BKE_scene.h" #include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" -#include "BKE_editmesh.h" #include "BKE_object.h" -- cgit v1.2.3 From 27553a2e4e03f6f7dfbb91bdeeffb108b9a05f1b Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Fri, 20 Mar 2020 12:23:14 +0100 Subject: Multires: Fix assert when removing modifier in edit mode It is not guaranteed that with Multires modifier existing there will be CD_MDISPS and CD_GRID_PAINT_MASK custom data layers. Fixes assert in the following scenario: - With default cube, go to edit mode - Add Multires modifier - Remove the Multires modifier --- source/blender/blenkernel/intern/multires.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'source/blender/blenkernel/intern/multires.c') diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index f7a3489f02e..b40dfcd3b7f 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -90,9 +90,14 @@ void multires_customdata_delete(Mesh *me) * 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); + if (CustomData_has_layer(&em->bm->ldata, CD_MDISPS)) { + BM_data_layer_free(em->bm, &em->bm->ldata, CD_MDISPS); + } + + if (CustomData_has_layer(&em->bm->ldata, CD_GRID_PAINT_MASK)) { + 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); -- cgit v1.2.3