From 4d841e1b355959aba4b55e9f7bfa83af0ed2d162 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Wed, 24 May 2023 13:16:57 +0200 Subject: [PATCH] Mesh: Reimplement and unify topology maps Combine the newer less efficient C++ implementations and the older less convenient C functions. The maps now contain one large array of indices, split into groups by a separate array of offset indices. Though performance of creating the maps is relatively unchanged, the new implementation uses 4 bytes less per source element than the C maps, and 20 bytes less than the newer C++ functions (which also had more overhead with larger N-gons). The usage syntax is simpler than the C functions as well. The reduced memory usage is helpful for when these maps are cached in the near future. It will also allow sharing the offsets between maps for different domains like vertex to corner and vertex to face. A simple `GroupedSpan` class is introduced to make accessing the topology maps much simpler. It combines offset indices and a separate span, splitting it into chunks in an efficient way. Pull Request: https://projects.blender.org/blender/blender/pulls/107861 --- source/blender/blenkernel/BKE_mesh_mapping.h | 97 ++-- source/blender/blenkernel/BKE_paint.h | 35 +- source/blender/blenkernel/BKE_pbvh.h | 4 +- source/blender/blenkernel/BKE_subdiv_mesh.hh | 4 +- source/blender/blenkernel/intern/mesh_fair.cc | 57 +-- .../blender/blenkernel/intern/mesh_mapping.cc | 466 +++++------------- .../intern/mesh_merge_customdata.cc | 15 +- .../blender/blenkernel/intern/mesh_normals.cc | 11 +- .../blender/blenkernel/intern/mesh_remap.cc | 135 +++-- .../blenkernel/intern/mesh_remesh_voxel.cc | 55 +-- source/blender/blenkernel/intern/multires.cc | 6 +- .../intern/multires_reshape_apply_base.cc | 27 +- .../blenkernel/intern/multires_unsubdivide.cc | 2 +- source/blender/blenkernel/intern/paint.cc | 39 +- source/blender/blenkernel/intern/pbvh.cc | 6 +- .../blender/blenkernel/intern/pbvh_colors.cc | 8 +- .../blender/blenkernel/intern/pbvh_intern.hh | 3 +- .../blender/blenkernel/intern/subdiv_mesh.cc | 29 +- source/blender/blenlib/BLI_offset_indices.hh | 50 +- .../blender/blenlib/intern/offset_indices.cc | 12 +- .../intern/draw_cache_impl_subdivision.cc | 14 +- source/blender/editors/mesh/editface.cc | 28 +- .../blender/editors/object/object_modifier.cc | 20 +- .../blender/editors/object/object_vgroup.cc | 28 +- .../editors/sculpt_paint/paint_vertex.cc | 62 +-- source/blender/editors/sculpt_paint/sculpt.cc | 50 +- .../sculpt_paint/sculpt_automasking.cc | 15 - .../editors/sculpt_paint/sculpt_dyntopo.cc | 4 - .../editors/sculpt_paint/sculpt_expand.cc | 11 +- .../editors/sculpt_paint/sculpt_face_set.cc | 26 +- .../sculpt_paint/sculpt_filter_color.cc | 4 - .../sculpt_paint/sculpt_filter_mask.cc | 4 - .../editors/sculpt_paint/sculpt_geodesic.cc | 24 +- .../editors/sculpt_paint/sculpt_ops.cc | 4 - .../editors/sculpt_paint/sculpt_smooth.cc | 6 - .../geometry/intern/mesh_split_edges.cc | 26 +- source/blender/modifiers/intern/MOD_skin.cc | 77 ++- .../modifiers/intern/MOD_weighted_normal.cc | 2 +- .../geometry/nodes/node_geo_blur_attribute.cc | 194 ++++---- .../geometry/nodes/node_geo_dual_mesh.cc | 21 +- .../nodes/node_geo_edges_to_face_groups.cc | 6 +- .../geometry/nodes/node_geo_extrude_mesh.cc | 14 +- ...ode_geo_mesh_topology_corners_of_vertex.cc | 9 +- .../node_geo_mesh_topology_edges_of_corner.cc | 2 +- .../node_geo_mesh_topology_edges_of_vertex.cc | 6 +- .../node_geo_mesh_topology_face_of_corner.cc | 4 +- ...geo_mesh_topology_offset_corner_in_face.cc | 2 +- .../blender/render/intern/texture_margin.cc | 2 +- 48 files changed, 713 insertions(+), 1013 deletions(-) diff --git a/source/blender/blenkernel/BKE_mesh_mapping.h b/source/blender/blenkernel/BKE_mesh_mapping.h index 8b52ddcc3c3..f11d3895606 100644 --- a/source/blender/blenkernel/BKE_mesh_mapping.h +++ b/source/blender/blenkernel/BKE_mesh_mapping.h @@ -119,27 +119,6 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap); #ifdef __cplusplus -/** - * Generates a map where the key is the vertex and the value - * is a list of polys that use that vertex as a corner. - * The lists are allocated from one memory pool. - */ -void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map, - int **r_mem, - blender::OffsetIndices polys, - const int *corner_verts, - int totvert); -/** - * Generates a map where the key is the vertex and the value - * is a list of loops that use that vertex as a corner. - * The lists are allocated from one memory pool. - */ -void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, - int **r_mem, - blender::OffsetIndices polys, - const int *corner_verts, - int totvert); - /** * Generates a map where the key is the edge and the value * is a list of looptris that use that edge. @@ -152,42 +131,6 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map, int totlooptri, const int *corner_verts, int totloop); -/** - * Generates a map where the key is the vertex and the value - * is a list of edges that use that vertex as an endpoint. - * The lists are allocated from one memory pool. - */ -void BKE_mesh_vert_edge_map_create( - MeshElemMap **r_map, int **r_mem, const blender::int2 *edges, int totvert, int totedge); -/** - * A version of #BKE_mesh_vert_edge_map_create that references connected vertices directly - * (not their edges). - */ -void BKE_mesh_vert_edge_vert_map_create( - MeshElemMap **r_map, int **r_mem, const blender::int2 *edges, int totvert, int totedge); - -/** - * Generates a map where the key is the edge and the value is a list of loops that use that edge. - * Loops indices of a same poly are contiguous and in winding order. - * The lists are allocated from one memory pool. - */ -void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map, - int **r_mem, - int totedge, - blender::OffsetIndices polys, - const int *corner_edges, - int totloop); -/** - * Generates a map where the key is the edge and the value - * is a list of polygons that use that edge. - * The lists are allocated from one memory pool. - */ -void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, - int **r_mem, - int totedge, - blender::OffsetIndices polys, - const int *corner_edges, - int totloop); /** * This function creates a map so the source-data (vert/edge/loop/poly) * can loop over the destination data (using the destination arrays origindex). @@ -346,20 +289,36 @@ int *BKE_mesh_calc_smoothgroups(int totedge, #ifdef __cplusplus -namespace blender::bke::mesh_topology { +namespace blender::bke::mesh { Array build_loop_to_poly_map(OffsetIndices polys); -Array> build_vert_to_edge_map(Span edges, int verts_num); -Array> build_vert_to_poly_map(OffsetIndices polys, - Span corner_verts, - int verts_num); -Array> build_vert_to_loop_map(Span corner_verts, int verts_num); -Array> build_edge_to_loop_map(Span corner_edges, int edges_num); -Array> build_edge_to_poly_map(OffsetIndices polys, - Span corner_edges, - int edges_num); -Vector> build_edge_to_loop_map_resizable(Span corner_edges, int edges_num); +GroupedSpan build_vert_to_edge_map(Span edges, + int verts_num, + Array &r_offsets, + Array &r_indices); -} // namespace blender::bke::mesh_topology +GroupedSpan build_vert_to_poly_map(OffsetIndices polys, + Span corner_verts, + int verts_num, + Array &r_offsets, + Array &r_indices); + +GroupedSpan build_vert_to_loop_map(Span corner_verts, + int verts_num, + Array &r_offsets, + Array &r_indices); + +GroupedSpan build_edge_to_loop_map(Span corner_edges, + int edges_num, + Array &r_offsets, + Array &r_indices); + +GroupedSpan build_edge_to_poly_map(OffsetIndices polys, + Span corner_edges, + int edges_num, + Array &r_offsets, + Array &r_indices); + +} // namespace blender::bke::mesh #endif diff --git a/source/blender/blenkernel/BKE_paint.h b/source/blender/blenkernel/BKE_paint.h index cb674d3f744..a366fe0d991 100644 --- a/source/blender/blenkernel/BKE_paint.h +++ b/source/blender/blenkernel/BKE_paint.h @@ -9,6 +9,10 @@ #include "BLI_bitmap.h" #include "BLI_compiler_compat.h" +#ifdef __cplusplus +# include "BLI_array.hh" +# include "BLI_offset_indices.hh" +#endif #include "BLI_utildefines.h" #include "DNA_brush_enums.h" @@ -40,7 +44,6 @@ struct ListBase; struct MLoopTri; struct Main; struct Mesh; -struct MeshElemMap; struct Object; struct PBVH; struct Paint; @@ -273,12 +276,17 @@ void BKE_paint_blend_read_lib(struct BlendLibReader *reader, #define SCULPT_FACE_SET_NONE 0 /** Used for both vertex color and weight paint. */ +#ifdef __cplusplus struct SculptVertexPaintGeomMap { - int *vert_map_mem; - struct MeshElemMap *vert_to_loop; - int *poly_map_mem; - struct MeshElemMap *vert_to_poly; + blender::Array vert_to_loop_offsets; + blender::Array vert_to_loop_indices; + blender::GroupedSpan vert_to_loop; + + blender::Array vert_to_poly_offsets; + blender::Array vert_to_poly_indices; + blender::GroupedSpan vert_to_poly; }; +#endif /** Pose Brush IK Chain. */ typedef struct SculptPoseIKChainSegment { @@ -599,16 +607,19 @@ typedef struct SculptSession { /* Mesh connectivity maps. */ /* Vertices to adjacent polys. */ - struct MeshElemMap *pmap; - int *pmap_mem; + blender::Array vert_to_poly_offsets; + blender::Array vert_to_poly_indices; + blender::GroupedSpan pmap; /* Edges to adjacent polys. */ - struct MeshElemMap *epmap; - int *epmap_mem; + blender::Array edge_to_poly_offsets; + blender::Array edge_to_poly_indices; + blender::GroupedSpan epmap; /* Vertices to adjacent edges. */ - struct MeshElemMap *vemap; - int *vemap_mem; + blender::Array vert_to_edge_offsets; + blender::Array vert_to_edge_indices; + blender::GroupedSpan vemap; /* Mesh Face Sets */ /* Total number of polys of the base mesh. */ @@ -706,7 +717,7 @@ typedef struct SculptSession { float prev_pivot_rot[4]; float prev_pivot_scale[3]; - union { + struct { struct { struct SculptVertexPaintGeomMap gmap; } vpaint; diff --git a/source/blender/blenkernel/BKE_pbvh.h b/source/blender/blenkernel/BKE_pbvh.h index 8e8b08f5d8a..fa82f1015ac 100644 --- a/source/blender/blenkernel/BKE_pbvh.h +++ b/source/blender/blenkernel/BKE_pbvh.h @@ -35,7 +35,6 @@ struct DMFlagMat; struct IsectRayPrecalc; struct MLoopTri; struct Mesh; -struct MeshElemMap; struct PBVH; struct PBVHBatches; struct PBVHNode; @@ -45,7 +44,6 @@ struct SubdivCCG; struct TaskParallelSettings; struct Image; struct ImageUser; -struct MeshElemMap; typedef struct PBVH PBVH; typedef struct PBVHNode PBVHNode; @@ -808,7 +806,6 @@ void BKE_pbvh_is_drawing_set(PBVH *pbvh, bool val); void BKE_pbvh_node_num_loops(PBVH *pbvh, PBVHNode *node, int *r_totloop); void BKE_pbvh_update_active_vcol(PBVH *pbvh, const struct Mesh *mesh); -void BKE_pbvh_pmap_set(PBVH *pbvh, const struct MeshElemMap *pmap); void BKE_pbvh_vertex_color_set(PBVH *pbvh, PBVHVertRef vertex, const float color[4]); void BKE_pbvh_vertex_color_get(const PBVH *pbvh, PBVHVertRef vertex, float r_color[4]); @@ -818,6 +815,7 @@ bool BKE_pbvh_draw_cache_invalid(const PBVH *pbvh); int BKE_pbvh_debug_draw_gen_get(PBVHNode *node); #ifdef __cplusplus +void BKE_pbvh_pmap_set(PBVH *pbvh, blender::GroupedSpan pmap); } namespace blender::bke::pbvh { diff --git a/source/blender/blenkernel/BKE_subdiv_mesh.hh b/source/blender/blenkernel/BKE_subdiv_mesh.hh index 1380aeeb1b7..b922b7b39bb 100644 --- a/source/blender/blenkernel/BKE_subdiv_mesh.hh +++ b/source/blender/blenkernel/BKE_subdiv_mesh.hh @@ -8,10 +8,10 @@ #pragma once #include "BLI_math_vector_types.hh" +#include "BLI_offset_indices.hh" #include "BLI_sys_types.h" struct Mesh; -struct MeshElemMap; struct Subdiv; struct SubdivToMeshSettings { @@ -36,7 +36,7 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, * interpolation will be done base on the edge vertices. */ void BKE_subdiv_mesh_interpolate_position_on_edge(const float (*coarse_positions)[3], const blender::int2 *coarse_edges, - const MeshElemMap *vert_to_edge_map, + blender::GroupedSpan vert_to_edge_map, int coarse_edge_index, bool is_simple, float u, diff --git a/source/blender/blenkernel/intern/mesh_fair.cc b/source/blender/blenkernel/intern/mesh_fair.cc index ecf88f5c797..e7c79bfcd09 100644 --- a/source/blender/blenkernel/intern/mesh_fair.cc +++ b/source/blender/blenkernel/intern/mesh_fair.cc @@ -66,9 +66,9 @@ class FairingContext { return totvert_; } - MeshElemMap *vertex_loop_map_get(const int v) + Span vertex_loop_map_get(const int v) { - return &vlmap_[v]; + return vlmap_[v]; } float *vertex_deformation_co_get(const int v) @@ -93,8 +93,7 @@ class FairingContext { int totvert_; int totloop_; - MeshElemMap *vlmap_; - int *vlmap_mem_; + blender::GroupedSpan vlmap_; private: void fair_setup_fairing(const int v, @@ -120,9 +119,9 @@ class FairingContext { float w_ij_sum = 0; const float w_i = vertex_weight->weight_at_index(v); - MeshElemMap *vlmap_elem = &vlmap_[v]; - for (int l = 0; l < vlmap_elem->count; l++) { - const int l_index = vlmap_elem->indices[l]; + const Span vlmap_elem = vlmap_[v]; + for (const int l : vlmap_elem.index_range()) { + const int l_index = vlmap_elem[l]; const int other_vert = other_vertex_index_from_loop(l_index, v); const float w_ij = loop_weight->weight_at_index(l_index); w_ij_sum += w_ij; @@ -202,8 +201,8 @@ class MeshFairingContext : public FairingContext { polys = mesh->polys(); corner_verts_ = mesh->corner_verts(); corner_edges_ = mesh->corner_edges(); - BKE_mesh_vert_loop_map_create( - &vlmap_, &vlmap_mem_, polys, corner_verts_.data(), mesh->totvert); + vlmap_ = blender::bke::mesh::build_vert_to_loop_map( + corner_verts_, positions.size(), vert_to_poly_offsets_, vert_to_poly_indices_); /* Deformation coords. */ co_.reserve(mesh->totvert); @@ -218,13 +217,7 @@ class MeshFairingContext : public FairingContext { } } - loop_to_poly_map_ = blender::bke::mesh_topology::build_loop_to_poly_map(polys); - } - - ~MeshFairingContext() override - { - MEM_SAFE_FREE(vlmap_); - MEM_SAFE_FREE(vlmap_mem_); + loop_to_poly_map_ = blender::bke::mesh::build_loop_to_poly_map(polys); } void adjacents_coords_from_loop(const int loop, @@ -252,6 +245,8 @@ class MeshFairingContext : public FairingContext { blender::OffsetIndices polys; Span edges_; Array loop_to_poly_map_; + Array vert_to_poly_offsets_; + Array vert_to_poly_indices_; }; class BMeshFairingContext : public FairingContext { @@ -272,9 +267,9 @@ class BMeshFairingContext : public FairingContext { co_[i] = v->co; } - bmloop_.reserve(bm->totloop); - vlmap_ = (MeshElemMap *)MEM_calloc_arrayN(bm->totvert, sizeof(MeshElemMap), "bmesh loop map"); - vlmap_mem_ = (int *)MEM_malloc_arrayN(bm->totloop, sizeof(int), "bmesh loop map mempool"); + bmloop_.reinitialize(bm->totloop); + vert_to_loop_offsets_ = Array(bm->totvert, 0); + vert_to_loop_indices_.reinitialize(bm->totloop); BMVert *v; BMLoop *l; @@ -286,22 +281,16 @@ class BMeshFairingContext : public FairingContext { BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { int loop_count = 0; const int vert_index = BM_elem_index_get(v); - vlmap_[vert_index].indices = &vlmap_mem_[index_iter]; + vert_to_loop_offsets_[vert_index] = index_iter; BM_ITER_ELEM (l, &loop_iter, v, BM_LOOPS_OF_VERT) { const int loop_index = BM_elem_index_get(l); bmloop_[loop_index] = l; - vlmap_mem_[index_iter] = loop_index; + vert_to_loop_indices_[index_iter] = loop_index; index_iter++; loop_count++; } - vlmap_[vert_index].count = loop_count; } - } - - ~BMeshFairingContext() override - { - MEM_SAFE_FREE(vlmap_); - MEM_SAFE_FREE(vlmap_mem_); + vert_to_loop_offsets_.last() = index_iter; } void adjacents_coords_from_loop(const int loop, @@ -322,7 +311,9 @@ class BMeshFairingContext : public FairingContext { protected: BMesh *bm; - Vector bmloop_; + Array bmloop_; + Array vert_to_loop_offsets_; + Array vert_to_loop_indices_; }; class UniformVertexWeight : public VertexWeight { @@ -332,7 +323,7 @@ class UniformVertexWeight : public VertexWeight { const int totvert = fairing_context->vertex_count_get(); vertex_weights_.reserve(totvert); for (int i = 0; i < totvert; i++) { - const int tot_loop = fairing_context->vertex_loop_map_get(i)->count; + const int tot_loop = fairing_context->vertex_loop_map_get(i).size(); if (tot_loop != 0) { vertex_weights_[i] = 1.0f / tot_loop; } @@ -366,9 +357,9 @@ class VoronoiVertexWeight : public VertexWeight { copy_v3_v3(a, fairing_context->vertex_deformation_co_get(i)); const float acute_threshold = M_PI_2; - MeshElemMap *vlmap_elem = fairing_context->vertex_loop_map_get(i); - for (int l = 0; l < vlmap_elem->count; l++) { - const int l_index = vlmap_elem->indices[l]; + const Span vlmap_elem = fairing_context->vertex_loop_map_get(i); + for (const int l : vlmap_elem.index_range()) { + const int l_index = vlmap_elem[l]; float b[3], c[3], d[3]; fairing_context->adjacents_coords_from_loop(l_index, b, c); diff --git a/source/blender/blenkernel/intern/mesh_mapping.cc b/source/blender/blenkernel/intern/mesh_mapping.cc index 29655e7266c..4d2d7448d22 100644 --- a/source/blender/blenkernel/intern/mesh_mapping.cc +++ b/source/blender/blenkernel/intern/mesh_mapping.cc @@ -183,74 +183,6 @@ void BKE_mesh_uv_vert_map_free(UvVertMap *vmap) } } -/** - * Generates a map where the key is the vertex and the value is a list - * of polys or loops that use that vertex as a corner. The lists are allocated - * from one memory pool. - * - * Wrapped by #BKE_mesh_vert_poly_map_create & BKE_mesh_vert_loop_map_create - */ -static void mesh_vert_poly_or_loop_map_create(MeshElemMap **r_map, - int **r_mem, - const blender::OffsetIndices polys, - const int *corner_verts, - int totvert, - const bool do_loops) -{ - MeshElemMap *map = MEM_cnew_array(size_t(totvert), __func__); - int *indices, *index_iter; - - indices = static_cast(MEM_mallocN(sizeof(int) * size_t(polys.total_size()), __func__)); - index_iter = indices; - - /* Count number of polys for each vertex */ - for (const int64_t i : polys.index_range()) { - for (const int64_t corner : polys[i]) { - map[corner_verts[corner]].count++; - } - } - - /* Assign indices mem */ - for (int64_t i = 0; i < totvert; i++) { - map[i].indices = index_iter; - index_iter += map[i].count; - - /* Reset 'count' for use as index in last loop */ - map[i].count = 0; - } - - /* Find the users */ - for (const int64_t i : polys.index_range()) { - for (const int64_t corner : polys[i]) { - const int v = corner_verts[corner]; - - map[v].indices[map[v].count] = do_loops ? int(corner) : int(i); - map[v].count++; - } - } - - *r_map = map; - *r_mem = indices; -} - -void BKE_mesh_vert_poly_map_create(MeshElemMap **r_map, - int **r_mem, - const blender::OffsetIndices polys, - const int *corner_verts, - int totvert) -{ - mesh_vert_poly_or_loop_map_create(r_map, r_mem, polys, corner_verts, totvert, false); -} - -void BKE_mesh_vert_loop_map_create(MeshElemMap **r_map, - int **r_mem, - const blender::OffsetIndices polys, - const int *corner_verts, - int totvert) -{ - mesh_vert_poly_or_loop_map_create(r_map, r_mem, polys, corner_verts, totvert, true); -} - void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map, int **r_mem, const int totvert, @@ -294,166 +226,6 @@ void BKE_mesh_vert_looptri_map_create(MeshElemMap **r_map, *r_mem = indices; } -void BKE_mesh_vert_edge_map_create( - MeshElemMap **r_map, int **r_mem, const blender::int2 *edges, int totvert, int totedge) -{ - MeshElemMap *map = MEM_cnew_array(size_t(totvert), __func__); - int *indices = static_cast(MEM_mallocN(sizeof(int[2]) * size_t(totedge), __func__)); - int *i_pt = indices; - - int i; - - /* Count number of edges for each vertex */ - for (i = 0; i < totedge; i++) { - map[edges[i][0]].count++; - map[edges[i][1]].count++; - } - - /* Assign indices mem */ - for (i = 0; i < totvert; i++) { - map[i].indices = i_pt; - i_pt += map[i].count; - - /* Reset 'count' for use as index in last loop */ - map[i].count = 0; - } - - /* Find the users */ - for (i = 0; i < totedge; i++) { - const int v[2] = {edges[i][0], edges[i][1]}; - - map[v[0]].indices[map[v[0]].count] = i; - map[v[1]].indices[map[v[1]].count] = i; - - map[v[0]].count++; - map[v[1]].count++; - } - - *r_map = map; - *r_mem = indices; -} - -void BKE_mesh_vert_edge_vert_map_create( - MeshElemMap **r_map, int **r_mem, const blender::int2 *edges, int totvert, int totedge) -{ - MeshElemMap *map = MEM_cnew_array(size_t(totvert), __func__); - int *indices = static_cast(MEM_mallocN(sizeof(int[2]) * size_t(totedge), __func__)); - int *i_pt = indices; - - int i; - - /* Count number of edges for each vertex */ - for (i = 0; i < totedge; i++) { - map[edges[i][0]].count++; - map[edges[i][1]].count++; - } - - /* Assign indices mem */ - for (i = 0; i < totvert; i++) { - map[i].indices = i_pt; - i_pt += map[i].count; - - /* Reset 'count' for use as index in last loop */ - map[i].count = 0; - } - - /* Find the users */ - for (i = 0; i < totedge; i++) { - const int v[2] = {edges[i][0], edges[i][1]}; - - map[v[0]].indices[map[v[0]].count] = int(v[1]); - map[v[1]].indices[map[v[1]].count] = int(v[0]); - - map[v[0]].count++; - map[v[1]].count++; - } - - *r_map = map; - *r_mem = indices; -} - -void BKE_mesh_edge_loop_map_create(MeshElemMap **r_map, - int **r_mem, - const int totedge, - const blender::OffsetIndices polys, - const int *corner_edges, - const int totloop) -{ - using namespace blender; - MeshElemMap *map = MEM_cnew_array(size_t(totedge), __func__); - int *indices = static_cast(MEM_mallocN(sizeof(int) * size_t(totloop) * 2, __func__)); - int *index_step; - - /* count face users */ - for (const int64_t i : IndexRange(totloop)) { - map[corner_edges[i]].count += 2; - } - - /* create offsets */ - index_step = indices; - for (int i = 0; i < totedge; i++) { - map[i].indices = index_step; - index_step += map[i].count; - - /* re-count, using this as an index below */ - map[i].count = 0; - } - - /* assign loop-edge users */ - for (const int64_t i : polys.index_range()) { - MeshElemMap *map_ele; - for (const int64_t corner : polys[i]) { - map_ele = &map[corner_edges[corner]]; - map_ele->indices[map_ele->count++] = int(corner); - map_ele->indices[map_ele->count++] = int(corner) + 1; - } - /* last edge/loop of poly, must point back to first loop! */ - map_ele->indices[map_ele->count - 1] = int(polys[i].start()); - } - - *r_map = map; - *r_mem = indices; -} - -void BKE_mesh_edge_poly_map_create(MeshElemMap **r_map, - int **r_mem, - const int totedge, - const blender::OffsetIndices polys, - const int *corner_edges, - const int totloop) -{ - MeshElemMap *map = MEM_cnew_array(size_t(totedge), __func__); - int *indices = static_cast(MEM_mallocN(sizeof(int) * size_t(totloop), __func__)); - int *index_step; - - /* count face users */ - for (const int64_t i : blender::IndexRange(totloop)) { - map[corner_edges[i]].count++; - } - - /* create offsets */ - index_step = indices; - for (int i = 0; i < totedge; i++) { - map[i].indices = index_step; - index_step += map[i].count; - - /* re-count, using this as an index below */ - map[i].count = 0; - } - - /* assign poly-edge users */ - for (const int64_t i : polys.index_range()) { - for (const int64_t corner : polys[i]) { - const int edge_i = corner_edges[corner]; - MeshElemMap *map_ele = &map[edge_i]; - map_ele->indices[map_ele->count++] = int(i); - } - } - - *r_map = map; - *r_mem = indices; -} - void BKE_mesh_origindex_map_create(MeshElemMap **r_map, int **r_mem, const int totsource, @@ -522,7 +294,17 @@ void BKE_mesh_origindex_map_create_looptri(MeshElemMap **r_map, *r_mem = indices; } -namespace blender::bke::mesh_topology { +namespace blender::bke::mesh { + +static Array create_reverse_offsets(const Span indices, const int items_num) +{ + Array offsets(items_num + 1, 0); + for (const int i : indices) { + offsets[i]++; + } + offset_indices::accumulate_counts_to_offsets(offsets); + return offsets; +} Array build_loop_to_poly_map(const OffsetIndices polys) { @@ -531,72 +313,97 @@ Array build_loop_to_poly_map(const OffsetIndices polys) return map; } -Array> build_vert_to_edge_map(const Span edges, const int verts_num) +GroupedSpan build_vert_to_edge_map(const Span edges, + const int verts_num, + Array &r_offsets, + Array &r_indices) { - Array> map(verts_num); - for (const int64_t i : edges.index_range()) { - map[edges[i][0]].append(int(i)); - map[edges[i][1]].append(int(i)); - } - return map; -} + r_offsets = create_reverse_offsets(edges.cast(), verts_num); + r_indices.reinitialize(r_offsets.last()); + Array counts(verts_num, 0); -Array> build_vert_to_poly_map(const OffsetIndices polys, - const Span corner_verts, - int verts_num) -{ - Array> map(verts_num); - for (const int64_t i : polys.index_range()) { - for (const int64_t vert_i : corner_verts.slice(polys[i])) { - map[int(vert_i)].append(int(i)); + for (const int64_t edge_i : edges.index_range()) { + for (const int vert : {edges[edge_i][0], edges[edge_i][1]}) { + r_indices[r_offsets[vert] + counts[vert]] = int(edge_i); + counts[vert]++; } } - return map; + return {OffsetIndices(r_offsets), r_indices}; } -Array> build_vert_to_loop_map(const Span corner_verts, const int verts_num) +GroupedSpan build_vert_to_poly_map(const OffsetIndices polys, + const Span corner_verts, + const int verts_num, + Array &r_offsets, + Array &r_indices) { - Array> map(verts_num); - for (const int64_t i : corner_verts.index_range()) { - map[corner_verts[i]].append(int(i)); - } - return map; -} + r_offsets = create_reverse_offsets(corner_verts, verts_num); + r_indices.reinitialize(r_offsets.last()); + Array counts(verts_num, 0); -Array> build_edge_to_loop_map(const Span corner_edges, const int edges_num) -{ - Array> map(edges_num); - for (const int64_t i : corner_edges.index_range()) { - map[corner_edges[i]].append(int(i)); - } - return map; -} - -Array> build_edge_to_poly_map(const OffsetIndices polys, - const Span corner_edges, - const int edges_num) -{ - Array> map(edges_num); - for (const int64_t i : polys.index_range()) { - for (const int edge : corner_edges.slice(polys[i])) { - map[edge].append(int(i)); + for (const int64_t poly_i : polys.index_range()) { + for (const int vert : corner_verts.slice(polys[poly_i])) { + r_indices[r_offsets[vert] + counts[vert]] = int(poly_i); + counts[vert]++; } } - return map; + return {OffsetIndices(r_offsets), r_indices}; } -Vector> build_edge_to_loop_map_resizable(const Span corner_edges, - const int edges_num) - +GroupedSpan build_vert_to_loop_map(const Span corner_verts, + const int verts_num, + Array &r_offsets, + Array &r_indices) { - Vector> map(edges_num); - for (const int64_t i : corner_edges.index_range()) { - map[corner_edges[i]].append(int(i)); + r_offsets = create_reverse_offsets(corner_verts, verts_num); + r_indices.reinitialize(r_offsets.last()); + Array counts(verts_num, 0); + + for (const int64_t corner : corner_verts.index_range()) { + const int vert = corner_verts[corner]; + r_indices[r_offsets[vert] + counts[vert]] = int(corner); + counts[vert]++; } - return map; + return {OffsetIndices(r_offsets), r_indices}; } -} // namespace blender::bke::mesh_topology +GroupedSpan build_edge_to_loop_map(const Span corner_edges, + const int edges_num, + Array &r_offsets, + Array &r_indices) +{ + r_offsets = create_reverse_offsets(corner_edges, edges_num); + r_indices.reinitialize(r_offsets.last()); + Array counts(edges_num, 0); + + for (const int64_t corner : corner_edges.index_range()) { + const int edge = corner_edges[corner]; + r_indices[r_offsets[edge] + counts[edge]] = int(corner); + counts[edge]++; + } + return {OffsetIndices(r_offsets), r_indices}; +} + +GroupedSpan build_edge_to_poly_map(const OffsetIndices polys, + const Span corner_edges, + const int edges_num, + Array &r_offsets, + Array &r_indices) +{ + r_offsets = create_reverse_offsets(corner_edges, edges_num); + r_indices.reinitialize(r_offsets.last()); + Array counts(edges_num, 0); + + for (const int64_t poly_i : polys.index_range()) { + for (const int edge : corner_edges.slice(polys[poly_i])) { + r_indices[r_offsets[edge] + counts[edge]] = int(poly_i); + counts[edge]++; + } + } + return {OffsetIndices(r_offsets), r_indices}; +} + +} // namespace blender::bke::mesh /** \} */ @@ -613,12 +420,12 @@ using MeshRemap_CheckIslandBoundary = int loop_index, int edge_index, int edge_user_count, - const MeshElemMap &edge_poly_map_elem)>; + const blender::Span edge_poly_map_elem)>; static void poly_edge_loop_islands_calc(const int totedge, const blender::OffsetIndices polys, const blender::Span corner_edges, - MeshElemMap *edge_poly_map, + blender::GroupedSpan edge_poly_map, const bool use_bitflags, MeshRemap_CheckIslandBoundary edge_boundary_check, int **r_poly_groups, @@ -641,9 +448,6 @@ static void poly_edge_loop_islands_calc(const int totedge, int tot_group = 0; bool group_id_overflow = false; - /* map vars */ - int *edge_poly_mem = nullptr; - if (polys.size() == 0) { *r_totgroup = 0; *r_poly_groups = nullptr; @@ -659,13 +463,11 @@ static void poly_edge_loop_islands_calc(const int totedge, *r_totedgeborder = 0; } - if (!edge_poly_map) { - BKE_mesh_edge_poly_map_create(&edge_poly_map, - &edge_poly_mem, - totedge, - polys, - corner_edges.data(), - int(corner_edges.size())); + blender::Array edge_to_poly_src_offsets; + blender::Array edge_to_poly_src_indices; + if (edge_poly_map.is_empty()) { + edge_poly_map = blender::bke::mesh::build_edge_to_poly_map( + polys, corner_edges, totedge, edge_to_poly_src_offsets, edge_to_poly_src_indices); } poly_groups = static_cast(MEM_callocN(sizeof(int) * size_t(polys.size()), __func__)); @@ -703,9 +505,9 @@ static void poly_edge_loop_islands_calc(const int totedge, for (const int64_t loop : polys[poly]) { const int edge = corner_edges[loop]; /* loop over poly users */ - const MeshElemMap &map_ele = edge_poly_map[edge]; - const int *p = map_ele.indices; - int i = map_ele.count; + const blender::Span map_ele = edge_poly_map[edge]; + const int *p = map_ele.data(); + int i = int(map_ele.size()); if (!edge_boundary_check(poly, int(loop), edge, i, map_ele)) { for (; i--; p++) { /* if we meet other non initialized its a bug */ @@ -790,10 +592,6 @@ static void poly_edge_loop_islands_calc(const int totedge, tot_group++; } - if (edge_poly_mem) { - MEM_freeN(edge_poly_map); - MEM_freeN(edge_poly_mem); - } MEM_freeN(poly_stack); *r_totgroup = tot_group; @@ -822,16 +620,15 @@ int *BKE_mesh_calc_smoothgroups(const int totedge, const int /*loop_index*/, const int edge_index, const int edge_user_count, - const MeshElemMap &edge_poly_map_elem) { + const blender::Span edge_poly_map_elem) { /* Edge is sharp if one of its polys is flat, or edge itself is sharp, * or edge is not used by exactly two polygons. */ if (poly_is_smooth(poly_index) && !(sharp_edges && sharp_edges[edge_index]) && (edge_user_count == 2)) { /* In that case, edge appears to be smooth, but we need to check its other poly too. */ - const int other_poly_index = (poly_index == edge_poly_map_elem.indices[0]) ? - edge_poly_map_elem.indices[1] : - edge_poly_map_elem.indices[0]; + const int other_poly_index = (poly_index == edge_poly_map_elem[0]) ? edge_poly_map_elem[1] : + edge_poly_map_elem[0]; return !poly_is_smooth(other_poly_index); } return true; @@ -840,7 +637,7 @@ int *BKE_mesh_calc_smoothgroups(const int totedge, poly_edge_loop_islands_calc(totedge, blender::Span(poly_offsets, totpoly + 1), {corner_edges, totloop}, - nullptr, + {}, use_bitflags, poly_is_island_boundary_smooth, &poly_groups, @@ -975,16 +772,10 @@ static bool mesh_calc_islands_loop_poly_uv(const int totedge, const float (*luvs)[2], MeshIslandStore *r_island_store) { + using namespace blender; int *poly_groups = nullptr; int num_poly_groups; - /* map vars */ - MeshElemMap *edge_poly_map; - int *edge_poly_mem; - - MeshElemMap *edge_loop_map; - int *edge_loop_mem; - int *poly_indices; int *loop_indices; int num_pidx, num_lidx; @@ -1004,12 +795,17 @@ static bool mesh_calc_islands_loop_poly_uv(const int totedge, BKE_mesh_loop_islands_init( r_island_store, MISLAND_TYPE_LOOP, totloop, MISLAND_TYPE_POLY, MISLAND_TYPE_EDGE); - BKE_mesh_edge_poly_map_create( - &edge_poly_map, &edge_poly_mem, totedge, polys, corner_edges, totloop); + Array edge_to_poly_offsets; + Array edge_to_poly_indices; + const GroupedSpan edge_to_poly_map = bke::mesh::build_edge_to_poly_map( + polys, {corner_edges, totloop}, totedge, edge_to_poly_offsets, edge_to_poly_indices); + Array edge_to_loop_offsets; + Array edge_to_loop_indices; + GroupedSpan edge_to_loop_map; if (luvs) { - BKE_mesh_edge_loop_map_create( - &edge_loop_map, &edge_loop_mem, totedge, polys, corner_edges, totloop); + edge_to_loop_map = bke::mesh::build_edge_to_loop_map( + {corner_edges, totloop}, totedge, edge_to_loop_offsets, edge_to_loop_indices); } /* TODO: I'm not sure edge seam flag is enough to define UV islands? @@ -1022,29 +818,29 @@ static bool mesh_calc_islands_loop_poly_uv(const int totedge, const int loop_index, const int edge_index, const int /*edge_user_count*/, - const MeshElemMap & /*edge_poly_map_elem*/) -> bool { + const Span /*edge_poly_map_elem*/) -> bool { if (luvs) { - const MeshElemMap &edge_to_loops = edge_loop_map[corner_edges[loop_index]]; + const Span edge_to_loops = edge_to_loop_map[corner_edges[loop_index]]; - BLI_assert(edge_to_loops.count >= 2 && (edge_to_loops.count % 2) == 0); + BLI_assert(edge_to_loops.size() >= 2 && (edge_to_loops.size() % 2) == 0); - const int v1 = corner_verts[edge_to_loops.indices[0]]; - const int v2 = corner_verts[edge_to_loops.indices[1]]; - const float *uvco_v1 = luvs[edge_to_loops.indices[0]]; - const float *uvco_v2 = luvs[edge_to_loops.indices[1]]; - for (int i = 2; i < edge_to_loops.count; i += 2) { - if (corner_verts[edge_to_loops.indices[i]] == v1) { - if (!equals_v2v2(uvco_v1, luvs[edge_to_loops.indices[i]]) || - !equals_v2v2(uvco_v2, luvs[edge_to_loops.indices[i + 1]])) + const int v1 = corner_verts[edge_to_loops[0]]; + const int v2 = corner_verts[edge_to_loops[1]]; + const float *uvco_v1 = luvs[edge_to_loops[0]]; + const float *uvco_v2 = luvs[edge_to_loops[1]]; + for (int i = 2; i < edge_to_loops.size(); i += 2) { + if (corner_verts[edge_to_loops[i]] == v1) { + if (!equals_v2v2(uvco_v1, luvs[edge_to_loops[i]]) || + !equals_v2v2(uvco_v2, luvs[edge_to_loops[i + 1]])) { return true; } } else { - BLI_assert(corner_verts[edge_to_loops.indices[i]] == v2); + BLI_assert(corner_verts[edge_to_loops[i]] == v2); UNUSED_VARS_NDEBUG(v2); - if (!equals_v2v2(uvco_v2, luvs[edge_to_loops.indices[i]]) || - !equals_v2v2(uvco_v1, luvs[edge_to_loops.indices[i + 1]])) + if (!equals_v2v2(uvco_v2, luvs[edge_to_loops[i]]) || + !equals_v2v2(uvco_v1, luvs[edge_to_loops[i + 1]])) { return true; } @@ -1060,7 +856,7 @@ static bool mesh_calc_islands_loop_poly_uv(const int totedge, poly_edge_loop_islands_calc(totedge, polys, {corner_edges, totloop}, - edge_poly_map, + edge_to_poly_map, false, mesh_check_island_boundary_uv, &poly_groups, @@ -1069,10 +865,6 @@ static bool mesh_calc_islands_loop_poly_uv(const int totedge, &num_edge_borders); if (!num_poly_groups) { - /* Should never happen... */ - MEM_freeN(edge_poly_map); - MEM_freeN(edge_poly_mem); - if (edge_borders) { MEM_freeN(edge_borders); } @@ -1126,14 +918,6 @@ static bool mesh_calc_islands_loop_poly_uv(const int totedge, edge_innercut_indices); } - MEM_freeN(edge_poly_map); - MEM_freeN(edge_poly_mem); - - if (luvs) { - MEM_freeN(edge_loop_map); - MEM_freeN(edge_loop_mem); - } - MEM_freeN(poly_indices); MEM_freeN(loop_indices); MEM_freeN(poly_groups); diff --git a/source/blender/blenkernel/intern/mesh_merge_customdata.cc b/source/blender/blenkernel/intern/mesh_merge_customdata.cc index a135a7e7d55..45c82f2fff4 100644 --- a/source/blender/blenkernel/intern/mesh_merge_customdata.cc +++ b/source/blender/blenkernel/intern/mesh_merge_customdata.cc @@ -113,10 +113,10 @@ void BKE_mesh_merge_customdata_for_apply_modifier(Mesh *me) return; } - int *vert_map_mem; - struct MeshElemMap *vert_to_loop; - BKE_mesh_vert_loop_map_create( - &vert_to_loop, &vert_map_mem, me->polys(), me->corner_verts().data(), me->totvert); + 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); Vector mloopuv_layers; mloopuv_layers.reserve(mloopuv_layers_num); @@ -130,12 +130,7 @@ void BKE_mesh_merge_customdata_for_apply_modifier(Mesh *me) threading::parallel_for(IndexRange(me->totvert), 1024, [&](IndexRange range) { for (const int64_t v_index : range) { - MeshElemMap &loops_for_vert = vert_to_loop[v_index]; - Span loops_for_vert_span(loops_for_vert.indices, loops_for_vert.count); - merge_uvs_for_vertex(loops_for_vert_span, mloopuv_layers_as_span); + merge_uvs_for_vertex(vert_to_loop[v_index], mloopuv_layers_as_span); } }); - - MEM_freeN(vert_to_loop); - MEM_freeN(vert_map_mem); } diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index 78efd3e2256..725d25e1fb2 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -819,7 +819,7 @@ void edges_sharp_from_angle_set(const OffsetIndices polys, Array edge_to_loops(sharp_edges.size(), int2(0)); /* Simple mapping from a loop to its polygon index. */ - const Array loop_to_poly = mesh_topology::build_loop_to_poly_map(polys); + const Array loop_to_poly = build_loop_to_poly_map(polys); mesh_edges_sharp_tag(polys, corner_verts, @@ -1318,7 +1318,7 @@ void normals_calc_loop(const Span vert_positions, Span loop_to_poly; Array local_loop_to_poly_map; if (loop_to_poly_map.is_empty()) { - local_loop_to_poly_map = mesh_topology::build_loop_to_poly_map(polys); + local_loop_to_poly_map = build_loop_to_poly_map(polys); loop_to_poly = local_loop_to_poly_map; } else { @@ -1419,11 +1419,8 @@ static void reverse_index_array(const Span item_indices, Array &r_reverse_indices) { r_offsets = Array(items_num + 1, 0); - for (const int index : item_indices) { - r_offsets[index]++; - } + offset_indices::build_reverse_offsets(item_indices, r_offsets); - offset_indices::accumulate_counts_to_offsets(r_offsets); r_reverse_indices.reinitialize(r_offsets.last()); Array count_per_item(items_num, 0); @@ -1465,7 +1462,7 @@ static void mesh_normals_loop_custom_set(Span positions, CornerNormalSpaceArray lnors_spacearr; BitVector<> done_loops(corner_verts.size(), false); Array loop_normals(corner_verts.size()); - const Array loop_to_poly = mesh_topology::build_loop_to_poly_map(polys); + const Array loop_to_poly = build_loop_to_poly_map(polys); /* In this case we always consider split nors as ON, * and do not want to use angle to define smooth fans! */ const bool use_split_normals = true; diff --git a/source/blender/blenkernel/intern/mesh_remap.cc b/source/blender/blenkernel/intern/mesh_remap.cc index 207ea5bb327..f1134290817 100644 --- a/source/blender/blenkernel/intern/mesh_remap.cc +++ b/source/blender/blenkernel/intern/mesh_remap.cc @@ -693,6 +693,7 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode, Mesh *me_dst, MeshPairRemap *r_map) { + using namespace blender; const float full_weight = 1.0f; const float max_dist_sq = max_dist * max_dist; int i; @@ -719,9 +720,6 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode, const blender::Span edges_src = me_src->edges(); const float(*positions_src)[3] = BKE_mesh_vert_positions(me_src); - MeshElemMap *vert_to_edge_src_map; - int *vert_to_edge_src_map_mem; - struct HitData { float hit_dist; int index; @@ -733,11 +731,10 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode, v_dst_to_src_map[i].hit_dist = -1.0f; } - BKE_mesh_vert_edge_map_create(&vert_to_edge_src_map, - &vert_to_edge_src_map_mem, - edges_src.data(), - num_verts_src, - int(edges_src.size())); + Array vert_to_edge_src_offsets; + Array vert_to_edge_src_indices; + const GroupedSpan vert_to_edge_src_map = bke::mesh::build_vert_to_edge_map( + edges_src, num_verts_src, vert_to_edge_src_offsets, vert_to_edge_src_indices); BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_VERTS, 2); nearest.index = -1; @@ -778,14 +775,15 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode, const int vidx_dst = j ? e_dst[0] : e_dst[1]; const float first_dist = v_dst_to_src_map[vidx_dst].hit_dist; const int vidx_src = v_dst_to_src_map[vidx_dst].index; - int *eidx_src, k; + const int *eidx_src; + int k; if (vidx_src < 0) { continue; } - eidx_src = vert_to_edge_src_map[vidx_src].indices; - k = vert_to_edge_src_map[vidx_src].count; + eidx_src = vert_to_edge_src_map[vidx_src].data(); + k = int(vert_to_edge_src_map[vidx_src].size()); for (; k--; eidx_src++) { const blender::int2 &edge_src = edges_src[*eidx_src]; @@ -838,8 +836,6 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode, } MEM_freeN(v_dst_to_src_map); - MEM_freeN(vert_to_edge_src_map); - MEM_freeN(vert_to_edge_src_map_mem); } else if (mode == MREMAP_MODE_EDGE_NEAREST) { BKE_bvhtree_from_mesh_get(&treedata, me_src, BVHTREE_FROM_EDGES, 2); @@ -1036,25 +1032,26 @@ void BKE_mesh_remap_calc_edges_from_mesh(const int mode, #define POLY_CENTER_INIT 1 #define POLY_COMPLETE 2 -static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands, - const int island_index, - BLI_AStarGraph *as_graph, - const blender::Span positions, - const blender::OffsetIndices polys, - const blender::Span corner_verts, - const int edge_idx, - BLI_bitmap *done_edges, - MeshElemMap *edge_to_poly_map, - const bool is_edge_innercut, - const int *poly_island_index_map, - float (*poly_centers)[3], - uchar *poly_status) +static void mesh_island_to_astar_graph_edge_process( + MeshIslandStore *islands, + const int island_index, + BLI_AStarGraph *as_graph, + const blender::Span positions, + const blender::OffsetIndices polys, + const blender::Span corner_verts, + const int edge_idx, + BLI_bitmap *done_edges, + const blender::GroupedSpan edge_to_poly_map, + const bool is_edge_innercut, + const int *poly_island_index_map, + float (*poly_centers)[3], + uchar *poly_status) { - blender::Array poly_island_indices(edge_to_poly_map[edge_idx].count); + blender::Array poly_island_indices(edge_to_poly_map[edge_idx].size()); int i, j; - for (i = 0; i < edge_to_poly_map[edge_idx].count; i++) { - const int pidx = edge_to_poly_map[edge_idx].indices[i]; + for (i = 0; i < edge_to_poly_map[edge_idx].size(); i++) { + const int pidx = edge_to_poly_map[edge_idx][i]; const blender::IndexRange poly = polys[pidx]; const int pidx_isld = islands ? poly_island_index_map[pidx] : pidx; void *custom_data = is_edge_innercut ? POINTER_FROM_INT(edge_idx) : POINTER_FROM_INT(-1); @@ -1098,7 +1095,7 @@ static void mesh_island_to_astar_graph_edge_process(MeshIslandStore *islands, static void mesh_island_to_astar_graph(MeshIslandStore *islands, const int island_index, const blender::Span positions, - MeshElemMap *edge_to_poly_map, + const blender::GroupedSpan edge_to_poly_map, const int numedges, const blender::OffsetIndices polys, const blender::Span corner_verts, @@ -1242,6 +1239,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, const float islands_precision_src, MeshPairRemap *r_map) { + using namespace blender; const float full_weight = 1.0f; const float max_dist_sq = max_dist * max_dist; @@ -1285,12 +1283,18 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, blender::Array poly_cents_src; - MeshElemMap *vert_to_loop_map_src = nullptr; - int *vert_to_loop_map_src_buff = nullptr; - MeshElemMap *vert_to_poly_map_src = nullptr; - int *vert_to_poly_map_src_buff = nullptr; - MeshElemMap *edge_to_poly_map_src = nullptr; - int *edge_to_poly_map_src_buff = nullptr; + Array vert_to_loop_src_offsets; + Array vert_to_loop_src_indices; + GroupedSpan vert_to_loop_map_src; + + Array vert_to_poly_src_offsets; + Array vert_to_poly_src_indices; + GroupedSpan vert_to_poly_map_src; + + Array edge_to_poly_src_offsets; + Array edge_to_poly_src_indices; + GroupedSpan edge_to_poly_map_src; + MeshElemMap *poly_to_looptri_map_src = nullptr; int *poly_to_looptri_map_src_buff = nullptr; @@ -1386,29 +1390,27 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, } if (use_from_vert) { - BKE_mesh_vert_loop_map_create(&vert_to_loop_map_src, - &vert_to_loop_map_src_buff, - polys_src, - corner_verts_src.data(), - num_verts_src); + 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); + if (mode & MREMAP_USE_POLY) { - BKE_mesh_vert_poly_map_create(&vert_to_poly_map_src, - &vert_to_poly_map_src_buff, - polys_src, - corner_verts_src.data(), - num_verts_src); + vert_to_poly_map_src = bke::mesh::build_vert_to_poly_map(polys_src, + corner_verts_src, + num_verts_src, + vert_to_poly_src_offsets, + vert_to_poly_src_indices); } } /* Needed for islands (or plain mesh) to AStar graph conversion. */ - BKE_mesh_edge_poly_map_create(&edge_to_poly_map_src, - &edge_to_poly_map_src_buff, - int(edges_src.size()), - polys_src, - corner_edges_src.data(), - int(corner_edges_src.size())); + edge_to_poly_map_src = bke::mesh::build_edge_to_poly_map(polys_src, + corner_edges_src, + int(edges_src.size()), + edge_to_poly_src_offsets, + edge_to_poly_src_indices); + if (use_from_vert) { - loop_to_poly_map_src = blender::bke::mesh_topology::build_loop_to_poly_map(polys_src); + loop_to_poly_map_src = blender::bke::mesh::build_loop_to_poly_map(polys_src); poly_cents_src.reinitialize(polys_src.size()); for (const int64_t i : polys_src.index_range()) { poly_cents_src[i] = blender::bke::mesh::poly_center_calc( @@ -1583,7 +1585,7 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, for (plidx_dst = 0; plidx_dst < poly_dst.size(); plidx_dst++) { const int vert_dst = corner_verts_dst[poly_dst.start() + plidx_dst]; if (use_from_vert) { - MeshElemMap *vert_to_refelem_map_src = nullptr; + blender::Span vert_to_refelem_map_src; copy_v3_v3(tmp_co, vert_positions_dst[vert_dst]); nearest.index = -1; @@ -1608,16 +1610,15 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, } nor_dst = &tmp_no; nors_src = loop_normals_src; - vert_to_refelem_map_src = vert_to_loop_map_src; + vert_to_refelem_map_src = vert_to_loop_map_src[nearest.index]; } else { /* if (mode == MREMAP_MODE_LOOP_NEAREST_POLYNOR) { */ nor_dst = &pnor_dst; nors_src = poly_normals_src; - vert_to_refelem_map_src = vert_to_poly_map_src; + vert_to_refelem_map_src = vert_to_poly_map_src[nearest.index]; } - for (int i = vert_to_refelem_map_src[nearest.index].count; i--;) { - const int index_src = vert_to_refelem_map_src[nearest.index].indices[i]; + for (const int index_src : vert_to_refelem_map_src) { BLI_assert(index_src != -1); const float dot = dot_v3v3(nors_src[index_src], *nor_dst); @@ -2084,24 +2085,6 @@ void BKE_mesh_remap_calc_loops_from_mesh(const int mode, BLI_astar_solution_free(&as_solution); } - if (vert_to_loop_map_src) { - MEM_freeN(vert_to_loop_map_src); - } - if (vert_to_loop_map_src_buff) { - MEM_freeN(vert_to_loop_map_src_buff); - } - if (vert_to_poly_map_src) { - MEM_freeN(vert_to_poly_map_src); - } - if (vert_to_poly_map_src_buff) { - MEM_freeN(vert_to_poly_map_src_buff); - } - if (edge_to_poly_map_src) { - MEM_freeN(edge_to_poly_map_src); - } - if (edge_to_poly_map_src_buff) { - MEM_freeN(edge_to_poly_map_src_buff); - } if (poly_to_looptri_map_src) { MEM_freeN(poly_to_looptri_map_src); } diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index b294de04a11..f0ad83e155c 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -365,10 +365,13 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) int i = 0; const CustomDataLayer *layer; - MeshElemMap *source_lmap = nullptr; - int *source_lmap_mem = nullptr; - MeshElemMap *target_lmap = nullptr; - int *target_lmap_mem = nullptr; + Array source_vert_to_loop_offsets; + Array source_vert_to_loop_indices; + blender::GroupedSpan source_lmap; + + Array target_vert_to_loop_offsets; + Array target_vert_to_loop_indices; + blender::GroupedSpan target_lmap; while ((layer = BKE_id_attribute_from_index( const_cast(&source->id), i++, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL))) @@ -412,18 +415,15 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) } else { /* Lazily init vertex -> loop maps. */ - if (!source_lmap) { - BKE_mesh_vert_loop_map_create(&source_lmap, - &source_lmap_mem, - source->polys(), - source->corner_verts().data(), - source->totvert); - - BKE_mesh_vert_loop_map_create(&target_lmap, - &target_lmap_mem, - target->polys(), - target->corner_verts().data(), - target->totvert); + if (source_lmap.is_empty()) { + source_lmap = blender::bke::mesh::build_vert_to_loop_map(source->corner_verts(), + source->totvert, + source_vert_to_loop_offsets, + source_vert_to_loop_indices); + target_lmap = blender::bke::mesh::build_vert_to_loop_map(target->corner_verts(), + target->totvert, + target_vert_to_loop_offsets, + target_vert_to_loop_indices); } blender::threading::parallel_for( @@ -439,10 +439,10 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) continue; } - MeshElemMap *source_loops = source_lmap + nearest.index; - MeshElemMap *target_loops = target_lmap + i; + const Span source_loops = source_lmap[nearest.index]; + const Span target_loops = target_lmap[i]; - if (target_loops->count == 0 || source_loops->count == 0) { + if (target_loops.size() == 0 || source_loops.size() == 0) { continue; } @@ -453,18 +453,17 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) CustomData_interp(source_cdata, target_cdata, - source_loops->indices, + source_loops.data(), nullptr, nullptr, - source_loops->count, - target_loops->indices[0]); + source_loops.size(), + target_loops[0]); - void *elem = POINTER_OFFSET(target_data, - size_t(target_loops->indices[0]) * data_size); + void *elem = POINTER_OFFSET(target_data, size_t(target_loops[0]) * data_size); /* Copy to rest of target loops. */ - for (int j = 1; j < target_loops->count; j++) { - memcpy(POINTER_OFFSET(target_data, size_t(target_loops->indices[j]) * data_size), + for (int j = 1; j < target_loops.size(); j++) { + memcpy(POINTER_OFFSET(target_data, size_t(target_loops[j]) * data_size), elem, data_size); } @@ -483,10 +482,6 @@ void BKE_remesh_reproject_vertex_paint(Mesh *target, const Mesh *source) target->default_color_attribute = BLI_strdup(source->default_color_attribute); } - MEM_SAFE_FREE(source_lmap); - MEM_SAFE_FREE(source_lmap_mem); - MEM_SAFE_FREE(target_lmap); - MEM_SAFE_FREE(target_lmap_mem); free_bvhtree_from_mesh(&bvhtree); } diff --git a/source/blender/blenkernel/intern/multires.cc b/source/blender/blenkernel/intern/multires.cc index 078ad9604ee..07ab12259e4 100644 --- a/source/blender/blenkernel/intern/multires.cc +++ b/source/blender/blenkernel/intern/multires.cc @@ -471,9 +471,9 @@ void multires_force_sculpt_rebuild(Object *object) object->sculpt->pbvh = nullptr; } - MEM_SAFE_FREE(ss->pmap); - - MEM_SAFE_FREE(ss->pmap_mem); + ss->vert_to_poly_indices = {}; + ss->vert_to_poly_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 359e271b44b..f3d5bfe82ed 100644 --- a/source/blender/blenkernel/intern/multires_reshape_apply_base.cc +++ b/source/blender/blenkernel/intern/multires_reshape_apply_base.cc @@ -70,13 +70,14 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape float(*base_positions)[3] = BKE_mesh_vert_positions_for_write(base_mesh); /* Update the context in case the vertices were duplicated. */ reshape_context->base_positions = base_positions; - MeshElemMap *pmap; - int *pmap_mem; - BKE_mesh_vert_poly_map_create(&pmap, - &pmap_mem, - reshape_context->base_polys, - reshape_context->base_corner_verts.data(), - base_mesh->totvert); + blender::Array vert_to_poly_offsets; + blender::Array vert_to_poly_indices; + const blender::GroupedSpan pmap = blender::bke::mesh::build_vert_to_poly_map( + reshape_context->base_polys, + reshape_context->base_corner_verts, + base_mesh->totvert, + vert_to_poly_offsets, + vert_to_poly_indices); float(*origco)[3] = static_cast( MEM_calloc_arrayN(base_mesh->totvert, sizeof(float[3]), __func__)); @@ -88,14 +89,14 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape float avg_no[3] = {0, 0, 0}, center[3] = {0, 0, 0}, push[3]; /* Don't adjust vertices not used by at least one poly. */ - if (!pmap[i].count) { + if (!pmap[i].size()) { continue; } /* Find center. */ int tot = 0; - for (int j = 0; j < pmap[i].count; j++) { - const blender::IndexRange poly = reshape_context->base_polys[pmap[i].indices[j]]; + for (int j = 0; j < pmap[i].size(); j++) { + const blender::IndexRange poly = reshape_context->base_polys[pmap[i][j]]; /* This double counts, not sure if that's bad or good. */ for (const int corner : poly) { @@ -109,8 +110,8 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape mul_v3_fl(center, 1.0f / tot); /* Find normal. */ - for (int j = 0; j < pmap[i].count; j++) { - const blender::IndexRange poly = reshape_context->base_polys[pmap[i].indices[j]]; + for (int j = 0; j < pmap[i].size(); j++) { + const blender::IndexRange poly = reshape_context->base_polys[pmap[i][j]]; /* Set up poly, loops, and coords in order to call #bke::mesh::poly_normal_calc(). */ blender::Array poly_verts(poly.size()); @@ -142,8 +143,6 @@ void multires_reshape_apply_base_refit_base_mesh(MultiresReshapeContext *reshape } MEM_freeN(origco); - MEM_freeN(pmap); - MEM_freeN(pmap_mem); /* 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 diff --git a/source/blender/blenkernel/intern/multires_unsubdivide.cc b/source/blender/blenkernel/intern/multires_unsubdivide.cc index 6b2cb748ad0..c843313912e 100644 --- a/source/blender/blenkernel/intern/multires_unsubdivide.cc +++ b/source/blender/blenkernel/intern/multires_unsubdivide.cc @@ -950,7 +950,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_topology::build_loop_to_poly_map(original_polys); + context->loop_to_face_map = blender::bke::mesh::build_loop_to_poly_map(original_polys); } /** diff --git a/source/blender/blenkernel/intern/paint.cc b/source/blender/blenkernel/intern/paint.cc index ea55efca7aa..02e331e2cf7 100644 --- a/source/blender/blenkernel/intern/paint.cc +++ b/source/blender/blenkernel/intern/paint.cc @@ -1388,10 +1388,12 @@ void BKE_sculptsession_free_vwpaint_data(SculptSession *ss) else { return; } - MEM_SAFE_FREE(gmap->vert_to_loop); - MEM_SAFE_FREE(gmap->vert_map_mem); - MEM_SAFE_FREE(gmap->vert_to_poly); - MEM_SAFE_FREE(gmap->poly_map_mem); + gmap->vert_to_loop_offsets = {}; + gmap->vert_to_loop_indices = {}; + gmap->vert_to_loop = {}; + gmap->vert_to_poly_offsets = {}; + gmap->vert_to_poly_indices = {}; + gmap->vert_to_poly = {}; } /** @@ -1442,15 +1444,6 @@ static void sculptsession_free_pbvh(Object *object) ss->pbvh = nullptr; } - MEM_SAFE_FREE(ss->pmap); - MEM_SAFE_FREE(ss->pmap_mem); - - MEM_SAFE_FREE(ss->epmap); - MEM_SAFE_FREE(ss->epmap_mem); - - MEM_SAFE_FREE(ss->vemap); - MEM_SAFE_FREE(ss->vemap_mem); - MEM_SAFE_FREE(ss->preview_vert_list); ss->preview_vert_count = 0; @@ -1495,15 +1488,6 @@ void BKE_sculptsession_free(Object *ob) sculptsession_free_pbvh(ob); - MEM_SAFE_FREE(ss->pmap); - MEM_SAFE_FREE(ss->pmap_mem); - - MEM_SAFE_FREE(ss->epmap); - MEM_SAFE_FREE(ss->epmap_mem); - - MEM_SAFE_FREE(ss->vemap); - MEM_SAFE_FREE(ss->vemap_mem); - if (ss->bm_log) { BM_log_free(ss->bm_log); } @@ -1536,7 +1520,7 @@ void BKE_sculptsession_free(Object *ob) MEM_SAFE_FREE(ss->last_paint_canvas_key); - MEM_freeN(ss); + MEM_delete(ss); ob->sculpt = nullptr; } @@ -1766,9 +1750,12 @@ static void sculpt_update_object( sculpt_attribute_update_refs(ob); sculpt_update_persistent_base(ob); - if (ob->type == OB_MESH && !ss->pmap) { - BKE_mesh_vert_poly_map_create( - &ss->pmap, &ss->pmap_mem, me->polys(), me->corner_verts().data(), me->totvert); + if (ob->type == OB_MESH && ss->pmap.is_empty()) { + ss->pmap = blender::bke::mesh::build_vert_to_poly_map(me->polys(), + me->corner_verts(), + me->totvert, + ss->vert_to_poly_offsets, + ss->vert_to_poly_indices); } if (ss->pbvh) { diff --git a/source/blender/blenkernel/intern/pbvh.cc b/source/blender/blenkernel/intern/pbvh.cc index d4ce777027e..e7f8ecd1cf2 100644 --- a/source/blender/blenkernel/intern/pbvh.cc +++ b/source/blender/blenkernel/intern/pbvh.cc @@ -1396,7 +1396,7 @@ static void pbvh_faces_update_normals(PBVH *pbvh, Span nodes) for (const PBVHNode *node : nodes) { for (const int vert : Span(node->vert_indices, node->uniq_verts)) { if (update_tags[vert]) { - polys_to_update.add_multiple({pbvh->pmap[vert].indices, pbvh->pmap[vert].count}); + polys_to_update.add_multiple(pbvh->pmap[vert]); } } } @@ -1435,7 +1435,7 @@ static void pbvh_faces_update_normals(PBVH *pbvh, Span nodes) threading::parallel_for(verts_to_update.index_range(), 1024, [&](const IndexRange range) { for (const int vert : verts_to_update.as_span().slice(range)) { float3 normal(0.0f); - for (const int poly : Span(pbvh->pmap[vert].indices, pbvh->pmap[vert].count)) { + for (const int poly : pbvh->pmap[vert]) { normal += poly_normals[poly]; } vert_normals[vert] = math::normalize(normal); @@ -3449,7 +3449,7 @@ void BKE_pbvh_update_active_vcol(PBVH *pbvh, const Mesh *mesh) BKE_pbvh_get_color_layer(mesh, &pbvh->color_layer, &pbvh->color_domain); } -void BKE_pbvh_pmap_set(PBVH *pbvh, const MeshElemMap *pmap) +void BKE_pbvh_pmap_set(PBVH *pbvh, const blender::GroupedSpan pmap) { pbvh->pmap = pmap; } diff --git a/source/blender/blenkernel/intern/pbvh_colors.cc b/source/blender/blenkernel/intern/pbvh_colors.cc index 8ac45e9863f..faa1e20283b 100644 --- a/source/blender/blenkernel/intern/pbvh_colors.cc +++ b/source/blender/blenkernel/intern/pbvh_colors.cc @@ -89,11 +89,9 @@ static void pbvh_vertex_color_get(const PBVH &pbvh, PBVHVertRef vertex, float r_ int index = vertex.i; if (pbvh.color_domain == ATTR_DOMAIN_CORNER) { - const MeshElemMap &melem = pbvh.pmap[index]; - int count = 0; zero_v4(r_color); - for (const int i_poly : Span(melem.indices, melem.count)) { + for (const int i_poly : pbvh.pmap[index]) { const IndexRange poly = pbvh.polys[i_poly]; Span colors{static_cast(pbvh.color_layer->data) + poly.start(), poly.size()}; Span poly_verts{pbvh.corner_verts + poly.start(), poly.size()}; @@ -124,9 +122,7 @@ static void pbvh_vertex_color_set(PBVH &pbvh, PBVHVertRef vertex, const float co int index = vertex.i; if (pbvh.color_domain == ATTR_DOMAIN_CORNER) { - const MeshElemMap &melem = pbvh.pmap[index]; - - for (const int i_poly : Span(melem.indices, melem.count)) { + for (const int i_poly : pbvh.pmap[index]) { const IndexRange poly = pbvh.polys[i_poly]; MutableSpan colors{static_cast(pbvh.color_layer->data) + poly.start(), poly.size()}; Span poly_verts{pbvh.corner_verts + poly.start(), poly.size()}; diff --git a/source/blender/blenkernel/intern/pbvh_intern.hh b/source/blender/blenkernel/intern/pbvh_intern.hh index 9fcd02a6c5d..ecc940b54a2 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.hh +++ b/source/blender/blenkernel/intern/pbvh_intern.hh @@ -12,7 +12,6 @@ struct PBVHGPUFormat; struct MLoopTri; -struct MeshElemMap; /* Axis-aligned bounding box */ struct BB { @@ -206,7 +205,7 @@ struct PBVH { BMLog *bm_log; SubdivCCG *subdiv_ccg; - const MeshElemMap *pmap; + blender::GroupedSpan pmap; CustomDataLayer *color_layer; eAttrDomain color_domain; diff --git a/source/blender/blenkernel/intern/subdiv_mesh.cc b/source/blender/blenkernel/intern/subdiv_mesh.cc index afe85ff3e19..7738175c62d 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.cc +++ b/source/blender/blenkernel/intern/subdiv_mesh.cc @@ -79,8 +79,9 @@ struct SubdivMeshContext { /* Lazily initialize a map from vertices to connected edges. */ std::mutex vert_to_edge_map_mutex; - int *vert_to_edge_buffer; - MeshElemMap *vert_to_edge_map; + blender::Array vert_to_edge_offsets; + blender::Array vert_to_edge_indices; + blender::GroupedSpan vert_to_edge_map; }; static void subdiv_mesh_ctx_cache_uv_layers(SubdivMeshContext *ctx) @@ -132,8 +133,6 @@ static void subdiv_mesh_prepare_accumulator(SubdivMeshContext *ctx, int num_vert static void subdiv_mesh_context_free(SubdivMeshContext *ctx) { MEM_SAFE_FREE(ctx->accumulated_counters); - MEM_SAFE_FREE(ctx->vert_to_edge_buffer); - MEM_SAFE_FREE(ctx->vert_to_edge_map); } /** \} */ @@ -951,7 +950,7 @@ static void subdiv_mesh_vertex_loose(const SubdivForeachContext *foreach_context * - neighbors[0] is an edge adjacent to edge->v1. * - neighbors[1] is an edge adjacent to edge->v2. */ static void find_edge_neighbors(const int2 *coarse_edges, - const MeshElemMap *vert_to_edge_map, + const blender::GroupedSpan vert_to_edge_map, const int edge_index, const int2 *neighbors[2]) { @@ -959,7 +958,7 @@ static void find_edge_neighbors(const int2 *coarse_edges, neighbors[0] = nullptr; neighbors[1] = nullptr; int neighbor_counters[2] = {0, 0}; - for (const int i : Span(vert_to_edge_map[edge[0]].indices, vert_to_edge_map[edge[0]].count)) { + for (const int i : vert_to_edge_map[edge[0]]) { if (i == edge_index) { continue; } @@ -968,7 +967,7 @@ static void find_edge_neighbors(const int2 *coarse_edges, ++neighbor_counters[0]; } } - for (const int i : Span(vert_to_edge_map[edge[1]].indices, vert_to_edge_map[edge[1]].count)) { + for (const int i : vert_to_edge_map[edge[1]]) { if (i == edge_index) { continue; } @@ -1026,7 +1025,7 @@ static void points_for_loose_edges_interpolation_get(const float (*coarse_positi void BKE_subdiv_mesh_interpolate_position_on_edge(const float (*coarse_positions)[3], const blender::int2 *coarse_edges, - const MeshElemMap *vert_to_edge_map, + const blender::GroupedSpan vert_to_edge_map, const int coarse_edge_index, const bool is_simple, const float u, @@ -1085,14 +1084,14 @@ static void subdiv_mesh_vertex_of_loose_edge(const SubdivForeachContext *foreach /* Lazily initialize a vertex to edge map to avoid quadratic runtime when subdividing loose * edges. Do this here to avoid the cost in common cases when there are no loose edges at all. */ - if (ctx->vert_to_edge_map == nullptr) { + if (ctx->vert_to_edge_map.is_empty()) { std::lock_guard lock{ctx->vert_to_edge_map_mutex}; - if (ctx->vert_to_edge_map == nullptr) { - BKE_mesh_vert_edge_map_create(&ctx->vert_to_edge_map, - &ctx->vert_to_edge_buffer, - ctx->coarse_edges.data(), - coarse_mesh->totvert, - ctx->coarse_mesh->totedge); + if (ctx->vert_to_edge_map.is_empty()) { + ctx->vert_to_edge_map = blender::bke::mesh::build_vert_to_edge_map( + ctx->coarse_edges, + coarse_mesh->totvert, + ctx->vert_to_edge_offsets, + ctx->vert_to_edge_indices); } } diff --git a/source/blender/blenlib/BLI_offset_indices.hh b/source/blender/blenlib/BLI_offset_indices.hh index 3fa8ce9dd2a..e867ab9a35e 100644 --- a/source/blender/blenlib/BLI_offset_indices.hh +++ b/source/blender/blenlib/BLI_offset_indices.hh @@ -92,10 +92,50 @@ template class OffsetIndices { } }; +/** + * References many separate spans in a larger contiguous array. This gives a more efficient way to + * store many grouped arrays, without requiring many small allocations, giving the general benefits + * of using contiguous memory. + * + * \note If the offsets are shared between many #GroupedSpan objects, it will still + * be more efficient to retrieve the #IndexRange only once and slice each span. + */ +template struct GroupedSpan { + OffsetIndices offsets; + Span data; + + GroupedSpan() = default; + GroupedSpan(OffsetIndices offsets, Span data) : offsets(offsets), data(data) + { + BLI_assert(this->offsets.total_size() == this->data.size()); + } + + Span operator[](const int64_t index) const + { + return this->data.slice(this->offsets[index]); + } + + int64_t size() const + { + return this->offsets.size(); + } + + IndexRange index_range() const + { + return this->offsets.index_range(); + } + + bool is_empty() const + { + return this->data.size() == 0; + } +}; + /** * Turn an array of sizes into the offset at each index including all previous sizes. */ -void accumulate_counts_to_offsets(MutableSpan counts_to_offsets, int start_offset = 0); +OffsetIndices accumulate_counts_to_offsets(MutableSpan counts_to_offsets, + int start_offset = 0); /** * Create a map from indexed elements to the source indices, in other words from the larger array @@ -103,8 +143,14 @@ void accumulate_counts_to_offsets(MutableSpan counts_to_offsets, int start_ */ void build_reverse_map(OffsetIndices offsets, MutableSpan r_map); +/** + * Build offsets to group the elements of \a indices pointing to the same index. + */ +void build_reverse_offsets(Span indices, MutableSpan r_map); + } // namespace blender::offset_indices namespace blender { +using offset_indices::GroupedSpan; using offset_indices::OffsetIndices; -} +} // namespace blender diff --git a/source/blender/blenlib/intern/offset_indices.cc b/source/blender/blenlib/intern/offset_indices.cc index 8b38d630b05..904e71c0a43 100644 --- a/source/blender/blenlib/intern/offset_indices.cc +++ b/source/blender/blenlib/intern/offset_indices.cc @@ -5,7 +5,7 @@ namespace blender::offset_indices { -void accumulate_counts_to_offsets(MutableSpan counts_to_offsets, const int start_offset) +OffsetIndices accumulate_counts_to_offsets(MutableSpan counts_to_offsets, const int start_offset) { int offset = start_offset; for (const int i : counts_to_offsets.index_range().drop_back(1)) { @@ -15,6 +15,7 @@ void accumulate_counts_to_offsets(MutableSpan counts_to_offsets, const int offset += count; } counts_to_offsets.last() = offset; + return OffsetIndices(counts_to_offsets); } void build_reverse_map(OffsetIndices offsets, MutableSpan r_map) @@ -26,4 +27,13 @@ void build_reverse_map(OffsetIndices offsets, MutableSpan r_map) }); } +void build_reverse_offsets(const Span indices, MutableSpan offsets) +{ + BLI_assert(std::all_of(offsets.begin(), offsets.end(), [](int value) { return value == 0; })); + for (const int i : indices) { + offsets[i]++; + } + offset_indices::accumulate_counts_to_offsets(offsets); +} + } // namespace blender::offset_indices diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc index d20058ad317..fe87877b016 100644 --- a/source/blender/draw/intern/draw_cache_impl_subdivision.cc +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -2230,13 +2230,10 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac const Span coarse_positions = coarse_mesh->vert_positions(); const Span coarse_edges = coarse_mesh->edges(); - int *vert_to_edge_buffer; - MeshElemMap *vert_to_edge_map; - BKE_mesh_vert_edge_map_create(&vert_to_edge_map, - &vert_to_edge_buffer, - coarse_edges.data(), - coarse_mesh->totvert, - coarse_edges.size()); + blender::Array vert_to_edge_offsets; + blender::Array vert_to_edge_indices; + const blender::GroupedSpan vert_to_edge_map = blender::bke::mesh::build_vert_to_edge_map( + coarse_edges, coarse_mesh->totvert, vert_to_edge_offsets, vert_to_edge_indices); for (int i = 0; i < coarse_loose_edge_len; i++) { const int coarse_edge_index = cache->loose_geom.edges[i]; @@ -2279,9 +2276,6 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac } } - MEM_freeN(vert_to_edge_buffer); - MEM_freeN(vert_to_edge_map); - /* Copy the remaining loose_verts. */ for (int i = 0; i < coarse_loose_vert_len; i++) { const int coarse_vertex_index = cache->loose_geom.verts[i]; diff --git a/source/blender/editors/mesh/editface.cc b/source/blender/editors/mesh/editface.cc index 9baf7982026..24c9a21c6f5 100644 --- a/source/blender/editors/mesh/editface.cc +++ b/source/blender/editors/mesh/editface.cc @@ -795,10 +795,12 @@ void paintvert_select_more(Mesh *mesh, const bool face_step) const Span corner_verts = mesh->corner_verts(); const Span edges = mesh->edges(); - Array> edge_to_face_map; + Array edge_to_face_offsets; + Array edge_to_face_indices; + GroupedSpan edge_to_face_map; if (face_step) { - edge_to_face_map = bke::mesh_topology::build_edge_to_poly_map( - polys, corner_edges, mesh->totedge); + edge_to_face_map = bke::mesh::build_edge_to_poly_map( + polys, corner_edges, mesh->totedge, edge_to_face_offsets, edge_to_face_indices); } /* Need a copy of the selected verts that we can read from and is not modified. */ @@ -851,15 +853,12 @@ void paintvert_select_less(Mesh *mesh, const bool face_step) const Span corner_verts = mesh->corner_verts(); const Span edges = mesh->edges(); - MeshElemMap *edge_poly_map; - int *edge_poly_mem = nullptr; + GroupedSpan edge_to_poly_map; + Array edge_to_poly_offsets; + Array edge_to_poly_indices; if (face_step) { - BKE_mesh_edge_poly_map_create(&edge_poly_map, - &edge_poly_mem, - edges.size(), - polys, - corner_edges.data(), - corner_edges.size()); + edge_to_poly_map = bke::mesh::build_edge_to_poly_map( + polys, corner_edges, edges.size(), edge_to_poly_offsets, edge_to_poly_indices); } /* Need a copy of the selected verts that we can read from and is not modified. */ @@ -879,8 +878,7 @@ void paintvert_select_less(Mesh *mesh, const bool face_step) if (!face_step) { continue; } - const Span neighbor_polys(edge_poly_map[i].indices, edge_poly_map[i].count); - for (const int poly_i : neighbor_polys) { + for (const int poly_i : edge_to_poly_map[i]) { if (hide_poly[poly_i]) { continue; } @@ -890,10 +888,6 @@ void paintvert_select_less(Mesh *mesh, const bool face_step) } } } - if (edge_poly_mem) { - MEM_freeN(edge_poly_map); - MEM_freeN(edge_poly_mem); - } select_vert.finish(); } diff --git a/source/blender/editors/object/object_modifier.cc b/source/blender/editors/object/object_modifier.cc index e7032857e28..4bfca674e77 100644 --- a/source/blender/editors/object/object_modifier.cc +++ b/source/blender/editors/object/object_modifier.cc @@ -2900,12 +2900,12 @@ static void skin_armature_bone_create(Object *skin_ob, const blender::int2 *edges, bArmature *arm, BLI_bitmap *edges_visited, - const MeshElemMap *emap, + const blender::GroupedSpan emap, EditBone *parent_bone, int parent_v) { - for (int i = 0; i < emap[parent_v].count; i++) { - int endx = emap[parent_v].indices[i]; + for (int i = 0; i < emap[parent_v].size(); i++) { + int endx = emap[parent_v][i]; const blender::int2 &edge = edges[endx]; /* ignore edge if already visited */ @@ -2967,9 +2967,11 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, MVertSkin *mvert_skin = static_cast( CustomData_get_layer_for_write(&me->vdata, CD_MVERT_SKIN, me->totvert)); - int *emap_mem; - MeshElemMap *emap; - BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me_edges.data(), me->totvert, me->totedge); + + blender::Array vert_to_edge_offsets; + blender::Array vert_to_edge_indices; + const blender::GroupedSpan emap = blender::bke::mesh::build_vert_to_edge_map( + me_edges, me->totvert, vert_to_edge_offsets, vert_to_edge_indices); BLI_bitmap *edges_visited = BLI_BITMAP_NEW(me->totedge, "edge_visited"); @@ -2982,7 +2984,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, /* Unless the skin root has just one adjacent edge, create * a fake root bone (have it going off in the Y direction * (arbitrary) */ - if (emap[v].count > 1) { + if (emap[v].size() > 1) { bone = ED_armature_ebone_add(arm, "Bone"); copy_v3_v3(bone->head, me_positions[v]); @@ -2992,7 +2994,7 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, bone->rad_head = bone->rad_tail = 0.25; } - if (emap[v].count >= 1) { + if (emap[v].size() >= 1) { skin_armature_bone_create( skin_ob, positions_eval, me_edges.data(), arm, edges_visited, emap, bone, v); } @@ -3000,8 +3002,6 @@ static Object *modifier_skin_armature_create(Depsgraph *depsgraph, Main *bmain, } MEM_freeN(edges_visited); - MEM_freeN(emap); - MEM_freeN(emap_mem); ED_armature_from_edit(bmain, arm); ED_armature_edit_free(arm); diff --git a/source/blender/editors/object/object_vgroup.cc b/source/blender/editors/object/object_vgroup.cc index dc6c5ca0886..57f6412112d 100644 --- a/source/blender/editors/object/object_vgroup.cc +++ b/source/blender/editors/object/object_vgroup.cc @@ -1569,9 +1569,6 @@ static void vgroup_smooth_subset(Object *ob, BMesh *bm = em ? em->bm : nullptr; Mesh *me = em ? nullptr : static_cast(ob->data); - MeshElemMap *emap; - int *emap_mem; - float *weight_accum_prev; float *weight_accum_curr; @@ -1585,15 +1582,16 @@ static void vgroup_smooth_subset(Object *ob, ED_vgroup_parray_alloc(static_cast(ob->data), &dvert_array, &dvert_tot, false); vgroup_subset_weights.fill(0.0f); + blender::Array vert_to_edge_offsets; + blender::Array vert_to_edge_indices; + blender::GroupedSpan emap; if (bm) { BM_mesh_elem_table_ensure(bm, BM_VERT); BM_mesh_elem_index_ensure(bm, BM_VERT); - - emap = nullptr; - emap_mem = nullptr; } else { - BKE_mesh_vert_edge_map_create(&emap, &emap_mem, me->edges().data(), me->totvert, me->totedge); + emap = blender::bke::mesh::build_vert_to_edge_map( + me->edges(), me->totvert, vert_to_edge_offsets, vert_to_edge_indices); } weight_accum_prev = static_cast( @@ -1639,8 +1637,8 @@ static void vgroup_smooth_subset(Object *ob, const blender::Span edges = me->edges(); for (int i = 0; i < dvert_tot; i++) { if (IS_ME_VERT_WRITE(i)) { - for (int j = 0; j < emap[i].count; j++) { - const int2 &edge = edges[emap[i].indices[j]]; + for (int j = 0; j < emap[i].size(); j++) { + const int2 &edge = edges[emap[i][j]]; const int i_other = (edge[0] == i) ? edge[1] : edge[0]; if (IS_ME_VERT_READ(i_other)) { STACK_PUSH(verts_used, i); @@ -1718,8 +1716,8 @@ static void vgroup_smooth_subset(Object *ob, /* checked already */ BLI_assert(IS_ME_VERT_WRITE(i)); - for (j = 0; j < emap[i].count; j++) { - const int2 &edge = edges[emap[i].indices[j]]; + for (j = 0; j < emap[i].size(); j++) { + const int2 &edge = edges[emap[i][j]]; const int i_other = (edge[0] == i ? edge[1] : edge[0]); if (IS_ME_VERT_READ(i_other)) { WEIGHT_ACCUMULATE; @@ -1754,14 +1752,6 @@ static void vgroup_smooth_subset(Object *ob, MEM_freeN(weight_accum_prev); MEM_freeN(verts_used); - if (bm) { - /* pass */ - } - else { - MEM_freeN(emap); - MEM_freeN(emap_mem); - } - if (dvert_array) { MEM_freeN(dvert_array); } diff --git a/source/blender/editors/sculpt_paint/paint_vertex.cc b/source/blender/editors/sculpt_paint/paint_vertex.cc index de01debacf9..f811879a762 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.cc +++ b/source/blender/editors/sculpt_paint/paint_vertex.cc @@ -1246,15 +1246,11 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob) const blender::OffsetIndices polys = me->polys(); const Span corner_verts = me->corner_verts(); - if (gmap->vert_to_loop == nullptr) { - gmap->vert_map_mem = nullptr; - gmap->vert_to_loop = nullptr; - gmap->poly_map_mem = nullptr; - gmap->vert_to_poly = nullptr; - BKE_mesh_vert_loop_map_create( - &gmap->vert_to_loop, &gmap->vert_map_mem, polys, corner_verts.data(), me->totvert); - BKE_mesh_vert_poly_map_create( - &gmap->vert_to_poly, &gmap->poly_map_mem, polys, corner_verts.data(), me->totvert); + 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_poly = blender::bke::mesh::build_vert_to_poly_map( + polys, corner_verts, me->totvert, gmap->vert_to_poly_offsets, gmap->vert_to_poly_indices); } /* Create average brush arrays */ @@ -1975,8 +1971,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata, /* Get the average poly weight */ int total_hit_loops = 0; float weight_final = 0.0f; - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - const int p_index = gmap->vert_to_poly[v_index].indices[j]; + for (const int p_index : gmap->vert_to_poly[v_index]) { const blender::IndexRange poly = ss->polys[p_index]; total_hit_loops += poly.size(); @@ -2089,8 +2084,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata, /* Get the color of the loop in the opposite direction of the brush movement * (this callback is specifically for smear.) */ float weight_final = 0.0; - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - const int p_index = gmap->vert_to_poly[v_index].indices[j]; + for (const int p_index : gmap->vert_to_poly[v_index]) { for (const int v_other_index : ss->corner_verts.slice(ss->polys[p_index])) { if (v_other_index != v_index) { const float3 &mv_other = ss->vert_positions[v_other_index]; @@ -3022,8 +3016,7 @@ static void do_vpaint_brush_blur_loops(bContext *C, int total_hit_loops = 0; Blend blend[4] = {0}; - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - int p_index = gmap->vert_to_poly[v_index].indices[j]; + for (const int p_index : gmap->vert_to_poly[v_index]) { if (!use_face_sel || select_poly[p_index]) { const blender::IndexRange poly = ss->polys[p_index]; total_hit_loops += poly.size(); @@ -3054,9 +3047,9 @@ static void do_vpaint_brush_blur_loops(bContext *C, /* For each poly owning this vert, * paint each loop belonging to this vert. */ - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - const int p_index = gmap->vert_to_poly[v_index].indices[j]; - const int l_index = gmap->vert_to_loop[v_index].indices[j]; + for (const int j : gmap->vert_to_poly[v_index].index_range()) { + const int p_index = gmap->vert_to_poly[v_index][j]; + const int l_index = gmap->vert_to_loop[v_index][j]; BLI_assert(ss->corner_verts[l_index] == v_index); if (!use_face_sel || select_poly[p_index]) { Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */ @@ -3166,8 +3159,7 @@ static void do_vpaint_brush_blur_verts(bContext *C, int total_hit_loops = 0; Blend blend[4] = {0}; - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - int p_index = gmap->vert_to_poly[v_index].indices[j]; + for (const int p_index : gmap->vert_to_poly[v_index]) { if (!use_face_sel || select_poly[p_index]) { const blender::IndexRange poly = ss->polys[p_index]; total_hit_loops += poly.size(); @@ -3198,11 +3190,7 @@ static void do_vpaint_brush_blur_verts(bContext *C, /* For each poly owning this vert, * paint each loop belonging to this vert. */ - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - const int p_index = gmap->vert_to_poly[v_index].indices[j]; - - BLI_assert(ss->corner_verts[gmap->vert_to_loop[v_index].indices[j]] == v_index); - + for (const int p_index : gmap->vert_to_poly[v_index]) { if (!use_face_sel || select_poly[p_index]) { Color color_orig(0, 0, 0, 0); /* unused when array is nullptr */ @@ -3323,9 +3311,9 @@ static void do_vpaint_brush_smear(bContext *C, * direction of the brush movement */ Color color_final(0, 0, 0, 0); - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - const int p_index = gmap->vert_to_poly[v_index].indices[j]; - const int l_index = gmap->vert_to_loop[v_index].indices[j]; + for (const int j : gmap->vert_to_poly[v_index].index_range()) { + const int p_index = gmap->vert_to_poly[v_index][j]; + const int l_index = gmap->vert_to_loop[v_index][j]; BLI_assert(ss->corner_verts[l_index] == v_index); UNUSED_VARS_NDEBUG(l_index); if (!use_face_sel || select_poly[p_index]) { @@ -3368,15 +3356,15 @@ static void do_vpaint_brush_smear(bContext *C, /* For each poly owning this vert, * paint each loop belonging to this vert. */ - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - const int p_index = gmap->vert_to_poly[v_index].indices[j]; + for (const int j : gmap->vert_to_poly[v_index].index_range()) { + const int p_index = gmap->vert_to_poly[v_index][j]; int elem_index; if constexpr (domain == ATTR_DOMAIN_POINT) { elem_index = v_index; } else { - const int l_index = gmap->vert_to_loop[v_index].indices[j]; + const int l_index = gmap->vert_to_loop[v_index][j]; elem_index = l_index; BLI_assert(ss->corner_verts[l_index] == v_index); } @@ -3460,13 +3448,13 @@ static void calculate_average_color(VPaintData *vpd, if (BKE_brush_curve_strength(brush, 0.0, cache->radius) > 0.0) { /* If the vertex is selected for painting. */ if (!use_vert_sel || select_vert[v_index]) { - accum2->len += gmap->vert_to_loop[v_index].count; + accum2->len += gmap->vert_to_poly[v_index].size(); /* if a vertex is within the brush region, then add its color to the blend. */ - for (int j = 0; j < gmap->vert_to_loop[v_index].count; j++) { + for (int j = 0; j < gmap->vert_to_poly[v_index].size(); j++) { int elem_index; if constexpr (domain == ATTR_DOMAIN_CORNER) { - elem_index = gmap->vert_to_loop[v_index].indices[j]; + elem_index = gmap->vert_to_loop[v_index][j]; } else { elem_index = v_index; @@ -3632,9 +3620,9 @@ static void vpaint_do_draw(bContext *C, } else { /* For each poly owning this vert, paint each loop belonging to this vert. */ - for (int j = 0; j < gmap->vert_to_poly[v_index].count; j++) { - const int p_index = gmap->vert_to_poly[v_index].indices[j]; - const int l_index = gmap->vert_to_loop[v_index].indices[j]; + for (const int j : gmap->vert_to_poly[v_index].index_range()) { + const int p_index = gmap->vert_to_poly[v_index][j]; + const int l_index = gmap->vert_to_loop[v_index][j]; BLI_assert(ss->corner_verts[l_index] == v_index); if (!use_face_sel || select_poly[p_index]) { Color color_orig = Color(0, 0, 0, 0); /* unused when array is nullptr */ diff --git a/source/blender/editors/sculpt_paint/sculpt.cc b/source/blender/editors/sculpt_paint/sculpt.cc index 1583cabd98e..25b8da1a96b 100644 --- a/source/blender/editors/sculpt_paint/sculpt.cc +++ b/source/blender/editors/sculpt_paint/sculpt.cc @@ -483,9 +483,8 @@ bool SCULPT_vertex_any_face_visible_get(SculptSession *ss, PBVHVertRef vertex) if (!ss->hide_poly) { return true; } - const MeshElemMap *vert_map = &ss->pmap[vertex.i]; - for (int j = 0; j < ss->pmap[vertex.i].count; j++) { - if (!ss->hide_poly[vert_map->indices[j]]) { + for (const int poly : ss->pmap[vertex.i]) { + if (!ss->hide_poly[poly]) { return true; } } @@ -506,9 +505,8 @@ bool SCULPT_vertex_all_faces_visible_get(const SculptSession *ss, PBVHVertRef ve if (!ss->hide_poly) { return true; } - const MeshElemMap *vert_map = &ss->pmap[vertex.i]; - for (int j = 0; j < vert_map->count; j++) { - if (ss->hide_poly[vert_map->indices[j]]) { + for (const int poly : ss->pmap[vertex.i]) { + if (ss->hide_poly[poly]) { return false; } } @@ -556,9 +554,7 @@ void SCULPT_vertex_face_set_set(SculptSession *ss, PBVHVertRef vertex, int face_ switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { BLI_assert(ss->face_sets != nullptr); - const MeshElemMap *vert_map = &ss->pmap[vertex.i]; - for (int j = 0; j < vert_map->count; j++) { - const int poly_index = vert_map->indices[j]; + for (const int poly_index : ss->pmap[vertex.i]) { if (ss->hide_poly && ss->hide_poly[poly_index]) { /* Skip hidden faces connected to the vertex. */ continue; @@ -591,11 +587,10 @@ int SCULPT_vertex_face_set_get(SculptSession *ss, PBVHVertRef vertex) if (!ss->face_sets) { return SCULPT_FACE_SET_NONE; } - const MeshElemMap *vert_map = &ss->pmap[vertex.i]; int face_set = 0; - for (int i = 0; i < vert_map->count; i++) { - if (ss->face_sets[vert_map->indices[i]] > face_set) { - face_set = abs(ss->face_sets[vert_map->indices[i]]); + for (const int poly_index : ss->pmap[vertex.i]) { + if (ss->face_sets[poly_index] > face_set) { + face_set = abs(ss->face_sets[poly_index]); } } return face_set; @@ -622,9 +617,8 @@ bool SCULPT_vertex_has_face_set(SculptSession *ss, PBVHVertRef vertex, int face_ if (!ss->face_sets) { return face_set == SCULPT_FACE_SET_NONE; } - const MeshElemMap *vert_map = &ss->pmap[vertex.i]; - for (int i = 0; i < vert_map->count; i++) { - if (ss->face_sets[vert_map->indices[i]] == face_set) { + for (const int poly_index : ss->pmap[vertex.i]) { + if (ss->face_sets[poly_index] == face_set) { return true; } } @@ -702,14 +696,13 @@ static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int ind if (!ss->face_sets) { return true; } - const MeshElemMap *vert_map = &ss->pmap[index]; int face_set = -1; - for (int i = 0; i < vert_map->count; i++) { + for (const int poly_index : ss->pmap[index]) { if (face_set == -1) { - face_set = ss->face_sets[vert_map->indices[i]]; + face_set = ss->face_sets[poly_index]; } else { - if (ss->face_sets[vert_map->indices[i]] != face_set) { + if (ss->face_sets[poly_index] != face_set) { return false; } } @@ -723,19 +716,19 @@ static bool sculpt_check_unique_face_set_in_base_mesh(SculptSession *ss, int ind */ static bool sculpt_check_unique_face_set_for_edge_in_base_mesh(SculptSession *ss, int v1, int v2) { - const MeshElemMap *vert_map = &ss->pmap[v1]; + const Span vert_map = ss->pmap[v1]; int p1 = -1, p2 = -1; - for (int i = 0; i < vert_map->count; i++) { - const int poly_i = vert_map->indices[i]; + for (int i = 0; i < vert_map.size(); i++) { + const int poly_i = vert_map[i]; for (const int corner : ss->polys[poly_i]) { if (ss->corner_verts[corner] == v2) { if (p1 == -1) { - p1 = vert_map->indices[i]; + p1 = vert_map[i]; break; } if (p2 == -1) { - p2 = vert_map->indices[i]; + p2 = vert_map[i]; break; } } @@ -876,19 +869,18 @@ static void sculpt_vertex_neighbors_get_faces(SculptSession *ss, PBVHVertRef vertex, SculptVertexNeighborIter *iter) { - const MeshElemMap *vert_map = &ss->pmap[vertex.i]; iter->size = 0; iter->num_duplicates = 0; iter->capacity = SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY; iter->neighbors = iter->neighbors_fixed; iter->neighbor_indices = iter->neighbor_indices_fixed; - for (int i = 0; i < vert_map->count; i++) { - if (ss->hide_poly && ss->hide_poly[vert_map->indices[i]]) { + for (const int poly_i : ss->pmap[vertex.i]) { + if (ss->hide_poly && ss->hide_poly[poly_i]) { /* Skip connectivity from hidden faces. */ continue; } - const blender::IndexRange poly = ss->polys[vert_map->indices[i]]; + const blender::IndexRange poly = ss->polys[poly_i]; const blender::int2 f_adj_v = blender::bke::mesh::poly_find_adjecent_verts( poly, ss->corner_verts, vertex.i); for (int j = 0; j < 2; j++) { diff --git a/source/blender/editors/sculpt_paint/sculpt_automasking.cc b/source/blender/editors/sculpt_paint/sculpt_automasking.cc index 7a6d19cfbcf..722a8318a74 100644 --- a/source/blender/editors/sculpt_paint/sculpt_automasking.cc +++ b/source/blender/editors/sculpt_paint/sculpt_automasking.cc @@ -639,11 +639,6 @@ static void SCULPT_topology_automasking_init(Sculpt *sd, Object *ob) SculptSession *ss = ob->sculpt; Brush *brush = BKE_paint_brush(&sd->paint); - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { - BLI_assert_unreachable(); - return; - } - const int totvert = SCULPT_vertex_count_get(ss); for (int i : IndexRange(totvert)) { PBVHVertRef vertex = BKE_pbvh_index_to_vertex(ss->pbvh, i); @@ -678,11 +673,6 @@ static void sculpt_face_sets_automasking_init(Sculpt *sd, Object *ob) return; } - if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES && !ss->pmap) { - BLI_assert_msg(0, "Face Sets automasking: pmap missing"); - return; - } - int tot_vert = SCULPT_vertex_count_get(ss); int active_face_set = SCULPT_active_face_set_get(ss); for (int i : IndexRange(tot_vert)) { @@ -702,11 +692,6 @@ static void SCULPT_boundary_automasking_init(Object *ob, { SculptSession *ss = ob->sculpt; - if (!ss->pmap) { - BLI_assert_msg(0, "Boundary Edges masking: pmap missing"); - return; - } - const int totvert = SCULPT_vertex_count_get(ss); int *edge_distance = (int *)MEM_callocN(sizeof(int) * totvert, "automask_factor"); diff --git a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc index bc7ce94fd18..bc07ef117d2 100644 --- a/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc +++ b/source/blender/editors/sculpt_paint/sculpt_dyntopo.cc @@ -70,10 +70,6 @@ void SCULPT_pbvh_clear(Object *ob) ss->pbvh = nullptr; } - MEM_SAFE_FREE(ss->pmap); - - MEM_SAFE_FREE(ss->pmap_mem); - BKE_object_free_derived_caches(ob); /* Tag to rebuild PBVH in depsgraph. */ diff --git a/source/blender/editors/sculpt_paint/sculpt_expand.cc b/source/blender/editors/sculpt_paint/sculpt_expand.cc index c9962bb04e4..003356dcd16 100644 --- a/source/blender/editors/sculpt_paint/sculpt_expand.cc +++ b/source/blender/editors/sculpt_paint/sculpt_expand.cc @@ -727,8 +727,8 @@ static float *sculpt_expand_diagonals_falloff_create(Object *ob, const PBVHVertR int v_next_i = BKE_pbvh_vertex_to_index(ss->pbvh, v_next); - for (int j = 0; j < ss->pmap[v_next_i].count; j++) { - for (const int vert : ss->corner_verts.slice(ss->polys[ss->pmap[v_next_i].indices[j]])) { + for (const int poly : ss->pmap[v_next_i]) { + for (const int vert : ss->corner_verts.slice(ss->polys[poly])) { const PBVHVertRef neighbor_v = BKE_pbvh_make_vref(vert); if (BLI_BITMAP_TEST(visited_verts, neighbor_v.i)) { continue; @@ -1985,7 +1985,7 @@ static void sculpt_expand_delete_face_set_id(int *r_face_sets, const int delete_id) { const int totface = ss->totfaces; - MeshElemMap *pmap = ss->pmap; + const blender::GroupedSpan pmap = ss->pmap; const blender::OffsetIndices polys = mesh->polys(); const blender::Span corner_verts = mesh->corner_verts(); @@ -2023,10 +2023,7 @@ static void sculpt_expand_delete_face_set_id(int *r_face_sets, const int f_index = POINTER_AS_INT(BLI_LINKSTACK_POP(queue)); int other_id = delete_id; for (const int vert : corner_verts.slice(polys[f_index])) { - const MeshElemMap *vert_map = &pmap[vert]; - for (int i = 0; i < vert_map->count; i++) { - - const int neighbor_face_index = vert_map->indices[i]; + for (const int neighbor_face_index : pmap[vert]) { if (expand_cache->original_face_sets[neighbor_face_index] <= 0) { /* Skip picking IDs from hidden Face Sets. */ continue; diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.cc b/source/blender/editors/sculpt_paint/sculpt_face_set.cc index 566e7e57386..da6e6416d02 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.cc +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.cc @@ -140,9 +140,8 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, SCULPT_automasking_node_update(ss, &automask_data, &vd); if (BKE_pbvh_type(ss->pbvh) == PBVH_FACES) { - MeshElemMap *vert_map = &ss->pmap[vd.index]; - for (int j = 0; j < ss->pmap[vd.index].count; j++) { - const blender::IndexRange poly = ss->polys[vert_map->indices[j]]; + for (const int poly_i : ss->pmap[vd.index]) { + const blender::IndexRange poly = ss->polys[poly_i]; const float3 poly_center = bke::mesh::poly_center_calc(positions, ss->corner_verts.slice(poly)); @@ -150,7 +149,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, if (!sculpt_brush_test_sq_fn(&test, poly_center)) { continue; } - const bool face_hidden = ss->hide_poly && ss->hide_poly[vert_map->indices[j]]; + const bool face_hidden = ss->hide_poly && ss->hide_poly[poly_i]; if (face_hidden) { continue; } @@ -166,7 +165,7 @@ static void do_draw_face_sets_brush_task_cb_ex(void *__restrict userdata, &automask_data); if (fade > 0.05f) { - ss->face_sets[vert_map->indices[j]] = ss->cache->paint_face_set; + ss->face_sets[poly_i] = ss->cache->paint_face_set; changed = true; } } @@ -552,9 +551,9 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, const FaceSetsFloodFill const OffsetIndices polys = mesh->polys(); const Span corner_edges = mesh->corner_edges(); - if (!ss->epmap) { - BKE_mesh_edge_poly_map_create( - &ss->epmap, &ss->epmap_mem, edges.size(), polys, corner_edges.data(), corner_edges.size()); + if (ss->epmap.is_empty()) { + ss->epmap = bke::mesh::build_edge_to_poly_map( + polys, corner_edges, edges.size(), ss->edge_to_poly_offsets, ss->edge_to_poly_indices); } int next_face_set = 1; @@ -574,8 +573,7 @@ static void sculpt_face_sets_init_flood_fill(Object *ob, const FaceSetsFloodFill queue.pop(); for (const int edge_i : corner_edges.slice(polys[poly_i])) { - const Span neighbor_polys(ss->epmap[edge_i].indices, ss->epmap[edge_i].count); - for (const int neighbor_i : neighbor_polys) { + for (const int neighbor_i : ss->epmap[edge_i]) { if (neighbor_i == poly_i) { continue; } @@ -1084,9 +1082,7 @@ static void sculpt_face_set_grow(Object *ob, continue; } for (const int vert : corner_verts.slice(polys[p])) { - const MeshElemMap *vert_map = &ss->pmap[vert]; - for (int i = 0; i < vert_map->count; i++) { - const int neighbor_face_index = vert_map->indices[i]; + for (const int neighbor_face_index : ss->pmap[vert]) { if (neighbor_face_index == p) { continue; } @@ -1114,9 +1110,7 @@ static void sculpt_face_set_shrink(Object *ob, } if (abs(prev_face_sets[p]) == active_face_set_id) { for (const int vert_i : corner_verts.slice(polys[p])) { - const MeshElemMap *vert_map = &ss->pmap[vert_i]; - for (int i = 0; i < vert_map->count; i++) { - const int neighbor_face_index = vert_map->indices[i]; + for (const int neighbor_face_index : ss->pmap[vert_i]) { if (neighbor_face_index == p) { continue; } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_color.cc b/source/blender/editors/sculpt_paint/sculpt_filter_color.cc index 78428d13239..2bb0a655233 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_color.cc +++ b/source/blender/editors/sculpt_paint/sculpt_filter_color.cc @@ -359,7 +359,6 @@ static int sculpt_color_filter_init(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - const PBVHType pbvh_type_prev = BKE_pbvh_type(ss->pbvh); SCULPT_undo_push_begin(ob, op); BKE_sculpt_color_layer_create_if_needed(ob); @@ -367,9 +366,6 @@ static int sculpt_color_filter_init(bContext *C, wmOperator *op) * earlier steps modifying the data. */ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); BKE_sculpt_update_object_for_edit(depsgraph, ob, true, false, true); - if (pbvh_type_prev == PBVH_FACES && !ob->sculpt->pmap) { - return OPERATOR_CANCELLED; - } SCULPT_filter_cache_init(C, ob, diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.cc b/source/blender/editors/sculpt_paint/sculpt_filter_mask.cc index e1949d8c063..3b61040e913 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.cc +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.cc @@ -174,10 +174,6 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op) SCULPT_vertex_random_access_ensure(ss); - if (!ob->sculpt->pmap) { - return OPERATOR_CANCELLED; - } - int num_verts = SCULPT_vertex_count_get(ss); Vector nodes = blender::bke::pbvh::search_gather(pbvh, nullptr, nullptr); diff --git a/source/blender/editors/sculpt_paint/sculpt_geodesic.cc b/source/blender/editors/sculpt_paint/sculpt_geodesic.cc index 7345f9afcfa..7e4d4e23b68 100644 --- a/source/blender/editors/sculpt_paint/sculpt_geodesic.cc +++ b/source/blender/editors/sculpt_paint/sculpt_geodesic.cc @@ -95,13 +95,13 @@ static float *SCULPT_geodesic_mesh_create(Object *ob, float *dists = static_cast(MEM_malloc_arrayN(totvert, sizeof(float), __func__)); BLI_bitmap *edge_tag = BLI_BITMAP_NEW(totedge, "edge tag"); - if (!ss->epmap) { - BKE_mesh_edge_poly_map_create( - &ss->epmap, &ss->epmap_mem, edges.size(), polys, corner_edges.data(), corner_edges.size()); + if (ss->epmap.is_empty()) { + ss->epmap = blender::bke::mesh::build_edge_to_poly_map( + polys, corner_edges, edges.size(), ss->edge_to_poly_offsets, ss->edge_to_poly_indices); } - if (!ss->vemap) { - BKE_mesh_vert_edge_map_create( - &ss->vemap, &ss->vemap_mem, edges.data(), mesh->totvert, edges.size()); + if (ss->vemap.is_empty()) { + ss->vemap = blender::bke::mesh::build_vert_to_edge_map( + edges, mesh->totvert, ss->vert_to_edge_offsets, ss->vert_to_edge_indices); } /* Both contain edge indices encoded as *void. */ @@ -171,9 +171,9 @@ static float *SCULPT_geodesic_mesh_create(Object *ob, vert_positions, v2, v1, SCULPT_GEODESIC_VERTEX_NONE, dists, initial_verts); } - if (ss->epmap[e].count != 0) { - for (int poly_map_index = 0; poly_map_index < ss->epmap[e].count; poly_map_index++) { - const int poly = ss->epmap[e].indices[poly_map_index]; + if (ss->epmap[e].size() != 0) { + for (int poly_map_index = 0; poly_map_index < ss->epmap[e].size(); poly_map_index++) { + const int poly = ss->epmap[e][poly_map_index]; if (ss->hide_poly && ss->hide_poly[poly]) { continue; } @@ -183,9 +183,9 @@ static float *SCULPT_geodesic_mesh_create(Object *ob, } if (sculpt_geodesic_mesh_test_dist_add( vert_positions, v_other, v1, v2, dists, initial_verts)) { - for (int edge_map_index = 0; edge_map_index < ss->vemap[v_other].count; + for (int edge_map_index = 0; edge_map_index < ss->vemap[v_other].size(); edge_map_index++) { - const int e_other = ss->vemap[v_other].indices[edge_map_index]; + const int e_other = ss->vemap[v_other][edge_map_index]; int ev_other; if (edges[e_other][0] == v_other) { ev_other = edges[e_other][1]; @@ -195,7 +195,7 @@ static float *SCULPT_geodesic_mesh_create(Object *ob, } if (e_other != e && !BLI_BITMAP_TEST(edge_tag, e_other) && - (ss->epmap[e_other].count == 0 || dists[ev_other] != FLT_MAX)) + (ss->epmap[e_other].size() == 0 || dists[ev_other] != FLT_MAX)) { if (BLI_BITMAP_TEST(affected_vertex, v_other) || BLI_BITMAP_TEST(affected_vertex, ev_other)) { diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.cc b/source/blender/editors/sculpt_paint/sculpt_ops.cc index ad88e6a62ad..46a9a43c54f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_ops.cc +++ b/source/blender/editors/sculpt_paint/sculpt_ops.cc @@ -577,10 +577,6 @@ void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - if (!ss->pmap) { - return; - } - float brush_co[3]; copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss)); diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.cc b/source/blender/editors/sculpt_paint/sculpt_smooth.cc index 8a84fda1d27..c4860717525 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.cc +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.cc @@ -331,7 +331,6 @@ void SCULPT_smooth( const int max_iterations = 4; const float fract = 1.0f / max_iterations; - PBVHType type = BKE_pbvh_type(ss->pbvh); int iteration, count; float last; @@ -340,11 +339,6 @@ void SCULPT_smooth( count = int(bstrength * max_iterations); last = max_iterations * (bstrength - count * fract); - if (type == PBVH_FACES && !ss->pmap) { - BLI_assert_msg(0, "sculpt smooth: pmap missing"); - return; - } - SCULPT_vertex_random_access_ensure(ss); SCULPT_boundary_info_ensure(ob); diff --git a/source/blender/geometry/intern/mesh_split_edges.cc b/source/blender/geometry/intern/mesh_split_edges.cc index 1811191fb20..dfa539e3006 100644 --- a/source/blender/geometry/intern/mesh_split_edges.cc +++ b/source/blender/geometry/intern/mesh_split_edges.cc @@ -372,11 +372,18 @@ void split_edges(Mesh &mesh, } /* Precalculate topology info. */ - Array> vert_to_edge_map = bke::mesh_topology::build_vert_to_edge_map(edges, - mesh.totvert); - Vector> edge_to_loop_map = bke::mesh_topology::build_edge_to_loop_map_resizable( - mesh.corner_edges(), mesh.totedge); - Array loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(mesh.polys()); + Array> vert_to_edge_map(mesh.totvert); + for (const int i : edges.index_range()) { + vert_to_edge_map[edges[i][0]].append(i); + vert_to_edge_map[edges[i][1]].append(i); + } + + Array orig_edge_to_loop_offsets; + Array orig_edge_to_loop_indices; + const GroupedSpan orig_edge_to_loop_map = bke::mesh::build_edge_to_loop_map( + mesh.corner_edges(), mesh.totedge, orig_edge_to_loop_offsets, orig_edge_to_loop_indices); + + Array loop_to_poly_map = bke::mesh::build_loop_to_poly_map(mesh.polys()); /* Store offsets, so we can split edges in parallel. */ Array edge_offsets(edges.size()); @@ -385,7 +392,7 @@ void split_edges(Mesh &mesh, for (const int edge : mask) { edge_offsets[edge] = new_edges_size; /* We add duplicates of the edge for each poly (except the first). */ - const int num_connected_loops = edge_to_loop_map[edge].size(); + const int num_connected_loops = orig_edge_to_loop_map[edge].size(); const int num_duplicates = std::max(0, num_connected_loops - 1); new_edges_size += num_duplicates; num_edge_duplicates[edge] = num_duplicates; @@ -398,7 +405,12 @@ void split_edges(Mesh &mesh, Vector new_edges(new_edges_size); new_edges.as_mutable_span().take_front(edges.size()).copy_from(edges); - edge_to_loop_map.resize(new_edges_size); + Vector> edge_to_loop_map(new_edges_size); + threading::parallel_for(edges.index_range(), 512, [&](const IndexRange range) { + for (const int i : range) { + edge_to_loop_map[i].extend(orig_edge_to_loop_map[i]); + } + }); /* Used for transferring attributes. */ Vector new_to_old_edges_map(IndexRange(new_edges.size()).as_span()); diff --git a/source/blender/modifiers/intern/MOD_skin.cc b/source/blender/modifiers/intern/MOD_skin.cc index f02dd705295..ecd74987196 100644 --- a/source/blender/modifiers/intern/MOD_skin.cc +++ b/source/blender/modifiers/intern/MOD_skin.cc @@ -453,7 +453,7 @@ static void merge_frame_corners(Frame **frames, int totframe) static Frame **collect_hull_frames(int v, SkinNode *frames, - const MeshElemMap *emap, + blender::GroupedSpan emap, const blender::Span edges, int *tothullframe) { @@ -461,11 +461,11 @@ static Frame **collect_hull_frames(int v, Frame **hull_frames; int hull_frames_num, i; - (*tothullframe) = emap[v].count; + (*tothullframe) = emap[v].size(); hull_frames = MEM_cnew_array(*tothullframe, __func__); hull_frames_num = 0; - for (i = 0; i < emap[v].count; i++) { - const blender::int2 &edge = edges[emap[v].indices[i]]; + for (i = 0; i < emap[v].size(); i++) { + const blender::int2 &edge = edges[emap[v][i]]; f = &frames[blender::bke::mesh::edge_other_vert(edge, v)]; /* Can't have adjacent branch nodes yet */ if (f->totframe) { @@ -530,13 +530,13 @@ static void end_node_frames(int v, SkinNode *skin_nodes, const float (*vert_positions)[3], const MVertSkin *nodes, - const MeshElemMap *emap, + blender::GroupedSpan emap, EMat *emat) { const float *rad = nodes[v].radius; float mat[3][3]; - if (emap[v].count == 0) { + if (emap[v].size() == 0) { float avg = half_v2(rad); /* For solitary nodes, just build a box (two frames) */ @@ -557,8 +557,8 @@ static void end_node_frames(int v, skin_nodes[v].flag |= CAP_START; /* Use incoming edge for orientation */ - copy_m3_m3(mat, emat[emap[v].indices[0]].mat); - if (emat[emap[v].indices[0]].origin != v) { + copy_m3_m3(mat, emat[emap[v][0]].mat); + if (emat[emap[v][0]].origin != v) { negate_v3(mat[0]); } @@ -578,13 +578,13 @@ static void end_node_frames(int v, } /* Returns 1 for seam, 0 otherwise */ -static int connection_node_mat(float mat[3][3], int v, const MeshElemMap *emap, EMat *emat) +static int connection_node_mat(float mat[3][3], int v, blender::GroupedSpan emap, EMat *emat) { float axis[3], angle, ine[3][3], oute[3][3]; EMat *e1, *e2; - e1 = &emat[emap[v].indices[0]]; - e2 = &emat[emap[v].indices[1]]; + e1 = &emat[emap[v][0]]; + e2 = &emat[emap[v][1]]; if (e1->origin != v && e2->origin == v) { copy_m3_m3(ine, e1->mat); @@ -615,7 +615,7 @@ static void connection_node_frames(int v, SkinNode *skin_nodes, const float (*vert_positions)[3], const MVertSkin *nodes, - const MeshElemMap *emap, + blender::GroupedSpan emap, EMat *emat) { const float *rad = nodes[v].radius; @@ -626,8 +626,8 @@ static void connection_node_frames(int v, float avg = half_v2(rad); /* Get edges */ - e1 = &emat[emap[v].indices[0]]; - e2 = &emat[emap[v].indices[1]]; + e1 = &emat[emap[v][0]]; + e2 = &emat[emap[v][1]]; /* Handle seam separately to avoid twisting */ /* Create two frames, will be hulled to neighbors later */ @@ -639,14 +639,14 @@ static void connection_node_frames(int v, negate_v3(mat[0]); } create_frame(&skin_nodes[v].frames[0], vert_positions[v], rad, mat, avg); - skin_nodes[v].seam_edges[0] = emap[v].indices[0]; + skin_nodes[v].seam_edges[0] = emap[v][0]; copy_m3_m3(mat, e2->mat); if (e2->origin != v) { negate_v3(mat[0]); } create_frame(&skin_nodes[v].frames[1], vert_positions[v], rad, mat, avg); - skin_nodes[v].seam_edges[1] = emap[v].indices[1]; + skin_nodes[v].seam_edges[1] = emap[v][1]; return; } @@ -659,7 +659,7 @@ static void connection_node_frames(int v, static SkinNode *build_frames(const float (*vert_positions)[3], int verts_num, const MVertSkin *nodes, - const MeshElemMap *emap, + blender::GroupedSpan emap, EMat *emat) { int v; @@ -667,10 +667,10 @@ static SkinNode *build_frames(const float (*vert_positions)[3], SkinNode *skin_nodes = MEM_cnew_array(verts_num, __func__); for (v = 0; v < verts_num; v++) { - if (emap[v].count <= 1) { + if (emap[v].size() <= 1) { end_node_frames(v, skin_nodes, vert_positions, nodes, emap, emat); } - else if (emap[v].count == 2) { + else if (emap[v].size() == 2) { connection_node_frames(v, skin_nodes, vert_positions, nodes, emap, emat); } else { @@ -721,7 +721,7 @@ struct EdgeStackElem { static void build_emats_stack(BLI_Stack *stack, BLI_bitmap *visited_e, EMat *emat, - const MeshElemMap *emap, + blender::GroupedSpan emap, const blender::Span edges, const MVertSkin *vs, const float (*vert_positions)[3]) @@ -744,7 +744,7 @@ static void build_emats_stack(BLI_Stack *stack, /* Process edge */ - parent_is_branch = ((emap[parent_v].count > 2) || (vs[parent_v].flag & MVERT_SKIN_ROOT)); + parent_is_branch = ((emap[parent_v].size() > 2) || (vs[parent_v].flag & MVERT_SKIN_ROOT)); v = blender::bke::mesh::edge_other_vert(edges[e], parent_v); emat[e].origin = parent_v; @@ -765,10 +765,10 @@ static void build_emats_stack(BLI_Stack *stack, } /* Add neighbors to stack */ - for (i = 0; i < emap[v].count; i++) { + for (i = 0; i < emap[v].size(); i++) { /* Add neighbors to stack */ copy_m3_m3(stack_elem.mat, emat[e].mat); - stack_elem.e = emap[v].indices[i]; + stack_elem.e = emap[v][i]; stack_elem.parent_v = v; BLI_stack_push(stack, &stack_elem); } @@ -778,7 +778,7 @@ static EMat *build_edge_mats(const MVertSkin *vs, const float (*vert_positions)[3], const int verts_num, const blender::Span edges, - const MeshElemMap *emap, + blender::GroupedSpan emap, bool *has_valid_root) { BLI_Stack *stack; @@ -796,16 +796,16 @@ static EMat *build_edge_mats(const MVertSkin *vs, * children to the stack */ for (v = 0; v < verts_num; v++) { if (vs[v].flag & MVERT_SKIN_ROOT) { - if (emap[v].count >= 1) { - const blender::int2 &edge = edges[emap[v].indices[0]]; + if (emap[v].size() >= 1) { + const blender::int2 &edge = edges[emap[v][0]]; calc_edge_mat(stack_elem.mat, vert_positions[v], vert_positions[blender::bke::mesh::edge_other_vert(edge, v)]); stack_elem.parent_v = v; /* Add adjacent edges to stack */ - for (i = 0; i < emap[v].count; i++) { - stack_elem.e = emap[v].indices[i]; + for (i = 0; i < emap[v].size(); i++) { + stack_elem.e = emap[v][i]; BLI_stack_push(stack, &stack_elem); } @@ -1568,7 +1568,7 @@ static void hull_merge_triangles(SkinOutput *so, const SkinModifierData *smd) static void skin_merge_close_frame_verts(SkinNode *skin_nodes, int verts_num, - const MeshElemMap *emap, + blender::GroupedSpan emap, const blender::Span edges) { Frame **hull_frames; @@ -1790,7 +1790,7 @@ static void skin_smooth_hulls(BMesh *bm, static bool skin_output_branch_hulls(SkinOutput *so, SkinNode *skin_nodes, int verts_num, - const MeshElemMap *emap, + blender::GroupedSpan emap, const blender::Span edges) { bool result = true; @@ -1824,7 +1824,7 @@ ENUM_OPERATORS(eSkinErrorFlag, SKIN_ERROR_HULL); static BMesh *build_skin(SkinNode *skin_nodes, int verts_num, - const MeshElemMap *emap, + blender::GroupedSpan emap, const blender::Span edges, const MDeformVert *input_dvert, SkinModifierData *smd, @@ -1913,8 +1913,6 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd, eSkinErrorFlag *r_ BMesh *bm; EMat *emat; SkinNode *skin_nodes; - MeshElemMap *emap; - int *emapmem; const MDeformVert *dvert; bool has_valid_root = false; @@ -1926,18 +1924,19 @@ static Mesh *base_skin(Mesh *origmesh, SkinModifierData *smd, eSkinErrorFlag *r_ dvert = BKE_mesh_deform_verts(origmesh); const int verts_num = origmesh->totvert; - BKE_mesh_vert_edge_map_create(&emap, &emapmem, edges.data(), verts_num, edges.size()); + blender::Array vert_to_edge_offsets; + blender::Array vert_to_edge_indices; + const blender::GroupedSpan vert_to_edge = blender::bke::mesh::build_vert_to_edge_map( + edges, verts_num, vert_to_edge_offsets, vert_to_edge_indices); - emat = build_edge_mats(nodes, vert_positions, verts_num, edges, emap, &has_valid_root); - skin_nodes = build_frames(vert_positions, verts_num, nodes, emap, emat); + emat = build_edge_mats(nodes, vert_positions, verts_num, edges, vert_to_edge, &has_valid_root); + skin_nodes = build_frames(vert_positions, verts_num, nodes, vert_to_edge, emat); MEM_freeN(emat); emat = nullptr; - bm = build_skin(skin_nodes, verts_num, emap, edges, dvert, smd, r_error); + bm = build_skin(skin_nodes, verts_num, vert_to_edge, edges, dvert, smd, r_error); MEM_freeN(skin_nodes); - MEM_freeN(emap); - MEM_freeN(emapmem); if (!has_valid_root) { *r_error |= SKIN_ERROR_NO_VALID_ROOT; diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.cc b/source/blender/modifiers/intern/MOD_weighted_normal.cc index d20ecbaf473..447d6d5d102 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.cc +++ b/source/blender/modifiers/intern/MOD_weighted_normal.cc @@ -538,7 +538,7 @@ static Mesh *modifyMesh(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_poly_map = bke::mesh_topology::build_loop_to_poly_map(result->polys()); + const Array loop_to_poly_map = bke::mesh::build_loop_to_poly_map(result->polys()); 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_blur_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc index 0c64781d539..cda23543272 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_blur_attribute.cc @@ -131,119 +131,128 @@ static void node_update(bNodeTree *ntree, bNode *node) bke::nodeSetSocketAvailability(ntree, out_socket_value_color4f, data_type == CD_PROP_COLOR); } -static Array> build_vert_to_vert_by_edge_map(const Span edges, - const int verts_num) +static void build_vert_to_vert_by_edge_map(const Span edges, + const int verts_num, + Array &r_offsets, + Array &r_indices) { - Array> map(verts_num); - for (const int2 &edge : edges) { - map[edge[0]].append(edge[1]); - map[edge[1]].append(edge[0]); - } - return map; -} - -static Array> build_edge_to_edge_by_vert_map(const Span edges, - const int verts_num, - const IndexMask edge_mask) -{ - Array> map(edges.size()); - Array> vert_to_edge_map = bke::mesh_topology::build_vert_to_edge_map(edges, - verts_num); - - threading::parallel_for(edge_mask.index_range(), 1024, [&](IndexRange range) { - for (const int edge_i : edge_mask.slice(range)) { - - Vector &self_edges = map[edge_i]; - const Span vert_1_edges = vert_to_edge_map[edges[edge_i][0]]; - const Span vert_2_edges = vert_to_edge_map[edges[edge_i][1]]; - - self_edges.reserve(vert_1_edges.size() - 1 + vert_2_edges.size() - 1); - - for (const int i : vert_1_edges) { - if (i != edge_i) { - self_edges.append(i); - } - } - for (const int i : vert_2_edges) { - if (i != edge_i) { - self_edges.append(i); - } + bke::mesh::build_vert_to_edge_map(edges, verts_num, r_offsets, r_indices); + const OffsetIndices offsets(r_offsets); + threading::parallel_for(IndexRange(verts_num), 2048, [&](const IndexRange range) { + for (const int vert : range) { + MutableSpan neighbors = r_indices.as_mutable_span().slice(offsets[vert]); + for (const int i : neighbors.index_range()) { + neighbors[i] = bke::mesh::edge_other_vert(edges[neighbors[i]], vert); } } }); - return map; } -static Array> build_face_to_edge_by_loop_map(const OffsetIndices polys, - const Span corner_edges, - const int edges_num) +static void build_edge_to_edge_by_vert_map(const Span edges, + const int verts_num, + Array &r_offsets, + Array &r_indices) { - Array> map(edges_num); - for (const int i : polys.index_range()) { - for (const int edge : corner_edges.slice(polys[i])) { - map[edge].append(i); + Array vert_to_edge_offset_data; + Array vert_to_edge_indices; + const GroupedSpan vert_to_edge = bke::mesh::build_vert_to_edge_map( + edges, verts_num, vert_to_edge_offset_data, vert_to_edge_indices); + const OffsetIndices vert_to_edge_offsets(vert_to_edge_offset_data); + + r_offsets = Array(edges.size() + 1, 0); + threading::parallel_for(edges.index_range(), 1024, [&](const IndexRange range) { + for (const int edge_i : range) { + const int2 edge = edges[edge_i]; + r_offsets[edge_i] = vert_to_edge_offsets[edge[0]].size() - 1 + + vert_to_edge_offsets[edge[1]].size() - 1; } - } - return map; -} + }); + const OffsetIndices offsets = offset_indices::accumulate_counts_to_offsets(r_offsets); + r_indices.reinitialize(offsets.total_size()); -static Array> build_face_to_face_by_edge_map(const OffsetIndices polys, - const Span corner_edges, - const int edges_num, - const IndexMask poly_mask) -{ - Array> map(polys.size()); - Array> faces_by_edge = build_face_to_edge_by_loop_map( - polys, corner_edges, edges_num); - - threading::parallel_for(poly_mask.index_range(), 1024, [&](IndexRange range) { - for (const int poly_i : poly_mask.slice(range)) { - for (const int edge : corner_edges.slice(polys[poly_i])) { - if (faces_by_edge[edge].size() > 1) { - for (const int neighbor : faces_by_edge[edge]) { - if (neighbor != poly_i) { - map[poly_i].append(neighbor); - } + threading::parallel_for(edges.index_range(), 1024, [&](const IndexRange range) { + for (const int edge_i : range) { + const int2 edge = edges[edge_i]; + MutableSpan neighbors = r_indices.as_mutable_span().slice(offsets[edge_i]); + int count = 0; + for (const Span neighbor_edges : {vert_to_edge[edge[0]], vert_to_edge[edge[1]]}) { + for (const int neighbor_edge : neighbor_edges) { + if (neighbor_edge != edge_i) { + neighbors[count] = neighbor_edge; + count++; } } } } }); - return map; } -static Array> create_mesh_map(const Mesh &mesh, - const eAttrDomain domain, - const IndexMask mask) +static void build_face_to_face_by_edge_map(const OffsetIndices polys, + const Span corner_edges, + const int edges_num, + Array &r_offsets, + Array &r_indices) +{ + Array edge_to_poly_offsets; + Array edge_to_poly_indices; + const GroupedSpan edge_to_poly_map = bke::mesh::build_edge_to_poly_map( + polys, corner_edges, edges_num, edge_to_poly_offsets, edge_to_poly_indices); + + r_offsets = Array(polys.size() + 1, 0); + for (const int poly_i : polys.index_range()) { + for (const int edge : corner_edges.slice(polys[poly_i])) { + for (const int neighbor : edge_to_poly_map[edge]) { + if (neighbor != poly_i) { + r_offsets[poly_i]++; + } + } + } + } + const OffsetIndices offsets = offset_indices::accumulate_counts_to_offsets(r_offsets); + r_indices.reinitialize(offsets.total_size()); + + threading::parallel_for(polys.index_range(), 1024, [&](IndexRange range) { + for (const int poly_i : range) { + MutableSpan neighbors = r_indices.as_mutable_span().slice(offsets[poly_i]); + int count = 0; + for (const int edge : corner_edges.slice(polys[poly_i])) { + for (const int neighbor : edge_to_poly_map[edge]) { + if (neighbor != poly_i) { + neighbors[count] = neighbor; + count++; + } + } + } + } + }); +} + +static GroupedSpan create_mesh_map(const Mesh &mesh, + const eAttrDomain domain, + Array &r_offsets, + Array &r_indices) { switch (domain) { - case ATTR_DOMAIN_POINT: { - const Span edges = mesh.edges(); - const int verts_num = mesh.totvert; - return build_vert_to_vert_by_edge_map(edges, verts_num); - } - case ATTR_DOMAIN_EDGE: { - const Span edges = mesh.edges(); - const int verts_num = mesh.totvert; - return build_edge_to_edge_by_vert_map(edges, verts_num, mask); - } - case ATTR_DOMAIN_FACE: { - const OffsetIndices polys = mesh.polys(); - const int edges_num = mesh.totedge; - return build_face_to_face_by_edge_map(polys, mesh.corner_edges(), edges_num, mask); - } - case ATTR_DOMAIN_CORNER: { - return {}; - } + case ATTR_DOMAIN_POINT: + build_vert_to_vert_by_edge_map(mesh.edges(), mesh.totvert, r_offsets, r_indices); + break; + case ATTR_DOMAIN_EDGE: + build_edge_to_edge_by_vert_map(mesh.edges(), mesh.totvert, r_offsets, r_indices); + break; + case ATTR_DOMAIN_FACE: + build_face_to_face_by_edge_map( + mesh.polys(), mesh.corner_edges(), mesh.totedge, r_offsets, r_indices); + break; default: BLI_assert_unreachable(); - return {}; + break; } + return {OffsetIndices(r_offsets), r_indices}; } template static Span blur_on_mesh_exec(const Span neighbor_weights, - const Span> neighbors_map, + const GroupedSpan neighbors_map, const int iterations, const MutableSpan buffer_a, const MutableSpan buffer_b) @@ -279,10 +288,11 @@ static GSpan blur_on_mesh(const Mesh &mesh, const GMutableSpan buffer_a, const GMutableSpan buffer_b) { - Array> neighbors_map = create_mesh_map(mesh, domain, neighbor_weights.index_range()); - if (neighbors_map.is_empty()) { - return buffer_a; - } + Array neighbor_offsets; + Array neighbor_indices; + const GroupedSpan neighbors_map = create_mesh_map( + mesh, domain, neighbor_offsets, neighbor_indices); + GSpan result_buffer; bke::attribute_math::convert_to_static_type(buffer_a.type(), [&](auto dummy) { using T = decltype(dummy); 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 ccf7521badb..d439d72f33c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -534,7 +534,7 @@ static bool vertex_needs_dissolving(const int vertex, const int first_poly_index, const int second_poly_index, const Span vertex_types, - const Span> vert_to_poly_map) + const GroupedSpan vert_to_poly_map) { /* Order is guaranteed to be the same because 2poly verts that are not on the boundary are * ignored in `sort_vertex_polys`. */ @@ -553,7 +553,7 @@ static bool vertex_needs_dissolving(const int vertex, static void dissolve_redundant_verts(const Span edges, const OffsetIndices polys, const Span corner_edges, - const Span> vert_to_poly_map, + const GroupedSpan vert_to_poly_map, MutableSpan vertex_types, MutableSpan old_to_new_edges_map, Vector &new_edges, @@ -628,11 +628,19 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, /* Stores the indices of the polygons connected to the vertex. Because the polygons are looped * over in order of their indices, the polygon's indices will be sorted in ascending order. * (This can change once they are sorted using `sort_vertex_polys`). */ - Array> vert_to_poly_map = bke::mesh_topology::build_vert_to_poly_map( - src_polys, src_corner_verts, src_positions.size()); + Array vert_to_poly_offset_data; + Array vert_to_poly_indices; + const GroupedSpan vert_to_poly_map = bke::mesh::build_vert_to_poly_map( + src_polys, + src_corner_verts, + src_positions.size(), + vert_to_poly_offset_data, + vert_to_poly_indices); + const OffsetIndices vert_to_poly_offsets(vert_to_poly_offset_data); + Array> vertex_shared_edges(src_mesh.totvert); Array> vertex_corners(src_mesh.totvert); - threading::parallel_for(vert_to_poly_map.index_range(), 512, [&](IndexRange range) { + threading::parallel_for(src_positions.index_range(), 512, [&](IndexRange range) { for (const int i : range) { if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold || (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) @@ -640,7 +648,8 @@ static Mesh *calc_dual_mesh(const Mesh &src_mesh, /* Bad vertex that we can't work with. */ continue; } - MutableSpan loop_indices = vert_to_poly_map[i]; + MutableSpan loop_indices = vert_to_poly_indices.as_mutable_span().slice( + vert_to_poly_offsets[i]); Array sorted_corners(loop_indices.size()); bool vertex_ok = true; if (vertex_types[i] == VertexType::Normal) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_edges_to_face_groups.cc b/source/blender/nodes/geometry/nodes/node_geo_edges_to_face_groups.cc index 0399d8620c9..cd17886ccf7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edges_to_face_groups.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edges_to_face_groups.cc @@ -54,8 +54,10 @@ class FaceSetFromBoundariesInput final : public bke::MeshFieldInput { const OffsetIndices polys = mesh.polys(); - const Array> edge_to_face_map = bke::mesh_topology::build_edge_to_poly_map( - polys, mesh.corner_edges(), mesh.totedge); + Array edge_to_face_offsets; + Array edge_to_face_indices; + const GroupedSpan edge_to_face_map = bke::mesh::build_edge_to_poly_map( + polys, mesh.corner_edges(), mesh.totedge, edge_to_face_offsets, edge_to_face_indices); AtomicDisjointSet islands(polys.size()); for (const int edge : non_boundary_edges) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc index 13e64e7f857..802bfb901d2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_extrude_mesh.cc @@ -441,8 +441,10 @@ static void extrude_mesh_edges(Mesh &mesh, return; } - const Array> edge_to_poly_map = bke::mesh_topology::build_edge_to_poly_map( - orig_polys, mesh.corner_edges(), mesh.totedge); + Array edge_to_poly_offsets; + Array edge_to_poly_indices; + const GroupedSpan edge_to_poly_map = bke::mesh::build_edge_to_poly_map( + orig_polys, mesh.corner_edges(), mesh.totedge, edge_to_poly_offsets, edge_to_poly_indices); /* Find the offsets on the vertex domain for translation. This must be done before the mesh's * custom data layers are reallocated, in case the virtual array references one of them. */ @@ -579,7 +581,7 @@ static void extrude_mesh_edges(Mesh &mesh, * original edge. */ copy_with_mixing( attribute.span, - [&](const int i) { return edge_to_poly_map[edge_selection[i]].as_span(); }, + [&](const int i) { return edge_to_poly_map[edge_selection[i]]; }, attribute.span.slice(new_poly_range)); break; } @@ -749,8 +751,10 @@ static void extrude_mesh_face_regions(Mesh &mesh, } /* All of the faces (selected and deselected) connected to each edge. */ - const Array> edge_to_poly_map = bke::mesh_topology::build_edge_to_poly_map( - orig_polys, mesh.corner_edges(), orig_edges.size()); + Array edge_to_poly_offsets; + Array edge_to_poly_indices; + const GroupedSpan edge_to_poly_map = bke::mesh::build_edge_to_poly_map( + orig_polys, mesh.corner_edges(), mesh.totedge, edge_to_poly_offsets, edge_to_poly_indices); /* All vertices that are connected to the selected polygons. * Start the size at one vert per poly to reduce unnecessary reallocation. */ 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 b5ff2f3a7dc..f99efcbd5b2 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 @@ -54,9 +54,10 @@ class CornersOfVertInput final : public bke::MeshFieldInput { const IndexMask mask) const final { const IndexRange vert_range(mesh.totvert); - const Span corner_verts = mesh.corner_verts(); - Array> vert_to_loop_map = bke::mesh_topology::build_vert_to_loop_map(corner_verts, - 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 bke::MeshFieldContext context{mesh, domain}; fn::FieldEvaluator evaluator{context, &mask}; @@ -67,7 +68,7 @@ class CornersOfVertInput final : public bke::MeshFieldInput { const VArray indices_in_sort = evaluator.get_evaluated(1); const bke::MeshFieldContext corner_context{mesh, ATTR_DOMAIN_CORNER}; - fn::FieldEvaluator corner_evaluator{corner_context, corner_verts.size()}; + fn::FieldEvaluator corner_evaluator{corner_context, mesh.totloop}; corner_evaluator.add(sort_weight_); corner_evaluator.evaluate(); const VArray all_sort_weights = corner_evaluator.get_evaluated(0); 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 2bd74c25838..f601464dde7 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 @@ -76,7 +76,7 @@ class CornerPreviousEdgeFieldInput final : public bke::MeshFieldInput { } const OffsetIndices polys = mesh.polys(); const Span corner_edges = mesh.corner_edges(); - Array loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys); + Array loop_to_poly_map = bke::mesh::build_loop_to_poly_map(polys); return VArray::ForFunc( mesh.totloop, [polys, corner_edges, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc index c44771657e0..c1fad4ea87d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_topology_edges_of_vertex.cc @@ -55,8 +55,10 @@ class EdgesOfVertInput final : public bke::MeshFieldInput { { const IndexRange vert_range(mesh.totvert); const Span edges = mesh.edges(); - const Array> vert_to_edge_map = bke::mesh_topology::build_vert_to_edge_map( - edges, mesh.totvert); + Array map_offsets; + Array map_indices; + const GroupedSpan vert_to_edge_map = bke::mesh::build_vert_to_edge_map( + edges, mesh.totvert, map_offsets, map_indices); const bke::MeshFieldContext context{mesh, domain}; fn::FieldEvaluator evaluator{context, &mask}; 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 efe7d3835ac..c9eefa8cef2 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 @@ -34,7 +34,7 @@ class CornerFaceIndexInput final : public bke::MeshFieldInput { if (domain != ATTR_DOMAIN_CORNER) { return {}; } - return VArray::ForContainer(bke::mesh_topology::build_loop_to_poly_map(mesh.polys())); + return VArray::ForContainer(bke::mesh::build_loop_to_poly_map(mesh.polys())); } uint64_t hash() const final @@ -63,7 +63,7 @@ class CornerIndexInFaceInput final : public bke::MeshFieldInput { return {}; } const OffsetIndices polys = mesh.polys(); - Array loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys); + Array loop_to_poly_map = bke::mesh::build_loop_to_poly_map(polys); return VArray::ForFunc( mesh.totloop, [polys, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) { const int poly_i = loop_to_poly_map[corner_i]; 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 8b22769e59a..162faefa2f9 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 @@ -50,7 +50,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_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys); + Array loop_to_poly_map = bke::mesh::build_loop_to_poly_map(polys); Array offset_corners(mask.min_array_size()); threading::parallel_for(mask.index_range(), 2048, [&](const IndexRange range) { diff --git a/source/blender/render/intern/texture_margin.cc b/source/blender/render/intern/texture_margin.cc index da8e9ef1cce..c151b749cd7 100644 --- a/source/blender/render/intern/texture_margin.cc +++ b/source/blender/render/intern/texture_margin.cc @@ -282,7 +282,7 @@ class TextureMarginMap { void build_tables() { - loop_to_poly_map_ = blender::bke::mesh_topology::build_loop_to_poly_map(polys_); + loop_to_poly_map_ = blender::bke::mesh::build_loop_to_poly_map(polys_); loop_adjacency_map_.resize(corner_edges_.size(), -1);