Mesh: Reimplement and unify topology maps #107861

Merged
Hans Goudey merged 14 commits from HooglyBoogly/blender:cleanup-unify-mesh-maps into main 2023-05-24 13:17:03 +02:00
48 changed files with 713 additions and 1013 deletions

View File

@ -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<int> 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<int> 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<int> 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<int> 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<int> build_loop_to_poly_map(OffsetIndices<int> polys);
Array<Vector<int>> build_vert_to_edge_map(Span<int2> edges, int verts_num);
Array<Vector<int>> build_vert_to_poly_map(OffsetIndices<int> polys,
Span<int> corner_verts,
int verts_num);
Array<Vector<int>> build_vert_to_loop_map(Span<int> corner_verts, int verts_num);
Array<Vector<int>> build_edge_to_loop_map(Span<int> corner_edges, int edges_num);
Array<Vector<int, 2>> build_edge_to_poly_map(OffsetIndices<int> polys,
Span<int> corner_edges,
int edges_num);
Vector<Vector<int>> build_edge_to_loop_map_resizable(Span<int> corner_edges, int edges_num);
GroupedSpan<int> build_vert_to_edge_map(Span<int2> edges,
int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices);
} // namespace blender::bke::mesh_topology
GroupedSpan<int> build_vert_to_poly_map(OffsetIndices<int> polys,
Span<int> corner_verts,
int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices);
GroupedSpan<int> build_vert_to_loop_map(Span<int> corner_verts,
int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices);
GroupedSpan<int> build_edge_to_loop_map(Span<int> corner_edges,
int edges_num,
Array<int> &r_offsets,
Array<int> &r_indices);
GroupedSpan<int> build_edge_to_poly_map(OffsetIndices<int> polys,
Span<int> corner_edges,
int edges_num,
Array<int> &r_offsets,
Array<int> &r_indices);
} // namespace blender::bke::mesh
#endif

View File

@ -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<int> vert_to_loop_offsets;
blender::Array<int> vert_to_loop_indices;
blender::GroupedSpan<int> vert_to_loop;
blender::Array<int> vert_to_poly_offsets;
blender::Array<int> vert_to_poly_indices;
blender::GroupedSpan<int> 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<int> vert_to_poly_offsets;
blender::Array<int> vert_to_poly_indices;
blender::GroupedSpan<int> pmap;
/* Edges to adjacent polys. */
struct MeshElemMap *epmap;
int *epmap_mem;
blender::Array<int> edge_to_poly_offsets;
blender::Array<int> edge_to_poly_indices;
blender::GroupedSpan<int> epmap;
/* Vertices to adjacent edges. */
struct MeshElemMap *vemap;
int *vemap_mem;
blender::Array<int> vert_to_edge_offsets;
blender::Array<int> vert_to_edge_indices;
blender::GroupedSpan<int> 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;

View File

@ -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<int> pmap);
}
namespace blender::bke::pbvh {

View File

@ -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<int> vert_to_edge_map,
int coarse_edge_index,
bool is_simple,
float u,

View File

@ -66,9 +66,9 @@ class FairingContext {
return totvert_;
}
MeshElemMap *vertex_loop_map_get(const int v)
Span<int> 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<int> 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<int> 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,
HooglyBoogly marked this conversation as resolved Outdated

Remove destructor because it's empty.

Remove destructor because it's empty.
@ -252,6 +245,8 @@ class MeshFairingContext : public FairingContext {
blender::OffsetIndices<int> polys;
Span<blender::int2> edges_;
Array<int> loop_to_poly_map_;
Array<int> vert_to_poly_offsets_;
Array<int> 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<int>(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 *> bmloop_;
Array<BMLoop *> bmloop_;
Array<int> vert_to_loop_offsets_;
Array<int> 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<int> 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);

View File

@ -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<int> polys,
const int *corner_verts,
int totvert,
const bool do_loops)
{
MeshElemMap *map = MEM_cnew_array<MeshElemMap>(size_t(totvert), __func__);
int *indices, *index_iter;
indices = static_cast<int *>(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<int> 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<int> 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<MeshElemMap>(size_t(totvert), __func__);
int *indices = static_cast<int *>(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<MeshElemMap>(size_t(totvert), __func__);
int *indices = static_cast<int *>(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<int> polys,
const int *corner_edges,
const int totloop)
{
using namespace blender;
MeshElemMap *map = MEM_cnew_array<MeshElemMap>(size_t(totedge), __func__);
int *indices = static_cast<int *>(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<int> polys,
const int *corner_edges,
const int totloop)
{
MeshElemMap *map = MEM_cnew_array<MeshElemMap>(size_t(totedge), __func__);
int *indices = static_cast<int *>(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<int> create_reverse_offsets(const Span<int> indices, const int items_num)
{
Array<int> offsets(items_num + 1, 0);
for (const int i : indices) {
offsets[i]++;
}
offset_indices::accumulate_counts_to_offsets(offsets);
return offsets;
}
Array<int> build_loop_to_poly_map(const OffsetIndices<int> polys)
{
@ -531,72 +313,97 @@ Array<int> build_loop_to_poly_map(const OffsetIndices<int> polys)
return map;
}
Array<Vector<int>> build_vert_to_edge_map(const Span<int2> edges, const int verts_num)
GroupedSpan<int> build_vert_to_edge_map(const Span<int2> edges,
const int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices)
{
Array<Vector<int>> 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<int>(), verts_num);
r_indices.reinitialize(r_offsets.last());
Array<int> counts(verts_num, 0);
Array<Vector<int>> build_vert_to_poly_map(const OffsetIndices<int> polys,
const Span<int> corner_verts,
int verts_num)
{
Array<Vector<int>> 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<int>(r_offsets), r_indices};
}
Array<Vector<int>> build_vert_to_loop_map(const Span<int> corner_verts, const int verts_num)
GroupedSpan<int> build_vert_to_poly_map(const OffsetIndices<int> polys,
const Span<int> corner_verts,
const int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices)
{
Array<Vector<int>> 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<int> counts(verts_num, 0);
Array<Vector<int>> build_edge_to_loop_map(const Span<int> corner_edges, const int edges_num)
{
Array<Vector<int>> map(edges_num);
for (const int64_t i : corner_edges.index_range()) {
map[corner_edges[i]].append(int(i));
}
return map;
}
Array<Vector<int, 2>> build_edge_to_poly_map(const OffsetIndices<int> polys,
const Span<int> corner_edges,
const int edges_num)
{
Array<Vector<int, 2>> 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<int>(r_offsets), r_indices};
}
Vector<Vector<int>> build_edge_to_loop_map_resizable(const Span<int> corner_edges,
const int edges_num)
GroupedSpan<int> build_vert_to_loop_map(const Span<int> corner_verts,
const int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices)
{
Vector<Vector<int>> 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<int> 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<int>(r_offsets), r_indices};
}
} // namespace blender::bke::mesh_topology
GroupedSpan<int> build_edge_to_loop_map(const Span<int> corner_edges,
const int edges_num,
Array<int> &r_offsets,
Array<int> &r_indices)
{
r_offsets = create_reverse_offsets(corner_edges, edges_num);
r_indices.reinitialize(r_offsets.last());
Array<int> 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<int>(r_offsets), r_indices};
}
GroupedSpan<int> build_edge_to_poly_map(const OffsetIndices<int> polys,
const Span<int> corner_edges,
const int edges_num,
Array<int> &r_offsets,
Array<int> &r_indices)
{
r_offsets = create_reverse_offsets(corner_edges, edges_num);
r_indices.reinitialize(r_offsets.last());
Array<int> 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<int>(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<int> edge_poly_map_elem)>;
static void poly_edge_loop_islands_calc(const int totedge,
const blender::OffsetIndices<int> polys,
const blender::Span<int> corner_edges,
MeshElemMap *edge_poly_map,
blender::GroupedSpan<int> 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<int> edge_to_poly_src_offsets;
blender::Array<int> 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<int *>(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<int> 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<int> 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<int> edge_to_poly_offsets;
Array<int> edge_to_poly_indices;
const GroupedSpan<int> 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<int> edge_to_loop_offsets;
Array<int> edge_to_loop_indices;
GroupedSpan<int> 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<int> /*edge_poly_map_elem*/) -> bool {
if (luvs) {
const MeshElemMap &edge_to_loops = edge_loop_map[corner_edges[loop_index]];
const Span<int> 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);

View File

@ -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<int> vert_to_loop_offsets;
Array<int> vert_to_loop_indices;
const GroupedSpan<int> vert_to_loop = bke::mesh::build_vert_to_loop_map(
me->corner_verts(), me->totvert, vert_to_loop_offsets, vert_to_loop_indices);
Vector<float2 *> 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<int> 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);
}

View File

@ -819,7 +819,7 @@ void edges_sharp_from_angle_set(const OffsetIndices<int> polys,
Array<int2> edge_to_loops(sharp_edges.size(), int2(0));
/* Simple mapping from a loop to its polygon index. */
const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map(polys);
const Array<int> 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<float3> vert_positions,
Span<int> loop_to_poly;
Array<int> 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<int> item_indices,
Array<int> &r_reverse_indices)
{
r_offsets = Array<int>(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<int> count_per_item(items_num, 0);
@ -1465,7 +1462,7 @@ static void mesh_normals_loop_custom_set(Span<float3> positions,
CornerNormalSpaceArray lnors_spacearr;
BitVector<> done_loops(corner_verts.size(), false);
Array<float3> loop_normals(corner_verts.size());
const Array<int> loop_to_poly = mesh_topology::build_loop_to_poly_map(polys);
const Array<int> 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;

View File

@ -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<blender::int2> 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<int> vert_to_edge_src_offsets;
Array<int> vert_to_edge_src_indices;
const GroupedSpan<int> 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<blender::float3> positions,
const blender::OffsetIndices<int> polys,
const blender::Span<int> 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<blender::float3> positions,
const blender::OffsetIndices<int> polys,
const blender::Span<int> corner_verts,
const int edge_idx,
BLI_bitmap *done_edges,
const blender::GroupedSpan<int> edge_to_poly_map,
const bool is_edge_innercut,
const int *poly_island_index_map,
float (*poly_centers)[3],
uchar *poly_status)
{
blender::Array<int, 16> poly_island_indices(edge_to_poly_map[edge_idx].count);
blender::Array<int, 16> 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<blender::float3> positions,
MeshElemMap *edge_to_poly_map,
const blender::GroupedSpan<int> edge_to_poly_map,
const int numedges,
const blender::OffsetIndices<int> polys,
const blender::Span<int> 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<blender::float3> 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<int> vert_to_loop_src_offsets;
Array<int> vert_to_loop_src_indices;
GroupedSpan<int> vert_to_loop_map_src;
Array<int> vert_to_poly_src_offsets;
Array<int> vert_to_poly_src_indices;
GroupedSpan<int> vert_to_poly_map_src;
Array<int> edge_to_poly_src_offsets;
Array<int> edge_to_poly_src_indices;
GroupedSpan<int> 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<int> 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);
}

View File

@ -363,10 +363,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<int> source_vert_to_loop_offsets;
Array<int> source_vert_to_loop_indices;
blender::GroupedSpan<int> source_lmap;
Array<int> target_vert_to_loop_offsets;
Array<int> target_vert_to_loop_indices;
blender::GroupedSpan<int> target_lmap;
while ((layer = BKE_id_attribute_from_index(
const_cast<ID *>(&source->id), i++, ATTR_DOMAIN_MASK_COLOR, CD_MASK_COLOR_ALL)))
@ -410,18 +413,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(
@ -437,10 +437,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<int> source_loops = source_lmap[nearest.index];
const Span<int> target_loops = target_lmap[i];
if (target_loops->count == 0 || source_loops->count == 0) {
if (target_loops.size() == 0 || source_loops.size() == 0) {
continue;
}
@ -451,18 +451,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);
}
@ -481,10 +480,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);
}

View File

@ -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)

View File

@ -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<int> vert_to_poly_offsets;
blender::Array<int> vert_to_poly_indices;
const blender::GroupedSpan<int> 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<float(*)[3]>(
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<int> 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

View File

@ -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);
}
/**

View File

@ -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) {

View File

@ -1396,7 +1396,7 @@ static void pbvh_faces_update_normals(PBVH *pbvh, Span<PBVHNode *> 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<PBVHNode *> 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<int> pmap)
{
pbvh->pmap = pmap;
}

View File

@ -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<T> colors{static_cast<const T *>(pbvh.color_layer->data) + poly.start(), poly.size()};
Span<int> 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<T> colors{static_cast<T *>(pbvh.color_layer->data) + poly.start(), poly.size()};
Span<int> poly_verts{pbvh.corner_verts + poly.start(), poly.size()};

View File

@ -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<int> pmap;
CustomDataLayer *color_layer;
eAttrDomain color_domain;

View File

@ -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<int> vert_to_edge_offsets;
blender::Array<int> vert_to_edge_indices;
blender::GroupedSpan<int> 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<int> 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<int> 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);
}
}

View File

@ -92,10 +92,50 @@ template<typename T> 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

My only very small concern with this type is that some might use multiple GroupSpan which all use the same offsets. In this case, it would be more efficient to lookup the range from the offsets only once. This is still possible of course, just a little less obvious.

My only very small concern with this type is that some might use multiple `GroupSpan` which all use the same `offsets`. In this case, it would be more efficient to lookup the range from the offsets only once. This is still possible of course, just a little less obvious.

Yeah, good point. Probably not necessary but I added a note in the classes description mentioning that.

Yeah, good point. Probably not necessary but I added a note in the classes description mentioning that.
* be more efficient to retrieve the #IndexRange only once and slice each span.
*/
template<typename T> struct GroupedSpan {
OffsetIndices<int> offsets;
Span<T> data;
GroupedSpan() = default;
HooglyBoogly marked this conversation as resolved
Review

Use this-> when refering to public data members.

Use `this->` when refering to public data members.
GroupedSpan(OffsetIndices<int> offsets, Span<T> data) : offsets(offsets), data(data)
{
BLI_assert(this->offsets.total_size() == this->data.size());
HooglyBoogly marked this conversation as resolved Outdated

vert_index -> index

`vert_index` -> `index`
}
Span<T> operator[](const int64_t index) const
{
return this->data.slice(this->offsets[index]);
HooglyBoogly marked this conversation as resolved Outdated

Also add a size and index_range method.

Also add a `size` and `index_range` method.
}
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<int> counts_to_offsets, int start_offset = 0);
OffsetIndices<int> accumulate_counts_to_offsets(MutableSpan<int> 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<int> counts_to_offsets, int start_
*/
void build_reverse_map(OffsetIndices<int> offsets, MutableSpan<int> r_map);
/**
* Build offsets to group the elements of \a indices pointing to the same index.
*/
void build_reverse_offsets(Span<int> indices, MutableSpan<int> r_map);
} // namespace blender::offset_indices
namespace blender {
using offset_indices::GroupedSpan;
using offset_indices::OffsetIndices;
}
} // namespace blender

View File

@ -5,7 +5,7 @@
namespace blender::offset_indices {
void accumulate_counts_to_offsets(MutableSpan<int> counts_to_offsets, const int start_offset)
OffsetIndices<int> accumulate_counts_to_offsets(MutableSpan<int> 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<int> counts_to_offsets, const int
offset += count;
}
counts_to_offsets.last() = offset;
return OffsetIndices<int>(counts_to_offsets);
}
void build_reverse_map(OffsetIndices<int> offsets, MutableSpan<int> r_map)
@ -26,4 +27,13 @@ void build_reverse_map(OffsetIndices<int> offsets, MutableSpan<int> r_map)
});
}
void build_reverse_offsets(const Span<int> indices, MutableSpan<int> 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

View File

@ -2236,13 +2236,10 @@ void DRW_subdivide_loose_geom(DRWSubdivCache *subdiv_cache, MeshBufferCache *cac
const Span<float3> coarse_positions = coarse_mesh->vert_positions();
const Span<int2> 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<int> vert_to_edge_offsets;
blender::Array<int> vert_to_edge_indices;
const blender::GroupedSpan<int> 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];
@ -2285,9 +2282,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];

View File

@ -795,10 +795,12 @@ void paintvert_select_more(Mesh *mesh, const bool face_step)
const Span<int> corner_verts = mesh->corner_verts();
const Span<int2> edges = mesh->edges();
Array<Vector<int, 2>> edge_to_face_map;
Array<int> edge_to_face_offsets;
Array<int> edge_to_face_indices;
GroupedSpan<int> 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<int> corner_verts = mesh->corner_verts();
const Span<int2> edges = mesh->edges();
MeshElemMap *edge_poly_map;
int *edge_poly_mem = nullptr;
GroupedSpan<int> edge_to_poly_map;
Array<int> edge_to_poly_offsets;
Array<int> 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<int> 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();
}

View File

@ -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<int> 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<MVertSkin *>(
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<int> vert_to_edge_offsets;
blender::Array<int> vert_to_edge_indices;
const blender::GroupedSpan<int> 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);

View File

@ -1569,9 +1569,6 @@ static void vgroup_smooth_subset(Object *ob,
BMesh *bm = em ? em->bm : nullptr;
Mesh *me = em ? nullptr : static_cast<Mesh *>(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<ID *>(ob->data), &dvert_array, &dvert_tot, false);
vgroup_subset_weights.fill(0.0f);
blender::Array<int> vert_to_edge_offsets;
blender::Array<int> vert_to_edge_indices;
blender::GroupedSpan<int> 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<float *>(
@ -1639,8 +1637,8 @@ static void vgroup_smooth_subset(Object *ob,
const blender::Span<int2> 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);
}

View File

@ -1246,15 +1246,11 @@ static void vertex_paint_init_session_data(const ToolSettings *ts, Object *ob)
const blender::OffsetIndices polys = me->polys();
const Span<int> 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<Color, Traits, domain> *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 */

View File

@ -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<int> 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++) {

View File

@ -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");

View File

@ -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. */

View File

@ -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<int> pmap = ss->pmap;
const blender::OffsetIndices polys = mesh->polys();
const blender::Span<int> 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;

View File

@ -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<int> 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<int> 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;
}

View File

@ -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,

View File

@ -174,10 +174,6 @@ static int sculpt_mask_filter_exec(bContext *C, wmOperator *op)
SCULPT_vertex_random_access_ensure(ss);
if (!ob->sculpt->pmap) {

I wonder if this is used as a check for emptyness or so and the code below depends on that, just a thought.

I wonder if this is used as a check for emptyness or so and the code below depends on that, just a thought.

Generally I think these are fairly paranoid checks and more likely hide bugs because some code didn't ensure the map was created before the operator was run. Removing them should be fine, and works in my tests.

Generally I think these are fairly paranoid checks and more likely hide bugs because some code didn't ensure the map was created before the operator was run. Removing them should be fine, and works in my tests.
return OPERATOR_CANCELLED;
}
int num_verts = SCULPT_vertex_count_get(ss);
Vector<PBVHNode *> nodes = blender::bke::pbvh::search_gather(pbvh, nullptr, nullptr);

View File

@ -95,13 +95,13 @@ static float *SCULPT_geodesic_mesh_create(Object *ob,
float *dists = static_cast<float *>(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)) {

View File

@ -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) {

Might also be used as a check to detect the no-polygon case.

Might also be used as a check to detect the no-polygon case.
return;
}
float brush_co[3];
copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss));

View File

@ -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);

View File

@ -372,11 +372,18 @@ void split_edges(Mesh &mesh,
}
/* Precalculate topology info. */
Array<Vector<int>> vert_to_edge_map = bke::mesh_topology::build_vert_to_edge_map(edges,
mesh.totvert);
Vector<Vector<int>> edge_to_loop_map = bke::mesh_topology::build_edge_to_loop_map_resizable(
mesh.corner_edges(), mesh.totedge);
Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(mesh.polys());
Array<Vector<int>> 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<int> orig_edge_to_loop_offsets;
Array<int> orig_edge_to_loop_indices;
const GroupedSpan<int> 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<int> loop_to_poly_map = bke::mesh::build_loop_to_poly_map(mesh.polys());
/* Store offsets, so we can split edges in parallel. */
Array<int> 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<int2> 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<Vector<int>> 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<int> new_to_old_edges_map(IndexRange(new_edges.size()).as_span());

View File

@ -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<int> emap,
const blender::Span<blender::int2> 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<Frame *>(*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<int> 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<int> 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<int> 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<int> emap,
EMat *emat)
{
int v;
@ -667,10 +667,10 @@ static SkinNode *build_frames(const float (*vert_positions)[3],
SkinNode *skin_nodes = MEM_cnew_array<SkinNode>(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<int> emap,
const blender::Span<blender::int2> 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<blender::int2> edges,
const MeshElemMap *emap,
blender::GroupedSpan<int> 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<int> emap,
const blender::Span<blender::int2> 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<int> emap,
const blender::Span<blender::int2> 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<int> emap,
const blender::Span<blender::int2> 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<int> vert_to_edge_offsets;
blender::Array<int> vert_to_edge_indices;
const blender::GroupedSpan<int> 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;

View File

@ -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<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(result->polys());
const Array<int> loop_to_poly_map = bke::mesh::build_loop_to_poly_map(result->polys());
bke::MutableAttributeAccessor attributes = result->attributes_for_write();
bke::SpanAttributeWriter<bool> sharp_edges = attributes.lookup_or_add_for_write_span<bool>(

View File

@ -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<Vector<int>> build_vert_to_vert_by_edge_map(const Span<int2> edges,
const int verts_num)
static void build_vert_to_vert_by_edge_map(const Span<int2> edges,
const int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices)
{
Array<Vector<int>> map(verts_num);
for (const int2 &edge : edges) {
map[edge[0]].append(edge[1]);
map[edge[1]].append(edge[0]);
}
return map;
}
static Array<Vector<int>> build_edge_to_edge_by_vert_map(const Span<int2> edges,
const int verts_num,
const IndexMask edge_mask)
{
Array<Vector<int>> map(edges.size());
Array<Vector<int>> 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<int> &self_edges = map[edge_i];
const Span<int> vert_1_edges = vert_to_edge_map[edges[edge_i][0]];
const Span<int> 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<int> offsets(r_offsets);
Review

Can you use GroupedSpan here?

Can you use `GroupedSpan` here?
Review

Not without a MutableGroupedSpan, which I wanted to avoid for now.

Not without a `MutableGroupedSpan`, which I wanted to avoid for now.
threading::parallel_for(IndexRange(verts_num), 2048, [&](const IndexRange range) {
for (const int vert : range) {
MutableSpan<int> 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);
Review

Unrelated, but just noticed that here. Think edge_other_vert could be implemented in a branchless way (when the error case can be ignored, which it can in many cases).
other_vert = edge.v1 + edge.v2 - query_vert

Unrelated, but just noticed that here. Think `edge_other_vert` could be implemented in a branchless way (when the error case can be ignored, which it can in many cases). `other_vert = edge.v1 + edge.v2 - query_vert`
Review

I wonder if we would care about potential overflow in that case. I guess it's crazy for a mesh to have 1-2 billion edges or so, but maybe it's possible.

I wonder if we would care about potential overflow in that case. I guess it's crazy for a mesh to have 1-2 billion edges or so, but maybe it's possible.
}
}
});
return map;
}
static Array<Vector<int>> build_face_to_edge_by_loop_map(const OffsetIndices<int> polys,
const Span<int> corner_edges,
const int edges_num)
static void build_edge_to_edge_by_vert_map(const Span<int2> edges,
const int verts_num,
Array<int> &r_offsets,
Array<int> &r_indices)
{
Array<Vector<int>> map(edges_num);
for (const int i : polys.index_range()) {
for (const int edge : corner_edges.slice(polys[i])) {
map[edge].append(i);
Array<int> vert_to_edge_offset_data;
Array<int> vert_to_edge_indices;
const GroupedSpan<int> vert_to_edge = bke::mesh::build_vert_to_edge_map(
edges, verts_num, vert_to_edge_offset_data, vert_to_edge_indices);
const OffsetIndices<int> vert_to_edge_offsets(vert_to_edge_offset_data);
r_offsets = Array<int>(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<Vector<int>> build_face_to_face_by_edge_map(const OffsetIndices<int> polys,
const Span<int> corner_edges,
const int edges_num,
const IndexMask poly_mask)
{
Array<Vector<int>> map(polys.size());
Array<Vector<int>> 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<int> neighbors = r_indices.as_mutable_span().slice(offsets[edge_i]);
int count = 0;
for (const Span<int> 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<Vector<int>> create_mesh_map(const Mesh &mesh,
const eAttrDomain domain,
const IndexMask mask)
static void build_face_to_face_by_edge_map(const OffsetIndices<int> polys,
const Span<int> corner_edges,
const int edges_num,
Array<int> &r_offsets,
Array<int> &r_indices)
{
Array<int> edge_to_poly_offsets;
Array<int> edge_to_poly_indices;
const GroupedSpan<int> 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<int>(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<int> 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<int> create_mesh_map(const Mesh &mesh,
const eAttrDomain domain,
Array<int> &r_offsets,
Array<int> &r_indices)
{
switch (domain) {
case ATTR_DOMAIN_POINT: {
const Span<int2> 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<int2> 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<int>(r_offsets), r_indices};
}
template<typename T>
static Span<T> blur_on_mesh_exec(const Span<float> neighbor_weights,
const Span<Vector<int>> neighbors_map,
const GroupedSpan<int> neighbors_map,
const int iterations,
const MutableSpan<T> buffer_a,
const MutableSpan<T> buffer_b)
@ -279,10 +288,11 @@ static GSpan blur_on_mesh(const Mesh &mesh,
const GMutableSpan buffer_a,
const GMutableSpan buffer_b)
{
Array<Vector<int>> neighbors_map = create_mesh_map(mesh, domain, neighbor_weights.index_range());
if (neighbors_map.is_empty()) {
return buffer_a;
}
Array<int> neighbor_offsets;
Array<int> neighbor_indices;
const GroupedSpan<int> 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);

View File

@ -534,7 +534,7 @@ static bool vertex_needs_dissolving(const int vertex,
const int first_poly_index,
const int second_poly_index,
const Span<VertexType> vertex_types,
const Span<Vector<int>> vert_to_poly_map)
const GroupedSpan<int> 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<int2> edges,
const OffsetIndices<int> polys,
const Span<int> corner_edges,
const Span<Vector<int>> vert_to_poly_map,
const GroupedSpan<int> vert_to_poly_map,
MutableSpan<VertexType> vertex_types,
MutableSpan<int> old_to_new_edges_map,
Vector<int2> &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<Vector<int>> vert_to_poly_map = bke::mesh_topology::build_vert_to_poly_map(
src_polys, src_corner_verts, src_positions.size());
Array<int> vert_to_poly_offset_data;
Array<int> vert_to_poly_indices;
const GroupedSpan<int> 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<int> vert_to_poly_offsets(vert_to_poly_offset_data);
Array<Array<int>> vertex_shared_edges(src_mesh.totvert);
Array<Array<int>> 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<int> loop_indices = vert_to_poly_map[i];
MutableSpan<int> loop_indices = vert_to_poly_indices.as_mutable_span().slice(
vert_to_poly_offsets[i]);
Array<int> sorted_corners(loop_indices.size());
bool vertex_ok = true;
if (vertex_types[i] == VertexType::Normal) {

View File

@ -54,8 +54,10 @@ class FaceSetFromBoundariesInput final : public bke::MeshFieldInput {
const OffsetIndices polys = mesh.polys();
const Array<Vector<int, 2>> edge_to_face_map = bke::mesh_topology::build_edge_to_poly_map(
polys, mesh.corner_edges(), mesh.totedge);
Array<int> edge_to_face_offsets;
Array<int> edge_to_face_indices;
const GroupedSpan<int> 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) {

View File

@ -441,8 +441,10 @@ static void extrude_mesh_edges(Mesh &mesh,
return;
}
const Array<Vector<int, 2>> edge_to_poly_map = bke::mesh_topology::build_edge_to_poly_map(
orig_polys, mesh.corner_edges(), mesh.totedge);
Array<int> edge_to_poly_offsets;
Array<int> edge_to_poly_indices;
const GroupedSpan<int> 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<Vector<int, 2>> edge_to_poly_map = bke::mesh_topology::build_edge_to_poly_map(
orig_polys, mesh.corner_edges(), orig_edges.size());
Array<int> edge_to_poly_offsets;
Array<int> edge_to_poly_indices;
const GroupedSpan<int> 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. */

View File

@ -54,9 +54,10 @@ class CornersOfVertInput final : public bke::MeshFieldInput {
const IndexMask mask) const final
{
const IndexRange vert_range(mesh.totvert);
const Span<int> corner_verts = mesh.corner_verts();
Array<Vector<int>> vert_to_loop_map = bke::mesh_topology::build_vert_to_loop_map(corner_verts,
mesh.totvert);
Array<int> map_offsets;
Array<int> map_indices;
const GroupedSpan<int> 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<int> indices_in_sort = evaluator.get_evaluated<int>(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<float> all_sort_weights = corner_evaluator.get_evaluated<float>(0);

View File

@ -76,7 +76,7 @@ class CornerPreviousEdgeFieldInput final : public bke::MeshFieldInput {
}
const OffsetIndices polys = mesh.polys();
const Span<int> corner_edges = mesh.corner_edges();
Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys);
Array<int> loop_to_poly_map = bke::mesh::build_loop_to_poly_map(polys);
return VArray<int>::ForFunc(
mesh.totloop,
[polys, corner_edges, loop_to_poly_map = std::move(loop_to_poly_map)](const int corner_i) {

View File

@ -55,8 +55,10 @@ class EdgesOfVertInput final : public bke::MeshFieldInput {
{
const IndexRange vert_range(mesh.totvert);
const Span<int2> edges = mesh.edges();
const Array<Vector<int>> vert_to_edge_map = bke::mesh_topology::build_vert_to_edge_map(
edges, mesh.totvert);
Array<int> map_offsets;
Array<int> map_indices;
const GroupedSpan<int> 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};

View File

@ -34,7 +34,7 @@ class CornerFaceIndexInput final : public bke::MeshFieldInput {
if (domain != ATTR_DOMAIN_CORNER) {
return {};
}
return VArray<int>::ForContainer(bke::mesh_topology::build_loop_to_poly_map(mesh.polys()));
return VArray<int>::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<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys);
Array<int> loop_to_poly_map = bke::mesh::build_loop_to_poly_map(polys);
return VArray<int>::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];

View File

@ -50,7 +50,7 @@ class OffsetCornerInFaceFieldInput final : public bke::MeshFieldInput {
const VArray<int> corner_indices = evaluator.get_evaluated<int>(0);
const VArray<int> offsets = evaluator.get_evaluated<int>(1);
Array<int> loop_to_poly_map = bke::mesh_topology::build_loop_to_poly_map(polys);
Array<int> loop_to_poly_map = bke::mesh::build_loop_to_poly_map(polys);
Array<int> offset_corners(mask.min_array_size());
threading::parallel_for(mask.index_range(), 2048, [&](const IndexRange range) {

View File

@ -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);