diff --git a/source/blender/blenkernel/BKE_mesh.hh b/source/blender/blenkernel/BKE_mesh.hh index 728877a70c2..e2fa49146f2 100644 --- a/source/blender/blenkernel/BKE_mesh.hh +++ b/source/blender/blenkernel/BKE_mesh.hh @@ -146,7 +146,6 @@ short2 lnor_space_custom_normal_to_data(const CornerNormalSpace &lnor_space, * Useful to materialize sharp edges (or non-smooth faces) without actually modifying the geometry * (splitting edges). * - * \param loop_to_face_map: Optional pre-created map from corners to their face. * \param sharp_edges: Optional array of sharp edge tags, used to split the evaluated normals on * each side of the edge. * \param r_lnors_spacearr: Optional return data filled with information about the custom @@ -204,6 +203,7 @@ void edges_sharp_from_angle_set(OffsetIndices faces, Span corner_verts, Span corner_edges, Span face_normals, + Span loop_to_face, const bool *sharp_faces, const float split_angle, MutableSpan sharp_edges); diff --git a/source/blender/blenkernel/BKE_mesh_mapping.hh b/source/blender/blenkernel/BKE_mesh_mapping.hh index 83dcfe09586..5c7d0220378 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.hh +++ b/source/blender/blenkernel/BKE_mesh_mapping.hh @@ -280,12 +280,17 @@ GroupedSpan build_vert_to_edge_map(Span edges, Array &r_offsets, Array &r_indices); +void build_vert_to_face_indices(OffsetIndices faces, + Span corner_verts, + OffsetIndices offsets, + MutableSpan face_indices); GroupedSpan build_vert_to_face_map(OffsetIndices faces, Span corner_verts, int verts_num, Array &r_offsets, Array &r_indices); +Array build_vert_to_corner_indices(Span corner_verts, OffsetIndices offsets); GroupedSpan build_vert_to_loop_map(Span corner_verts, int verts_num, Array &r_offsets, diff --git a/source/blender/blenkernel/BKE_mesh_types.hh b/source/blender/blenkernel/BKE_mesh_types.hh index 5dd07c2e268..416a4500a67 100644 --- a/source/blender/blenkernel/BKE_mesh_types.hh +++ b/source/blender/blenkernel/BKE_mesh_types.hh @@ -140,6 +140,17 @@ struct MeshRuntime { SharedCache> vert_normals_cache; SharedCache> face_normals_cache; + /** + * Cache of offsets for vert to face/corner maps. The same offsets array is used to group + * indices for both the vertex to face and vertex to corner maps. + */ + SharedCache> vert_to_face_offset_cache; + /** Cache of indices for vert to face map. */ + SharedCache> vert_to_face_map_cache; + /** Cache of indices for vert to corner map. */ + SharedCache> vert_to_corner_map_cache; + /** Cache of face indices for each face corner. */ + SharedCache> corner_to_face_map_cache; /** Cache of data about edges not used by faces. See #Mesh::loose_edges(). */ SharedCache loose_edges_cache; /** Cache of data about vertices not used by edges. See #Mesh::loose_verts(). */ diff --git a/source/blender/blenkernel/BKE_paint.hh b/source/blender/blenkernel/BKE_paint.hh index b91a811fc37..228165afee2 100644 --- a/source/blender/blenkernel/BKE_paint.hh +++ b/source/blender/blenkernel/BKE_paint.hh @@ -267,12 +267,7 @@ void BKE_paint_blend_read_data(BlendDataReader *reader, const Scene *scene, Pain /** Used for both vertex color and weight paint. */ struct SculptVertexPaintGeomMap { - blender::Array vert_to_loop_offsets; - blender::Array vert_to_loop_indices; blender::GroupedSpan vert_to_loop; - - blender::Array vert_to_face_offsets; - blender::Array vert_to_face_indices; blender::GroupedSpan vert_to_face; }; @@ -591,9 +586,7 @@ struct SculptSession { float *vmask; /* Mesh connectivity maps. */ - /* Vertices to adjacent faces. */ - blender::Array vert_to_face_offsets; - blender::Array vert_to_face_indices; + /* Vertices to adjacent polys. */ blender::GroupedSpan pmap; /* Edges to adjacent faces. */ diff --git a/source/blender/blenkernel/intern/data_transfer.cc b/source/blender/blenkernel/intern/data_transfer.cc index ea74e99c56f..313b4851888 100644 --- a/source/blender/blenkernel/intern/data_transfer.cc +++ b/source/blender/blenkernel/intern/data_transfer.cc @@ -393,7 +393,7 @@ static void data_transfer_dtdata_type_preprocess(const Mesh *me_src, me_dst->faces(), me_dst->corner_verts(), me_dst->corner_edges(), - {}, + me_dst->corner_to_face_map(), me_dst->vert_normals(), me_dst->face_normals(), sharp_edges, diff --git a/source/blender/blenkernel/intern/key.cc b/source/blender/blenkernel/intern/key.cc index 2dcd8588c37..38b725f761d 100644 --- a/source/blender/blenkernel/intern/key.cc +++ b/source/blender/blenkernel/intern/key.cc @@ -2278,7 +2278,7 @@ void BKE_keyblock_mesh_calc_normals(const KeyBlock *kb, faces, corner_verts, corner_edges, - {}, + mesh->corner_to_face_map(), {reinterpret_cast(vert_normals), mesh->totvert}, {reinterpret_cast(face_normals), faces.size()}, sharp_edges, diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 17598efdefd..14f6bcb0212 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -139,6 +139,10 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int mesh_dst->runtime->loose_edges_cache = mesh_src->runtime->loose_edges_cache; mesh_dst->runtime->looptris_cache = mesh_src->runtime->looptris_cache; mesh_dst->runtime->looptri_faces_cache = mesh_src->runtime->looptri_faces_cache; + mesh_dst->runtime->vert_to_face_offset_cache = mesh_src->runtime->vert_to_face_offset_cache; + mesh_dst->runtime->vert_to_face_map_cache = mesh_src->runtime->vert_to_face_map_cache; + mesh_dst->runtime->vert_to_corner_map_cache = mesh_src->runtime->vert_to_corner_map_cache; + mesh_dst->runtime->corner_to_face_map_cache = mesh_src->runtime->corner_to_face_map_cache; /* Only do tessface if we have no faces. */ const bool do_tessface = ((mesh_src->totface_legacy != 0) && (mesh_src->faces_num == 0)); @@ -1778,7 +1782,7 @@ void BKE_mesh_calc_normals_split_ex(const Mesh *mesh, mesh->faces(), mesh->corner_verts(), mesh->corner_edges(), - {}, + mesh->corner_to_face_map(), mesh->vert_normals(), mesh->face_normals(), sharp_edges, diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc index b4cd12098de..e589fb0f58f 100644 --- a/source/blender/blenkernel/intern/mesh_fair.cc +++ b/source/blender/blenkernel/intern/mesh_fair.cc @@ -204,8 +204,7 @@ class MeshFairingContext : public FairingContext { faces = mesh->faces(); corner_verts_ = mesh->corner_verts(); corner_edges_ = mesh->corner_edges(); - vlmap_ = blender::bke::mesh::build_vert_to_loop_map( - corner_verts_, positions.size(), vert_to_face_offsets_, vert_to_face_indices_); + vlmap_ = mesh->vert_to_corner_map(); /* Deformation coords. */ co_.reserve(mesh->totvert); @@ -220,7 +219,7 @@ class MeshFairingContext : public FairingContext { } } - loop_to_face_map_ = blender::bke::mesh::build_loop_to_face_map(faces); + loop_to_face_map_ = mesh->corner_to_face_map(); } void adjacents_coords_from_loop(const int loop, @@ -247,9 +246,7 @@ class MeshFairingContext : public FairingContext { Span corner_edges_; blender::OffsetIndices faces; Span edges_; - Array loop_to_face_map_; - Array vert_to_face_offsets_; - Array vert_to_face_indices_; + Span loop_to_face_map_; }; class BMeshFairingContext : public FairingContext { diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc index 1b3220fe497..60a8f67399a 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.cc +++ b/source/blender/blenkernel/intern/mesh_mapping.cc @@ -379,6 +379,20 @@ GroupedSpan build_vert_to_edge_map(const Span edges, return {OffsetIndices(r_offsets), r_indices}; } +void build_vert_to_face_indices(const OffsetIndices faces, + const Span corner_verts, + const OffsetIndices offsets, + MutableSpan r_indices) +{ + Array counts(offsets.size(), 0); + for (const int64_t face_i : faces.index_range()) { + for (const int vert : corner_verts.slice(faces[face_i])) { + r_indices[offsets[vert].start() + counts[vert]] = int(face_i); + counts[vert]++; + } + } +} + GroupedSpan build_vert_to_face_map(const OffsetIndices faces, const Span corner_verts, const int verts_num, @@ -387,17 +401,16 @@ GroupedSpan build_vert_to_face_map(const OffsetIndices faces, { r_offsets = create_reverse_offsets(corner_verts, verts_num); r_indices.reinitialize(r_offsets.last()); - Array counts(verts_num, 0); - - for (const int64_t face_i : faces.index_range()) { - for (const int vert : corner_verts.slice(faces[face_i])) { - r_indices[r_offsets[vert] + counts[vert]] = int(face_i); - counts[vert]++; - } - } + build_vert_to_face_indices(faces, corner_verts, OffsetIndices(r_offsets), r_indices); return {OffsetIndices(r_offsets), r_indices}; } +Array build_vert_to_corner_indices(const Span corner_verts, + const OffsetIndices offsets) +{ + return reverse_indices_in_groups(corner_verts, offsets); +} + GroupedSpan build_vert_to_loop_map(const Span corner_verts, const int verts_num, Array &r_offsets, diff --git a/source/blender/blenkernel/intern/mesh_merge_customdata.cc b/source/blender/blenkernel/intern/mesh_merge_customdata.cc index cba83044d9b..82c0e311cf8 100644 --- a/source/blender/blenkernel/intern/mesh_merge_customdata.cc +++ b/source/blender/blenkernel/intern/mesh_merge_customdata.cc @@ -114,10 +114,7 @@ void BKE_mesh_merge_customdata_for_apply_modifier(Mesh *me) return; } - Array vert_to_loop_offsets; - Array vert_to_loop_indices; - const GroupedSpan vert_to_loop = bke::mesh::build_vert_to_loop_map( - me->corner_verts(), me->totvert, vert_to_loop_offsets, vert_to_loop_indices); + const GroupedSpan vert_to_loop = me->vert_to_corner_map(); Vector mloopuv_layers; mloopuv_layers.reserve(mloopuv_layers_num); diff --git a/source/blender/blenkernel/intern/mesh_mirror.cc b/source/blender/blenkernel/intern/mesh_mirror.cc index 6913490a884..61e66515697 100644 --- a/source/blender/blenkernel/intern/mesh_mirror.cc +++ b/source/blender/blenkernel/intern/mesh_mirror.cc @@ -414,7 +414,7 @@ Mesh *BKE_mesh_mirror_apply_mirror_on_axis_for_modifier(MirrorModifierData *mmd, result_faces, result_corner_verts, result_corner_edges, - {}, + result->corner_to_face_map(), result->vert_normals(), result->face_normals(), sharp_edges, diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 99d5ab7d7e3..b62079bbd2b 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -791,6 +791,7 @@ void edges_sharp_from_angle_set(const OffsetIndices faces, const Span corner_verts, const Span corner_edges, const Span face_normals, + const Span loop_to_face, const bool *sharp_faces, const float split_angle, MutableSpan sharp_edges) @@ -803,9 +804,6 @@ void edges_sharp_from_angle_set(const OffsetIndices faces, /* Mapping edge -> loops. See #bke::mesh::normals_calc_loop for details. */ Array edge_to_loops(sharp_edges.size(), int2(0)); - /* Simple mapping from a loop to its face index. */ - const Array loop_to_face = build_loop_to_face_map(faces); - mesh_edges_sharp_tag(faces, corner_verts, corner_edges, @@ -1257,17 +1255,6 @@ void normals_calc_loop(const Span vert_positions, * Note also that loose edges always have both values set to 0! */ Array edge_to_loops(edges.size(), int2(0)); - /* Simple mapping from a loop to its face index. */ - Span loop_to_face; - Array local_loop_to_face_map; - if (loop_to_face_map.is_empty()) { - local_loop_to_face_map = build_loop_to_face_map(faces); - loop_to_face = local_loop_to_face_map; - } - else { - loop_to_face = loop_to_face_map; - } - /* When using custom loop normals, disable the angle feature! */ const bool check_angle = (split_angle < float(M_PI)) && (clnors_data == nullptr); @@ -1293,7 +1280,7 @@ void normals_calc_loop(const Span vert_positions, common_data.corner_verts = corner_verts; common_data.corner_edges = corner_edges; common_data.edge_to_loops = edge_to_loops; - common_data.loop_to_face = loop_to_face; + common_data.loop_to_face = loop_to_face_map; common_data.face_normals = face_normals; common_data.vert_normals = vert_normals; @@ -1305,7 +1292,7 @@ void normals_calc_loop(const Span vert_positions, mesh_edges_sharp_tag(faces, corner_verts, corner_edges, - loop_to_face, + loop_to_face_map, face_normals, Span(sharp_faces, sharp_faces ? faces.size() : 0), Span(sharp_edges, sharp_edges ? edges.size() : 0), diff --git a/source/blender/blenkernel/intern/mesh_remap.cc b/source/blender/blenkernel/intern/mesh_remap.cc index b0bf2862a0e..702b479b35e 100644 --- a/source/blender/blenkernel/intern/mesh_remap.cc +++ b/source/blender/blenkernel/intern/mesh_remap.cc @@ -1290,12 +1290,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, blender::Array face_cents_src; - Array vert_to_loop_src_offsets; - Array vert_to_loop_src_indices; GroupedSpan vert_to_loop_map_src; - - Array vert_to_face_src_offsets; - Array vert_to_face_src_indices; GroupedSpan vert_to_face_map_src; Array edge_to_face_src_offsets; @@ -1306,7 +1301,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, int *face_to_looptri_map_src_buff = nullptr; /* Unlike above, those are one-to-one mappings, simpler! */ - blender::Array loop_to_face_map_src; + blender::Span loop_to_face_map_src; const blender::Span positions_src = me_src->vert_positions(); const int num_verts_src = me_src->totvert; @@ -1371,7 +1366,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, faces_dst, {corner_verts_dst, numloops_dst}, {corner_edges_dst, numloops_dst}, - {}, + mesh_dst->corner_to_face_map(), mesh_dst->vert_normals(), mesh_dst->face_normals(), sharp_edges, @@ -1397,15 +1392,9 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, } if (use_from_vert) { - vert_to_loop_map_src = bke::mesh::build_vert_to_loop_map( - corner_verts_src, num_verts_src, vert_to_loop_src_offsets, vert_to_loop_src_indices); - + vert_to_loop_map_src = me_src->vert_to_corner_map(); if (mode & MREMAP_USE_POLY) { - vert_to_face_map_src = bke::mesh::build_vert_to_face_map(faces_src, - corner_verts_src, - num_verts_src, - vert_to_face_src_offsets, - vert_to_face_src_indices); + vert_to_face_map_src = me_src->vert_to_face_map(); } } @@ -1417,7 +1406,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, edge_to_face_src_indices); if (use_from_vert) { - loop_to_face_map_src = blender::bke::mesh::build_loop_to_face_map(faces_src); + loop_to_face_map_src = me_src->corner_to_face_map(); face_cents_src.reinitialize(faces_src.size()); for (const int64_t i : faces_src.index_range()) { face_cents_src[i] = blender::bke::mesh::face_center_calc( diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index 43f0ec28fe8..d3c2ade9794 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -386,27 +386,13 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) return; } - Array source_vert_to_loop_offsets; - Array source_vert_to_loop_indices; GroupedSpan source_lmap; - Array target_vert_to_loop_offsets; - Array target_vert_to_loop_indices; GroupedSpan target_lmap; BVHTreeFromMesh bvhtree = {nullptr}; threading::parallel_invoke( [&]() { BKE_bvhtree_from_mesh_get(&bvhtree, source, BVHTREE_FROM_VERTS, 2); }, - [&]() { - source_lmap = mesh::build_vert_to_loop_map(source->corner_verts(), - source->totvert, - source_vert_to_loop_offsets, - source_vert_to_loop_indices); - }, - [&]() { - target_lmap = mesh::build_vert_to_loop_map(target->corner_verts(), - target->totvert, - target_vert_to_loop_offsets, - target_vert_to_loop_indices); - }); + [&]() { source_lmap = source->vert_to_corner_map(); }, + [&]() { target_lmap = target->vert_to_corner_map(); }); const Span target_positions = target->vert_positions(); Array nearest_src_verts(target_positions.size()); diff --git a/source/blender/blenkernel/intern/mesh_runtime.cc b/source/blender/blenkernel/intern/mesh_runtime.cc index b11f8f566ad..a9c49a20dc4 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.cc +++ b/source/blender/blenkernel/intern/mesh_runtime.cc @@ -14,6 +14,7 @@ #include "DNA_meshdata_types.h" #include "DNA_object_types.h" +#include "BLI_array_utils.hh" #include "BLI_math_geom.h" #include "BLI_task.hh" #include "BLI_timeit.hh" @@ -22,6 +23,7 @@ #include "BKE_editmesh_cache.hh" #include "BKE_lib_id.h" #include "BKE_mesh.hh" +#include "BKE_mesh_mapping.hh" #include "BKE_mesh_runtime.hh" #include "BKE_shrinkwrap.h" #include "BKE_subdiv_ccg.hh" @@ -125,6 +127,58 @@ static void try_tag_verts_no_face_none(const Mesh &mesh) } // namespace blender::bke +blender::Span Mesh::corner_to_face_map() const +{ + using namespace blender; + this->runtime->corner_to_face_map_cache.ensure([&](Array &r_data) { + const OffsetIndices faces = this->faces(); + r_data = bke::mesh::build_loop_to_face_map(faces); + }); + return this->runtime->corner_to_face_map_cache.data(); +} + +blender::OffsetIndices Mesh::vert_to_face_map_offsets() const +{ + using namespace blender; + this->runtime->vert_to_face_offset_cache.ensure([&](Array &r_data) { + r_data = Array(this->totvert + 1, 0); + offset_indices::build_reverse_offsets(this->corner_verts(), r_data); + }); + return OffsetIndices(this->runtime->vert_to_face_offset_cache.data()); +} + +blender::GroupedSpan Mesh::vert_to_face_map() const +{ + using namespace blender; + const OffsetIndices offsets = this->vert_to_face_map_offsets(); + this->runtime->vert_to_face_map_cache.ensure([&](Array &r_data) { + r_data.reinitialize(this->totloop); + if (this->runtime->vert_to_corner_map_cache.is_cached() && + this->runtime->corner_to_face_map_cache.is_cached()) + { + /* The vertex to face cache can be built from the vertex to face corner + * and face corner to face maps if they are both already cached. */ + array_utils::gather(this->runtime->vert_to_corner_map_cache.data().as_span(), + this->runtime->corner_to_face_map_cache.data().as_span(), + r_data.as_mutable_span()); + } + else { + bke::mesh::build_vert_to_face_indices(this->faces(), this->corner_verts(), offsets, r_data); + } + }); + return {offsets, this->runtime->vert_to_face_map_cache.data()}; +} + +blender::GroupedSpan Mesh::vert_to_corner_map() const +{ + using namespace blender; + const OffsetIndices offsets = this->vert_to_face_map_offsets(); + this->runtime->vert_to_corner_map_cache.ensure([&](Array &r_data) { + r_data = bke::mesh::build_vert_to_corner_indices(this->corner_verts(), offsets); + }); + return {offsets, this->runtime->vert_to_corner_map_cache.data()}; +} + const blender::bke::LooseVertCache &Mesh::loose_verts() const { using namespace blender::bke; @@ -250,6 +304,10 @@ void BKE_mesh_runtime_clear_geometry(Mesh *mesh) free_bvh_cache(*mesh->runtime); free_subdiv_ccg(*mesh->runtime); mesh->runtime->bounds_cache.tag_dirty(); + mesh->runtime->vert_to_face_offset_cache.tag_dirty(); + mesh->runtime->vert_to_face_map_cache.tag_dirty(); + mesh->runtime->vert_to_corner_map_cache.tag_dirty(); + mesh->runtime->corner_to_face_map_cache.tag_dirty(); mesh->runtime->vert_normals_cache.tag_dirty(); mesh->runtime->face_normals_cache.tag_dirty(); mesh->runtime->loose_edges_cache.tag_dirty(); @@ -271,6 +329,9 @@ void BKE_mesh_tag_edges_split(Mesh *mesh) free_bvh_cache(*mesh->runtime); mesh->runtime->vert_normals_cache.tag_dirty(); free_subdiv_ccg(*mesh->runtime); + mesh->runtime->vert_to_face_offset_cache.tag_dirty(); + mesh->runtime->vert_to_face_map_cache.tag_dirty(); + mesh->runtime->vert_to_corner_map_cache.tag_dirty(); if (mesh->runtime->loose_edges_cache.is_cached() && mesh->runtime->loose_edges_cache.data().count != 0) { @@ -298,6 +359,7 @@ void BKE_mesh_tag_face_winding_changed(Mesh *mesh) { mesh->runtime->vert_normals_cache.tag_dirty(); mesh->runtime->face_normals_cache.tag_dirty(); + mesh->runtime->vert_to_corner_map_cache.tag_dirty(); } void BKE_mesh_tag_positions_changed(Mesh *mesh) diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc index 9b02ace2097..56489d3626c 100644 --- a/source/blender/blenkernel/intern/multires.cc +++ b/source/blender/blenkernel/intern/multires.cc @@ -469,10 +469,6 @@ void multires_force_sculpt_rebuild(Object *object) BKE_pbvh_free(ss->pbvh); object->sculpt->pbvh = nullptr; } - - ss->vert_to_face_indices = {}; - ss->vert_to_face_offsets = {}; - ss->pmap = {}; } void multires_force_external_reload(Object *object) diff --git a/source/blender/blenkernel/intern/multires_reshape_apply_base.cc b/source/blender/blenkernel/intern/multires_reshape_apply_base.cc index 7b31a3e6f6e..60679801ce8 100644 --- a/source/blender/blenkernel/intern/multires_reshape_apply_base.cc +++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.cc @@ -72,14 +72,7 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape blender::MutableSpan base_positions = base_mesh->vert_positions_for_write(); /* Update the context in case the vertices were duplicated. */ reshape_context->base_positions = base_positions; - blender::Array vert_to_face_offsets; - blender::Array vert_to_face_indices; - const blender::GroupedSpan pmap = blender::bke::mesh::build_vert_to_face_map( - reshape_context->base_faces, - reshape_context->base_corner_verts, - base_mesh->totvert, - vert_to_face_offsets, - vert_to_face_indices); + const blender::GroupedSpan pmap = base_mesh->vert_to_face_map(); float(*origco)[3] = static_cast( MEM_calloc_arrayN(base_mesh->totvert, sizeof(float[3]), __func__)); diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.cc b/source/blender/blenkernel/intern/multires_unsubdivide.cc index 37c40a88d88..c291671705f 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.cc +++ b/source/blender/blenkernel/intern/multires_unsubdivide.cc @@ -925,7 +925,6 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract( MultiresUnsubdivideContext *context) { Mesh *original_mesh = context->original_mesh; - const blender::OffsetIndices original_faces = original_mesh->faces(); Mesh *base_mesh = context->base_mesh; @@ -953,7 +952,7 @@ static void multires_unsubdivide_prepare_original_bmesh_for_extract( BM_elem_flag_set(v, BM_ELEM_TAG, true); } - context->loop_to_face_map = blender::bke::mesh::build_loop_to_face_map(original_faces); + context->loop_to_face_map = original_mesh->corner_to_face_map(); } /** diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.hh b/source/blender/blenkernel/intern/multires_unsubdivide.hh index 077b27f4b46..896acb8a6ad 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.hh +++ b/source/blender/blenkernel/intern/multires_unsubdivide.hh @@ -52,7 +52,7 @@ struct MultiresUnsubdivideContext { /* Private data. */ BMesh *bm_original_mesh; - blender::Array loop_to_face_map; + blender::Span loop_to_face_map; const int *base_to_orig_vmap; }; diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index 7e024b19b42..9ef84f4a0aa 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1391,13 +1391,7 @@ void BKE_sculptsession_free_deformMats(SculptSession *ss) void BKE_sculptsession_free_vwpaint_data(SculptSession *ss) { - SculptVertexPaintGeomMap *gmap = nullptr; - if (ss->mode_type == OB_MODE_VERTEX_PAINT) { - gmap = &ss->mode.vpaint.gmap; - } - else if (ss->mode_type == OB_MODE_WEIGHT_PAINT) { - gmap = &ss->mode.wpaint.gmap; - + if (ss->mode_type == OB_MODE_WEIGHT_PAINT) { MEM_SAFE_FREE(ss->mode.wpaint.alpha_weight); if (ss->mode.wpaint.dvert_prev) { BKE_defvert_array_free_elems(ss->mode.wpaint.dvert_prev, ss->totvert); @@ -1405,15 +1399,6 @@ void BKE_sculptsession_free_vwpaint_data(SculptSession *ss) ss->mode.wpaint.dvert_prev = nullptr; } } - else { - return; - } - gmap->vert_to_loop_offsets = {}; - gmap->vert_to_loop_indices = {}; - gmap->vert_to_loop = {}; - gmap->vert_to_face_offsets = {}; - gmap->vert_to_face_indices = {}; - gmap->vert_to_face = {}; } /** @@ -1459,8 +1444,6 @@ static void sculptsession_free_pbvh(Object *object) ss->pbvh = nullptr; } - ss->vert_to_face_offsets = {}; - ss->vert_to_face_indices = {}; ss->pmap = {}; ss->edge_to_face_offsets = {}; ss->edge_to_face_indices = {}; @@ -1776,12 +1759,8 @@ static void sculpt_update_object( sculpt_attribute_update_refs(ob); sculpt_update_persistent_base(ob); - if (ob->type == OB_MESH && ss->pmap.is_empty()) { - ss->pmap = blender::bke::mesh::build_vert_to_face_map(me->faces(), - me->corner_verts(), - me->totvert, - ss->vert_to_face_offsets, - ss->vert_to_face_indices); + if (ob->type == OB_MESH) { + ss->pmap = me->vert_to_face_map(); } if (ss->pbvh) { diff --git a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc index 886cc7512d8..4a9c93a6b47 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh_render_data.cc @@ -357,7 +357,7 @@ void mesh_render_data_update_normals(MeshRenderData &mr, const eMRDataType data_ mr.faces, mr.corner_verts, mr.corner_edges, - {}, + mr.me->corner_to_face_map(), mr.vert_normals, mr.face_normals, sharp_edges, diff --git a/source/blender/editors/mesh/mesh_data.cc b/source/blender/editors/mesh/mesh_data.cc index 2bbbad25154..6e23637089c 100644 --- a/source/blender/editors/mesh/mesh_data.cc +++ b/source/blender/editors/mesh/mesh_data.cc @@ -744,6 +744,7 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator me->corner_verts(), me->corner_edges(), me->face_normals(), + me->corner_to_face_map(), sharp_faces, me->smoothresh, sharp_edges.span); @@ -1165,6 +1166,7 @@ void ED_mesh_split_faces(Mesh *mesh) corner_verts, corner_edges, mesh->face_normals(), + mesh->corner_to_face_map(), sharp_faces, split_angle, sharp_edges); diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index 65dc7c9bfd0..4c23947e1b0 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -241,15 +241,9 @@ void init_session_data(const ToolSettings *ts, Object *ob) } Mesh *me = (Mesh *)ob->data; - const blender::OffsetIndices faces = me->faces(); - const Span corner_verts = me->corner_verts(); - if (gmap->vert_to_loop_indices.is_empty()) { - gmap->vert_to_loop = blender::bke::mesh::build_vert_to_loop_map( - corner_verts, me->totvert, gmap->vert_to_loop_offsets, gmap->vert_to_loop_indices); - gmap->vert_to_face = blender::bke::mesh::build_vert_to_face_map( - faces, corner_verts, me->totvert, gmap->vert_to_face_offsets, gmap->vert_to_face_indices); - } + gmap->vert_to_loop = me->vert_to_corner_map(); + gmap->vert_to_face = me->vert_to_face_map(); /* Create average brush arrays */ if (ob->mode == OB_MODE_WEIGHT_PAINT) { diff --git a/source/blender/geometry/intern/mesh_split_edges.cc b/source/blender/geometry/intern/mesh_split_edges.cc index 253d9ec2773..66a07ddfa49 100644 --- a/source/blender/geometry/intern/mesh_split_edges.cc +++ b/source/blender/geometry/intern/mesh_split_edges.cc @@ -517,10 +517,7 @@ void split_edges(Mesh &mesh, const BitVector<> selection_bits = selection_to_bit_vector(selected_edges, orig_edges.size()); const bke::LooseEdgeCache &loose_edges = mesh.loose_edges(); - Array vert_to_corner_offsets; - Array vert_to_corner_indices; - const GroupedSpan vert_to_corner_map = bke::mesh::build_vert_to_loop_map( - mesh.corner_verts(), orig_verts_num, vert_to_corner_offsets, vert_to_corner_indices); + const GroupedSpan vert_to_corner_map = mesh.vert_to_corner_map(); Array edge_to_corner_offsets; Array edge_to_corner_indices; @@ -535,7 +532,7 @@ void split_edges(Mesh &mesh, orig_edges, orig_verts_num, vert_to_edge_offsets, vert_to_edge_indices); } - const Array corner_to_face_map = bke::mesh::build_loop_to_face_map(mesh.faces()); + const Array corner_to_face_map = mesh.corner_to_face_map(); const Array> corner_groups = calc_all_corner_groups(faces, mesh.corner_verts(), diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 5134f8ac955..0e7eab367c2 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -316,6 +316,23 @@ typedef struct Mesh { /** Set cached mesh bounds to a known-correct value to avoid their lazy calculation later on. */ void bounds_set_eager(const blender::Bounds &bounds); + /** + * Cached map containing the index of the face using each face corner. + */ + blender::Span corner_to_face_map() const; + /** + * Offsets per vertex used to slice arrays containing data for connected faces or face corners. + */ + blender::OffsetIndices vert_to_face_map_offsets() const; + /** + * Cached map from each vertex to the corners using it. + */ + blender::GroupedSpan vert_to_corner_map() const; + /** + * Cached map from each vertex to the faces using it. + */ + blender::GroupedSpan vert_to_face_map() const; + /** * Cached information about loose edges, calculated lazily when necessary. */ diff --git a/source/blender/modifiers/intern/MOD_normal_edit.cc b/source/blender/modifiers/intern/MOD_normal_edit.cc index 64f72588442..954c722fadd 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.cc +++ b/source/blender/modifiers/intern/MOD_normal_edit.cc @@ -534,7 +534,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, faces, corner_verts, corner_edges, - {}, + result->corner_to_face_map(), result->vert_normals(), result->face_normals(), sharp_edges.span.data(), diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index 81b6c6ff536..737eb4b3c59 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -543,7 +543,7 @@ static Mesh *modify_mesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh int defgrp_index; MOD_get_vgroup(ctx->object, mesh, wnmd->defgrp_name, &dvert, &defgrp_index); - const Array loop_to_face_map = bke::mesh::build_loop_to_face_map(result->faces()); + const Span loop_to_face_map = result->corner_to_face_map(); bke::MutableAttributeAccessor attributes = result->attributes_for_write(); bke::SpanAttributeWriter sharp_edges = attributes.lookup_or_add_for_write_span( diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index bfc5fdfc267..cf1ada8e1ab 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -630,15 +630,8 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, /* Stores the indices of the faces connected to the vertex. Because the faces are looped * over in order of their indices, the face's indices will be sorted in ascending order. * (This can change once they are sorted using `sort_vertex_faces`). */ - Array vert_to_face_offset_data; - Array vert_to_face_indices; - const GroupedSpan vert_to_face_map = bke::mesh::build_vert_to_face_map( - src_faces, - src_corner_verts, - src_positions.size(), - vert_to_face_offset_data, - vert_to_face_indices); - const OffsetIndices vert_to_face_offsets(vert_to_face_offset_data); + Array vert_to_face_indices = src_mesh.vert_to_face_map().data; + const OffsetIndices vert_to_face_offsets = src_mesh.vert_to_face_map().offsets; Array> vertex_shared_edges(src_mesh.totvert); Array> vertex_corners(src_mesh.totvert); @@ -692,6 +685,8 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, } }); + const GroupedSpan vert_to_face_map(vert_to_face_offsets, vert_to_face_indices); + Vector vert_positions(src_mesh.faces_num); for (const int i : src_faces.index_range()) { const IndexRange face = src_faces[i]; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc index f9d4d70057b..45e6ea43ac6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_corners_of_vertex.cc @@ -49,10 +49,7 @@ class CornersOfVertInput final : public bke::MeshFieldInput { const IndexMask &mask) const final { const IndexRange vert_range(mesh.totvert); - Array map_offsets; - Array map_indices; - const GroupedSpan vert_to_loop_map = bke::mesh::build_vert_to_loop_map( - mesh.corner_verts(), mesh.totvert, map_offsets, map_indices); + const GroupedSpan vert_to_corner_map = mesh.vert_to_corner_map(); const bke::MeshFieldContext context{mesh, domain}; fn::FieldEvaluator evaluator{context, &mask}; @@ -83,7 +80,7 @@ class CornersOfVertInput final : public bke::MeshFieldInput { continue; } - const Span corners = vert_to_loop_map[vert_i]; + const Span corners = vert_to_corner_map[vert_i]; if (corners.is_empty()) { corner_of_vertex[selection_i] = 0; continue; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc index a2e14801ff9..ed1d82edf32 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_corner.cc @@ -75,12 +75,10 @@ class CornerPreviousEdgeFieldInput final : public bke::MeshFieldInput { } const OffsetIndices faces = mesh.faces(); const Span corner_edges = mesh.corner_edges(); - Array loop_to_face_map = bke::mesh::build_loop_to_face_map(faces); + const Span corner_to_face = mesh.corner_to_face_map(); return VArray::ForFunc( - mesh.totloop, - [faces, corner_edges, loop_to_face_map = std::move(loop_to_face_map)](const int corner_i) { - return corner_edges[bke::mesh::face_corner_prev(faces[loop_to_face_map[corner_i]], - corner_i)]; + corner_edges.size(), [faces, corner_edges, corner_to_face](const int corner) { + return corner_edges[bke::mesh::face_corner_prev(faces[corner_to_face[corner]], corner)]; }); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc index 6474d30945d..a2c8b71ec08 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_face_of_corner.cc @@ -36,7 +36,7 @@ class CornerFaceIndexInput final : public bke::MeshFieldInput { if (domain != ATTR_DOMAIN_CORNER) { return {}; } - return VArray::ForContainer(bke::mesh::build_loop_to_face_map(mesh.faces())); + return VArray::ForSpan(mesh.corner_to_face_map()); } uint64_t hash() const final @@ -65,12 +65,11 @@ class CornerIndexInFaceInput final : public bke::MeshFieldInput { return {}; } const OffsetIndices faces = mesh.faces(); - Array loop_to_face_map = bke::mesh::build_loop_to_face_map(faces); - return VArray::ForFunc( - mesh.totloop, [faces, loop_to_face_map = std::move(loop_to_face_map)](const int corner_i) { - const int face_i = loop_to_face_map[corner_i]; - return corner_i - faces[face_i].start(); - }); + const Span corner_to_face = mesh.corner_to_face_map(); + return VArray::ForFunc(mesh.totloop, [faces, corner_to_face](const int corner) { + const int face_i = corner_to_face[corner]; + return corner - faces[face_i].start(); + }); } uint64_t hash() const final diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc index 4e96a2a6fd6..7cc09979da4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_offset_corner_in_face.cc @@ -52,7 +52,7 @@ class OffsetCornerInFaceFieldInput final : public bke::MeshFieldInput { const VArray corner_indices = evaluator.get_evaluated(0); const VArray offsets = evaluator.get_evaluated(1); - Array loop_to_face_map = bke::mesh::build_loop_to_face_map(faces); + const Span corner_to_face = mesh.corner_to_face_map(); Array offset_corners(mask.min_array_size()); mask.foreach_index_optimized(GrainSize(2048), [&](const int selection_i) { @@ -63,7 +63,7 @@ class OffsetCornerInFaceFieldInput final : public bke::MeshFieldInput { return; } - const IndexRange face = faces[loop_to_face_map[corner_i]]; + const IndexRange face = faces[corner_to_face[corner_i]]; offset_corners[selection_i] = apply_offset_in_cyclic_range(face, corner_i, offset); });