Changeset View
Changeset View
Standalone View
Standalone View
source/blender/blenkernel/intern/mesh_calc_edges.cc
| Show First 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | static void add_existing_edges_to_hash_maps(Mesh *mesh, | ||||
| }); | }); | ||||
| } | } | ||||
| static void add_polygon_edges_to_hash_maps(Mesh *mesh, | static void add_polygon_edges_to_hash_maps(Mesh *mesh, | ||||
| MutableSpan<EdgeMap> edge_maps, | MutableSpan<EdgeMap> edge_maps, | ||||
| uint32_t parallel_mask) | uint32_t parallel_mask) | ||||
| { | { | ||||
| const Span<MPoly> polys = mesh->polys(); | const Span<MPoly> polys = mesh->polys(); | ||||
| const Span<MLoop> loops = mesh->loops(); | const Span<int> corner_verts = mesh->corner_verts(); | ||||
| threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) { | threading::parallel_for_each(edge_maps, [&](EdgeMap &edge_map) { | ||||
| const int task_index = &edge_map - edge_maps.data(); | const int task_index = &edge_map - edge_maps.data(); | ||||
| for (const MPoly &poly : polys) { | for (const MPoly &poly : polys) { | ||||
| Span<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop); | const IndexRange corners(poly.loopstart, poly.totloop); | ||||
| const MLoop *prev_loop = &poly_loops.last(); | int corner_prev = corners.last(); | ||||
| for (const MLoop &next_loop : poly_loops) { | for (const int next_corner : corners) { | ||||
| /* Can only be the same when the mesh data is invalid. */ | /* Can only be the same when the mesh data is invalid. */ | ||||
| if (prev_loop->v != next_loop.v) { | const int vert = corner_verts[next_corner]; | ||||
| OrderedEdge ordered_edge{prev_loop->v, next_loop.v}; | const int vert_prev = corner_verts[corner_prev]; | ||||
| if (vert_prev != vert) { | |||||
| OrderedEdge ordered_edge{vert_prev, vert}; | |||||
| /* Only add the edge when it belongs into this map. */ | /* Only add the edge when it belongs into this map. */ | ||||
| if (task_index == (parallel_mask & ordered_edge.hash2())) { | if (task_index == (parallel_mask & ordered_edge.hash2())) { | ||||
| edge_map.lookup_or_add(ordered_edge, {nullptr}); | edge_map.lookup_or_add(ordered_edge, {nullptr}); | ||||
| } | } | ||||
| } | } | ||||
| prev_loop = &next_loop; | corner_prev = next_corner; | ||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edge_maps, | static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edge_maps, | ||||
| MutableSpan<MEdge> new_edges) | MutableSpan<MEdge> new_edges) | ||||
| { | { | ||||
| Show All 29 Lines | static void serialize_and_initialize_deduplicated_edges(MutableSpan<EdgeMap> edge_maps, | ||||
| }); | }); | ||||
| } | } | ||||
| static void update_edge_indices_in_poly_loops(Mesh *mesh, | static void update_edge_indices_in_poly_loops(Mesh *mesh, | ||||
| Span<EdgeMap> edge_maps, | Span<EdgeMap> edge_maps, | ||||
| uint32_t parallel_mask) | uint32_t parallel_mask) | ||||
| { | { | ||||
| const Span<MPoly> polys = mesh->polys(); | const Span<MPoly> polys = mesh->polys(); | ||||
| MutableSpan<MLoop> loops = mesh->loops_for_write(); | const Span<int> corner_verts = mesh->corner_verts(); | ||||
| MutableSpan<int> corner_edges = mesh->corner_edges_for_write(); | |||||
| threading::parallel_for(IndexRange(mesh->totpoly), 100, [&](IndexRange range) { | threading::parallel_for(IndexRange(mesh->totpoly), 100, [&](IndexRange range) { | ||||
| for (const int poly_index : range) { | for (const int poly_index : range) { | ||||
| const MPoly &poly = polys[poly_index]; | const MPoly &poly = polys[poly_index]; | ||||
| MutableSpan<MLoop> poly_loops = loops.slice(poly.loopstart, poly.totloop); | const IndexRange corners(poly.loopstart, poly.totloop); | ||||
| int prev_corner = corners.last(); | |||||
| for (const int next_corner : corners) { | |||||
| const int vert = corner_verts[next_corner]; | |||||
| const int vert_prev = corner_verts[prev_corner]; | |||||
| MLoop *prev_loop = &poly_loops.last(); | |||||
| for (MLoop &next_loop : poly_loops) { | |||||
| int edge_index; | int edge_index; | ||||
| if (prev_loop->v != next_loop.v) { | if (vert_prev != vert) { | ||||
| OrderedEdge ordered_edge{prev_loop->v, next_loop.v}; | OrderedEdge ordered_edge{vert_prev, vert}; | ||||
| /* Double lookup: First find the map that contains the edge, then lookup the edge. */ | /* Double lookup: First find the map that contains the edge, then lookup the edge. */ | ||||
| const EdgeMap &edge_map = edge_maps[parallel_mask & ordered_edge.hash2()]; | const EdgeMap &edge_map = edge_maps[parallel_mask & ordered_edge.hash2()]; | ||||
| edge_index = edge_map.lookup(ordered_edge).index; | edge_index = edge_map.lookup(ordered_edge).index; | ||||
| } | } | ||||
| else { | else { | ||||
| /* This is an invalid edge; normally this does not happen in Blender, | /* This is an invalid edge; normally this does not happen in Blender, | ||||
| * but it can be part of an imported mesh with invalid geometry. See | * but it can be part of an imported mesh with invalid geometry. See | ||||
| * T76514. */ | * T76514. */ | ||||
| edge_index = 0; | edge_index = 0; | ||||
| } | } | ||||
| prev_loop->e = edge_index; | corner_edges[prev_corner] = edge_index; | ||||
| prev_loop = &next_loop; | prev_corner = next_corner; | ||||
| } | } | ||||
| } | } | ||||
| }); | }); | ||||
| } | } | ||||
| static int get_parallel_maps_count(const Mesh *mesh) | static int get_parallel_maps_count(const Mesh *mesh) | ||||
| { | { | ||||
| /* Don't use parallelization when the mesh is small. */ | /* Don't use parallelization when the mesh is small. */ | ||||
| Show All 35 Lines | void BKE_mesh_calc_edges(Mesh *mesh, bool keep_existing_edges, const bool select_new_edges) | ||||
| /* Compute total number of edges. */ | /* Compute total number of edges. */ | ||||
| int new_totedge = 0; | int new_totedge = 0; | ||||
| for (EdgeMap &edge_map : edge_maps) { | for (EdgeMap &edge_map : edge_maps) { | ||||
| new_totedge += edge_map.size(); | new_totedge += edge_map.size(); | ||||
| } | } | ||||
| /* Create new edges. */ | /* Create new edges. */ | ||||
| if (!CustomData_get_layer_named(&mesh->ldata, CD_PROP_INT32, ".corner_edge")) { | |||||
| CustomData_add_layer_named( | |||||
| &mesh->ldata, CD_PROP_INT32, CD_CONSTRUCT, nullptr, mesh->totloop, ".corner_edge"); | |||||
| } | |||||
| MutableSpan<MEdge> new_edges{ | MutableSpan<MEdge> new_edges{ | ||||
| static_cast<MEdge *>(MEM_calloc_arrayN(new_totedge, sizeof(MEdge), __func__)), new_totedge}; | static_cast<MEdge *>(MEM_calloc_arrayN(new_totedge, sizeof(MEdge), __func__)), new_totedge}; | ||||
| calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges); | calc_edges::serialize_and_initialize_deduplicated_edges(edge_maps, new_edges); | ||||
| calc_edges::update_edge_indices_in_poly_loops(mesh, edge_maps, parallel_mask); | calc_edges::update_edge_indices_in_poly_loops(mesh, edge_maps, parallel_mask); | ||||
| /* Free old CustomData and assign new one. */ | /* Free old CustomData and assign new one. */ | ||||
| CustomData_free(&mesh->edata, mesh->totedge); | CustomData_free(&mesh->edata, mesh->totedge); | ||||
| CustomData_reset(&mesh->edata); | CustomData_reset(&mesh->edata); | ||||
| Show All 29 Lines | |||||