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/BKE_multires.h | 4 ++ source/blender/blenkernel/intern/mesh_evaluate.c | 1 + source/blender/blenkernel/intern/multires.c | 48 +++++++++++++++++++--- .../blender/blenkernel/intern/multires_reshape.c | 3 +- .../intern/subdiv_displacement_multires.c | 6 +-- 5 files changed, 52 insertions(+), 10 deletions(-) diff --git a/source/blender/blenkernel/BKE_multires.h b/source/blender/blenkernel/BKE_multires.h index 941675489c1..4ee255d4e61 100644 --- a/source/blender/blenkernel/BKE_multires.h +++ b/source/blender/blenkernel/BKE_multires.h @@ -130,6 +130,10 @@ int multires_mdisp_corners(struct MDisps *s); /* update multires data after topology changing */ void multires_topology_changed(struct Mesh *me); +void multires_ensure_external_read(struct Mesh *mesh, int top_level); +void multiresModifier_ensure_external_read(struct Mesh *mesh, + const struct MultiresModifierData *mmd); + /**** interpolation stuff ****/ void old_mdisps_bilinear(float out[3], float (*disps)[3], const int st, float u, float v); int mdisp_rot_face_to_crn(struct MVert *mvert, diff --git a/source/blender/blenkernel/intern/mesh_evaluate.c b/source/blender/blenkernel/intern/mesh_evaluate.c index 7b655b2d8fc..e14803e4193 100644 --- a/source/blender/blenkernel/intern/mesh_evaluate.c +++ b/source/blender/blenkernel/intern/mesh_evaluate.c @@ -3576,6 +3576,7 @@ void BKE_mesh_convert_mfaces_to_mpolys_ex(ID *id, if (id) { /* ensure external data is transferred */ + /* TODO(sergey): Use multiresModifier_ensure_external_read(). */ CustomData_external_read(fdata, id, CD_MASK_MDISPS, totface_i); } 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 */ diff --git a/source/blender/blenkernel/intern/multires_reshape.c b/source/blender/blenkernel/intern/multires_reshape.c index eef35aead28..a29398b24a0 100644 --- a/source/blender/blenkernel/intern/multires_reshape.c +++ b/source/blender/blenkernel/intern/multires_reshape.c @@ -149,8 +149,7 @@ bool multiresModifier_reshapeFromCCG(const int tot_level, return false; } - CustomData_external_read( - &coarse_mesh->ldata, &coarse_mesh->id, CD_MASK_MDISPS, coarse_mesh->totloop); + multires_ensure_external_read(coarse_mesh, reshape_context.top.level); multires_reshape_store_original_grids(&reshape_context); multires_reshape_ensure_grids(coarse_mesh, reshape_context.top.level); diff --git a/source/blender/blenkernel/intern/subdiv_displacement_multires.c b/source/blender/blenkernel/intern/subdiv_displacement_multires.c index 1f78cf4eb3b..50b2b3c7c46 100644 --- a/source/blender/blenkernel/intern/subdiv_displacement_multires.c +++ b/source/blender/blenkernel/intern/subdiv_displacement_multires.c @@ -47,6 +47,7 @@ typedef struct MultiresDisplacementData { int grid_size; /* Mesh is used to read external displacement. */ Mesh *mesh; + const MultiresModifierData *mmd; const MPoly *mpoly; const MDisps *mdisps; /* Indexed by ptex face index, contains polygon/corner which corresponds @@ -328,9 +329,7 @@ static int displacement_get_face_corner(MultiresDisplacementData *data, static void initialize(SubdivDisplacement *displacement) { MultiresDisplacementData *data = displacement->user_data; - Mesh *mesh = data->mesh; - /* Make sure external displacement is read. */ - CustomData_external_read(&mesh->ldata, &mesh->id, CD_MASK_MDISPS, mesh->totloop); + multiresModifier_ensure_external_read(data->mesh, data->mmd); data->is_initialized = true; } @@ -421,6 +420,7 @@ static void displacement_init_data(SubdivDisplacement *displacement, data->subdiv = subdiv; data->grid_size = BKE_subdiv_grid_size_from_level(mmd->totlvl); data->mesh = mesh; + data->mmd = mmd; data->mpoly = mesh->mpoly; data->mdisps = CustomData_get_layer(&mesh->ldata, CD_MDISPS); data->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); -- cgit v1.2.3