diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 122029c3785..f4fbe983d2d 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -109,7 +109,10 @@ static void mesh_copy_data(Main *bmain, mesh_dst->runtime = new blender::bke::MeshRuntime(); mesh_dst->runtime->deformed_only = mesh_src->runtime->deformed_only; - mesh_dst->runtime->wrapper_type = mesh_src->runtime->wrapper_type; + /* Subd runtime.mesh_eval is not copied, will need to be reevaluated. */ + mesh_dst->runtime->wrapper_type = (mesh_src->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) ? + ME_WRAPPER_TYPE_MDATA : + mesh_src->runtime->wrapper_type; mesh_dst->runtime->subsurf_runtime_data = mesh_src->runtime->subsurf_runtime_data; mesh_dst->runtime->cd_mask_extra = mesh_src->runtime->cd_mask_extra; /* Copy face dot tags and edge tags, since meshes may be duplicated after a subsurf modifier or diff --git a/source/blender/blenkernel/intern/mesh_wrapper.cc b/source/blender/blenkernel/intern/mesh_wrapper.cc index 8d0696d6278..e2b63564a76 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.cc +++ b/source/blender/blenkernel/intern/mesh_wrapper.cc @@ -78,6 +78,10 @@ Mesh *BKE_mesh_wrapper_from_editmesh(std::shared_ptr em, void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh) { + if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) { + return; + } + std::lock_guard lock{mesh->runtime->eval_mutex}; if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_MDATA) { return; @@ -85,42 +89,38 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *mesh) /* Must isolate multithreaded tasks while holding a mutex lock. */ blender::threading::isolate_task([&]() { - switch (mesh->runtime->wrapper_type) { - case ME_WRAPPER_TYPE_MDATA: - case ME_WRAPPER_TYPE_SUBD: { - break; /* Quiet warning. */ + if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_BMESH) { + mesh->verts_num = 0; + mesh->edges_num = 0; + mesh->faces_num = 0; + mesh->corners_num = 0; + + BLI_assert(mesh->runtime->edit_mesh != nullptr); + BLI_assert(mesh->runtime->edit_data != nullptr); + + BMEditMesh *em = mesh->runtime->edit_mesh.get(); + BM_mesh_bm_to_me_for_eval(*em->bm, *mesh, &mesh->runtime->cd_mask_extra); + + /* Adding original index layers here assumes that all BMesh Mesh wrappers are created from + * original edit mode meshes (the only case where adding original indices makes sense). + * If that assumption is broken, the layers might be incorrect because they might not + * actually be "original". + * + * There is also a performance aspect, where this also assumes that original indices are + * always needed when converting a BMesh to a mesh with the mesh wrapper system. That might + * be wrong, but it's not harmful. */ + BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh); + + blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data; + if (!edit_data.vert_positions.is_empty()) { + mesh->vert_positions_for_write().copy_from(edit_data.vert_positions); + mesh->runtime->is_original_bmesh = false; } - case ME_WRAPPER_TYPE_BMESH: { - mesh->verts_num = 0; - mesh->edges_num = 0; - mesh->faces_num = 0; - mesh->corners_num = 0; - BLI_assert(mesh->runtime->edit_mesh != nullptr); - BLI_assert(mesh->runtime->edit_data != nullptr); - - BMEditMesh *em = mesh->runtime->edit_mesh.get(); - BM_mesh_bm_to_me_for_eval(*em->bm, *mesh, &mesh->runtime->cd_mask_extra); - - /* Adding original index layers here assumes that all BMesh Mesh wrappers are created from - * original edit mode meshes (the only case where adding original indices makes sense). - * If that assumption is broken, the layers might be incorrect because they might not - * actually be "original". - * - * There is also a performance aspect, where this also assumes that original indices are - * always needed when converting a BMesh to a mesh with the mesh wrapper system. That might - * be wrong, but it's not harmful. */ - BKE_mesh_ensure_default_orig_index_customdata_no_check(mesh); - - blender::bke::EditMeshData &edit_data = *mesh->runtime->edit_data; - if (!edit_data.vert_positions.is_empty()) { - mesh->vert_positions_for_write().copy_from(edit_data.vert_positions); - mesh->runtime->is_original_bmesh = false; - } - - mesh->runtime->edit_data.reset(); - break; - } + mesh->runtime->edit_data.reset(); + } + else if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) { + BLI_assert(!"Should not be converting subd wrapper to mdata wrapper"); } /* Keep type assignment last, so that read-only access only uses the mdata code paths after all @@ -311,7 +311,8 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh) { using namespace blender::bke; SubsurfRuntimeData *runtime_data = mesh->runtime->subsurf_runtime_data; - if (runtime_data == nullptr || runtime_data->settings.level == 0) { + if (runtime_data->settings.level == 0) { + mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD; return mesh; } @@ -323,6 +324,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh) mesh_settings.use_optimal_display = runtime_data->use_optimal_display; if (mesh_settings.resolution < 3) { + mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD; return mesh; } @@ -330,6 +332,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh) runtime_data, mesh, false); if (subdiv == nullptr) { /* Happens on bad topology, but also on empty input mesh. */ + mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD; return mesh; } const bool use_clnors = runtime_data->use_loop_normals; @@ -362,6 +365,7 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh) } mesh->runtime->mesh_eval = subdiv_mesh; mesh->runtime->wrapper_type = ME_WRAPPER_TYPE_SUBD; + BLI_assert(mesh->runtime->mesh_eval != nullptr); } return mesh->runtime->mesh_eval; @@ -369,17 +373,19 @@ static Mesh *mesh_wrapper_ensure_subdivision(Mesh *mesh) Mesh *BKE_mesh_wrapper_ensure_subdivision(Mesh *mesh) { - std::lock_guard lock{mesh->runtime->eval_mutex}; - if (mesh->runtime->wrapper_type == ME_WRAPPER_TYPE_SUBD) { - return mesh->runtime->mesh_eval; + /* Subdiv evaluation might have been skipped, in which case the original mesh is ok. */ + return (mesh->runtime->mesh_eval) ? mesh->runtime->mesh_eval : mesh; + } + if (mesh->runtime->subsurf_runtime_data == nullptr) { + return mesh; } - Mesh *result; + std::lock_guard lock{mesh->runtime->eval_mutex}; /* Must isolate multithreaded tasks while holding a mutex lock. */ + Mesh *result; blender::threading::isolate_task([&]() { result = mesh_wrapper_ensure_subdivision(mesh); }); - return result; }