Mesh: Replace EdgeHash and EdgeSet with C++ classes
The `EdgeHash` and `EdgeSet` data structures are designed specifically
as a hash of an order agnostic pair of integers. This specialization can
be achieved much more easily with the templated C++ data structures,
which gives improved performance, readability, and type safety.
This PR removes the older data structures and replaces their use with
`Map`, `Set`, or `VectorSet` depending on the situation. The changes
are mostly straightforward, but there are a few places where the old
API made the goals of the code confusing.
The last time these removed data structures were significantly changed,
they were already moving closer to the implementation of the newer
C++ data structures (aa63a87d37).
Pull Request: https://projects.blender.org/blender/blender/pulls/111391
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
*/
|
||||
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_set.hh"
|
||||
|
||||
#include <float.h>
|
||||
|
||||
@@ -17,8 +19,6 @@ struct ClothModifierData;
|
||||
struct CollisionModifierData;
|
||||
struct Implicit_Data;
|
||||
struct Depsgraph;
|
||||
struct EdgeSet;
|
||||
struct GHash;
|
||||
struct LinkNode;
|
||||
struct Mesh;
|
||||
struct MVertTri;
|
||||
@@ -78,13 +78,13 @@ struct Cloth {
|
||||
BVHTree *bvhtree; /* collision tree for this cloth object */
|
||||
BVHTree *bvhselftree; /* collision tree for this cloth object (may be same as bvhtree) */
|
||||
MVertTri *tri;
|
||||
Implicit_Data *implicit; /* our implicit solver connects to this pointer */
|
||||
EdgeSet *edgeset; /* used for selfcollisions */
|
||||
Implicit_Data *implicit; /* our implicit solver connects to this pointer */
|
||||
blender::Set<blender::OrderedEdge> edgeset; /* used for selfcollisions */
|
||||
int last_frame;
|
||||
float initial_mesh_volume; /* Initial volume of the mesh. Used for pressure */
|
||||
float average_acceleration[3]; /* Moving average of overall acceleration. */
|
||||
const blender::int2 *edges; /* Used for hair collisions. */
|
||||
EdgeSet *sew_edge_graph; /* Sewing edges represented using a GHash */
|
||||
blender::Set<blender::OrderedEdge> sew_edge_graph; /* Sewing edges. */
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_offset_indices.hh"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_brush_enums.h"
|
||||
@@ -31,7 +33,6 @@ struct BlendWriter;
|
||||
struct Brush;
|
||||
struct CurveMapping;
|
||||
struct Depsgraph;
|
||||
struct EdgeSet;
|
||||
struct EnumPropertyItem;
|
||||
struct ExpandCache;
|
||||
struct FilterCache;
|
||||
@@ -353,7 +354,7 @@ struct SculptClothLengthConstraint {
|
||||
struct SculptClothSimulation {
|
||||
SculptClothLengthConstraint *length_constraints;
|
||||
int tot_length_constraints;
|
||||
EdgeSet *created_length_constraints;
|
||||
blender::Set<blender::OrderedEdge> created_length_constraints;
|
||||
int capacity_length_constraints;
|
||||
float *length_constraint_tweak;
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
#include "BLI_buffer.h"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "DNA_particle_types.h"
|
||||
@@ -31,7 +33,6 @@ struct BlendLibReader;
|
||||
struct BlendWriter;
|
||||
struct CustomData_MeshMasks;
|
||||
struct Depsgraph;
|
||||
struct EdgeHash;
|
||||
struct KDTree_3d;
|
||||
struct LinkNode;
|
||||
struct MCol;
|
||||
@@ -84,7 +85,7 @@ typedef struct SPHData {
|
||||
ParticleSystem *psys[10];
|
||||
ParticleData *pa;
|
||||
float mass;
|
||||
struct EdgeHash *eh;
|
||||
blender::Map<blender::OrderedEdge, int> eh;
|
||||
float *gravity;
|
||||
float hfac;
|
||||
/* Average distance to neighbors (other particles in the support domain),
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
#include "BKE_DerivedMesh.h"
|
||||
|
||||
/* Thread sync primitives used directly. */
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
struct CCGEdge;
|
||||
struct CCGElem;
|
||||
@@ -21,7 +23,6 @@ struct CCGSubSurf;
|
||||
struct CCGVert;
|
||||
struct DMFlagMat;
|
||||
struct DerivedMesh;
|
||||
struct EdgeHash;
|
||||
struct Mesh;
|
||||
struct MeshElemMap;
|
||||
struct MultiresModifierData;
|
||||
@@ -122,7 +123,7 @@ struct CCGDerivedMesh {
|
||||
MultiresModifiedFlags modified_flags;
|
||||
} multires;
|
||||
|
||||
EdgeHash *ehash;
|
||||
blender::VectorSet<blender::OrderedEdge> *ehash;
|
||||
|
||||
ThreadMutex loops_cache_lock;
|
||||
ThreadRWMutex origindex_cache_rwlock;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
@@ -482,21 +481,12 @@ void cloth_free_modifier(ClothModifierData *clmd)
|
||||
MEM_freeN(cloth->tri);
|
||||
}
|
||||
|
||||
if (cloth->edgeset) {
|
||||
BLI_edgeset_free(cloth->edgeset);
|
||||
}
|
||||
|
||||
if (cloth->sew_edge_graph) {
|
||||
BLI_edgeset_free(cloth->sew_edge_graph);
|
||||
cloth->sew_edge_graph = nullptr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (clmd->clothObject->facemarks) {
|
||||
MEM_freeN(clmd->clothObject->facemarks);
|
||||
}
|
||||
#endif
|
||||
MEM_freeN(cloth);
|
||||
MEM_delete(cloth);
|
||||
clmd->clothObject = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -559,21 +549,12 @@ void cloth_free_modifier_extern(ClothModifierData *clmd)
|
||||
MEM_freeN(cloth->tri);
|
||||
}
|
||||
|
||||
if (cloth->edgeset) {
|
||||
BLI_edgeset_free(cloth->edgeset);
|
||||
}
|
||||
|
||||
if (cloth->sew_edge_graph) {
|
||||
BLI_edgeset_free(cloth->sew_edge_graph);
|
||||
cloth->sew_edge_graph = nullptr;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (clmd->clothObject->facemarks) {
|
||||
MEM_freeN(clmd->clothObject->facemarks);
|
||||
}
|
||||
#endif
|
||||
MEM_freeN(cloth);
|
||||
MEM_delete(cloth);
|
||||
clmd->clothObject = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -742,10 +723,9 @@ static bool cloth_from_object(
|
||||
}
|
||||
|
||||
/* Allocate a new cloth object. */
|
||||
clmd->clothObject = MEM_cnew<Cloth>(__func__);
|
||||
clmd->clothObject = MEM_new<Cloth>(__func__);
|
||||
if (clmd->clothObject) {
|
||||
clmd->clothObject->old_solver_type = 255;
|
||||
clmd->clothObject->edgeset = nullptr;
|
||||
}
|
||||
else {
|
||||
BKE_modifier_set_error(ob, &(clmd->modifier), "Out of memory on allocating clmd->clothObject");
|
||||
@@ -763,8 +743,6 @@ static bool cloth_from_object(
|
||||
clmd->clothObject->springs = nullptr;
|
||||
clmd->clothObject->numsprings = -1;
|
||||
|
||||
clmd->clothObject->sew_edge_graph = nullptr;
|
||||
|
||||
if (clmd->sim_parms->shapekey_rest &&
|
||||
!(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_DYNAMIC_BASEMESH))
|
||||
{
|
||||
@@ -944,10 +922,7 @@ static void cloth_free_errorsprings(Cloth *cloth,
|
||||
|
||||
MEM_SAFE_FREE(spring_ref);
|
||||
|
||||
if (cloth->edgeset) {
|
||||
BLI_edgeset_free(cloth->edgeset);
|
||||
cloth->edgeset = nullptr;
|
||||
}
|
||||
cloth->edgeset.clear_and_shrink();
|
||||
}
|
||||
|
||||
BLI_INLINE void cloth_bend_poly_dir(
|
||||
@@ -1407,7 +1382,7 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
|
||||
float max_length,
|
||||
float max_diversion,
|
||||
bool check_normal,
|
||||
uint *r_tar_v_idx)
|
||||
int *r_tar_v_idx)
|
||||
{
|
||||
float co[3], no[3], new_co[3];
|
||||
float radius;
|
||||
@@ -1444,7 +1419,7 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
|
||||
BLI_bvhtree_ray_cast(
|
||||
treedata->tree, new_co, no, radius, &rayhit, treedata->raycast_callback, treedata);
|
||||
|
||||
uint vert_idx = -1;
|
||||
int vert_idx = -1;
|
||||
const int *corner_verts = treedata->corner_verts;
|
||||
const MLoopTri *lt = nullptr;
|
||||
|
||||
@@ -1458,7 +1433,7 @@ static bool find_internal_spring_target_vertex(BVHTreeFromMesh *treedata,
|
||||
lt = &treedata->looptri[rayhit.index];
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
uint tmp_vert_idx = corner_verts[lt->tri[i]];
|
||||
int tmp_vert_idx = corner_verts[lt->tri[i]];
|
||||
if (tmp_vert_idx == v_idx) {
|
||||
/* We managed to hit ourselves. */
|
||||
return false;
|
||||
@@ -1495,7 +1470,6 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
const Span<int> corner_edges = mesh->corner_edges();
|
||||
int index2 = 0; /* our second vertex index */
|
||||
LinkNodePair *edgelist = nullptr;
|
||||
EdgeSet *edgeset = nullptr;
|
||||
LinkNode *search = nullptr, *search2 = nullptr;
|
||||
BendSpringRef *spring_ref = nullptr;
|
||||
|
||||
@@ -1507,10 +1481,9 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
/* NOTE: handling ownership of springs and edgeset is quite sloppy
|
||||
* currently they are never initialized but assert just to be sure */
|
||||
BLI_assert(cloth->springs == nullptr);
|
||||
BLI_assert(cloth->edgeset == nullptr);
|
||||
BLI_assert(cloth->edgeset.is_empty());
|
||||
|
||||
cloth->springs = nullptr;
|
||||
cloth->edgeset = nullptr;
|
||||
|
||||
if (clmd->sim_parms->bending_model == CLOTH_BENDING_ANGULAR) {
|
||||
spring_ref = static_cast<BendSpringRef *>(
|
||||
@@ -1532,7 +1505,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
|
||||
if (use_internal_springs && numface > 0) {
|
||||
BVHTreeFromMesh treedata = {nullptr};
|
||||
uint tar_v_idx;
|
||||
int tar_v_idx;
|
||||
Mesh *tmp_mesh = nullptr;
|
||||
RNG *rng;
|
||||
|
||||
@@ -1543,7 +1516,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
tmp_mesh = cloth_make_rest_mesh(clmd, mesh);
|
||||
}
|
||||
|
||||
EdgeSet *existing_vert_pairs = BLI_edgeset_new("cloth_sewing_edges_graph");
|
||||
Set<OrderedEdge> existing_vert_pairs;
|
||||
BKE_bvhtree_from_mesh_get(&treedata, tmp_mesh ? tmp_mesh : mesh, BVHTREE_FROM_LOOPTRI, 2);
|
||||
rng = BLI_rng_new_srandom(0);
|
||||
|
||||
@@ -1561,12 +1534,12 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
(clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_INTERNAL_SPRINGS_NORMAL),
|
||||
&tar_v_idx))
|
||||
{
|
||||
if (BLI_edgeset_haskey(existing_vert_pairs, i, tar_v_idx)) {
|
||||
if (existing_vert_pairs.contains({i, tar_v_idx})) {
|
||||
/* We have already created a spring between these verts! */
|
||||
continue;
|
||||
}
|
||||
|
||||
BLI_edgeset_insert(existing_vert_pairs, i, tar_v_idx);
|
||||
existing_vert_pairs.add({i, tar_v_idx});
|
||||
|
||||
spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
|
||||
|
||||
@@ -1592,7 +1565,6 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
}
|
||||
else {
|
||||
cloth_free_errorsprings(cloth, edgelist, spring_ref);
|
||||
BLI_edgeset_free(existing_vert_pairs);
|
||||
free_bvhtree_from_mesh(&treedata);
|
||||
if (tmp_mesh) {
|
||||
BKE_id_free(nullptr, &tmp_mesh->id);
|
||||
@@ -1601,7 +1573,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
}
|
||||
}
|
||||
}
|
||||
BLI_edgeset_free(existing_vert_pairs);
|
||||
existing_vert_pairs.clear_and_shrink();
|
||||
free_bvhtree_from_mesh(&treedata);
|
||||
if (tmp_mesh) {
|
||||
BKE_id_free(nullptr, &tmp_mesh->id);
|
||||
@@ -1616,8 +1588,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
|
||||
if (clmd->sim_parms->flags & CLOTH_SIMSETTINGS_FLAG_SEW) {
|
||||
/* cloth->sew_edge_graph should not exist before this */
|
||||
BLI_assert(cloth->sew_edge_graph == nullptr);
|
||||
cloth->sew_edge_graph = BLI_edgeset_new("cloth_sewing_edges_graph");
|
||||
BLI_assert(cloth->sew_edge_graph.is_empty());
|
||||
}
|
||||
|
||||
/* Structural springs. */
|
||||
@@ -1635,7 +1606,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
spring->lin_stiffness = 1.0f;
|
||||
spring->type = CLOTH_SPRING_TYPE_SEWING;
|
||||
|
||||
BLI_edgeset_insert(cloth->sew_edge_graph, edges[i][0], edges[i][1]);
|
||||
cloth->sew_edge_graph.add({edges[i][0], edges[i][1]});
|
||||
}
|
||||
else {
|
||||
shrink_factor = cloth_shrink_factor(clmd, cloth->verts, spring->ij, spring->kl);
|
||||
@@ -1681,8 +1652,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
}
|
||||
}
|
||||
|
||||
edgeset = BLI_edgeset_new_ex(__func__, numedges);
|
||||
cloth->edgeset = edgeset;
|
||||
cloth->edgeset.reserve(numedges);
|
||||
|
||||
if (numface) {
|
||||
for (int i = 0; i < numface; i++) {
|
||||
@@ -1799,7 +1769,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
|
||||
/* Check for existing spring. */
|
||||
/* Check also if start-point is equal to endpoint. */
|
||||
if ((index2 != tspring2->ij) && !BLI_edgeset_haskey(edgeset, tspring2->ij, index2)) {
|
||||
if ((index2 != tspring2->ij) && !cloth->edgeset.contains({tspring2->ij, index2})) {
|
||||
spring = (ClothSpring *)MEM_callocN(sizeof(ClothSpring), "cloth spring");
|
||||
|
||||
if (!spring) {
|
||||
@@ -1816,7 +1786,7 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
spring->lin_stiffness = (cloth->verts[spring->kl].bend_stiff +
|
||||
cloth->verts[spring->ij].bend_stiff) /
|
||||
2.0f;
|
||||
BLI_edgeset_insert(edgeset, spring->ij, spring->kl);
|
||||
cloth->edgeset.add({spring->ij, spring->kl});
|
||||
bend_springs++;
|
||||
|
||||
BLI_linklist_prepend(&cloth->springs, spring);
|
||||
@@ -1911,15 +1881,13 @@ static bool cloth_build_springs(ClothModifierData *clmd, Mesh *mesh)
|
||||
/* Insert other near springs in `edgeset` AFTER bending springs are calculated
|
||||
* (for self-collision). */
|
||||
for (int i = 0; i < numedges; i++) { /* struct springs */
|
||||
BLI_edgeset_add(edgeset, edges[i][0], edges[i][1]);
|
||||
cloth->edgeset.add({edges[i][0], edges[i][1]});
|
||||
}
|
||||
|
||||
for (int i = 0; i < numface; i++) { /* edge springs */
|
||||
if (faces[i].size() == 4) {
|
||||
BLI_edgeset_add(
|
||||
edgeset, corner_verts[faces[i].start() + 0], corner_verts[faces[i].start() + 2]);
|
||||
BLI_edgeset_add(
|
||||
edgeset, corner_verts[faces[i].start() + 1], corner_verts[faces[i].start() + 3]);
|
||||
cloth->edgeset.add({corner_verts[faces[i].start() + 0], corner_verts[faces[i].start() + 2]});
|
||||
cloth->edgeset.add({corner_verts[faces[i].start() + 1], corner_verts[faces[i].start() + 3]});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_vector.h"
|
||||
@@ -1079,7 +1078,7 @@ static bool cloth_bvh_selfcollision_is_active(const ClothModifierData *clmd,
|
||||
}
|
||||
|
||||
if (sewing_active) {
|
||||
if (BLI_edgeset_haskey(cloth->sew_edge_graph, tri_a->tri[i], tri_b->tri[j])) {
|
||||
if (cloth->sew_edge_graph.contains({tri_a->tri[i], tri_b->tri[j]})) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_bounds.hh"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_endian_switch.h"
|
||||
#include "BLI_ghash.h"
|
||||
#include "BLI_hash.h"
|
||||
@@ -30,7 +29,9 @@
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_resource_scope.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_span.hh"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_task.hh"
|
||||
@@ -468,6 +469,7 @@ static bool is_uv_bool_sublayer(const CustomDataLayer &layer)
|
||||
static int customdata_compare(
|
||||
CustomData *c1, CustomData *c2, const int total_length, Mesh *m1, const float thresh)
|
||||
{
|
||||
using namespace blender;
|
||||
CustomDataLayer *l1, *l2;
|
||||
int layer_count1 = 0, layer_count2 = 0, j;
|
||||
const uint64_t cd_mask_non_generic = CD_MASK_MDEFORMVERT;
|
||||
@@ -535,18 +537,17 @@ static int customdata_compare(
|
||||
|
||||
if (StringRef(l1->name) == ".edge_verts") {
|
||||
int etot = m1->totedge;
|
||||
EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot);
|
||||
|
||||
for (j = 0; j < etot; j++, e1++) {
|
||||
BLI_edgehash_insert(eh, (*e1)[0], (*e1)[1], e1);
|
||||
Set<OrderedEdge> ordered_edges;
|
||||
ordered_edges.reserve(etot);
|
||||
for (const int2 value : Span(e1, etot)) {
|
||||
ordered_edges.add(value);
|
||||
}
|
||||
|
||||
for (j = 0; j < etot; j++, e2++) {
|
||||
if (!BLI_edgehash_lookup(eh, (*e2)[0], (*e2)[1])) {
|
||||
for (j = 0; j < etot; j++) {
|
||||
if (!ordered_edges.contains(e2[j])) {
|
||||
return MESHCMP_EDGEUNKNOWN;
|
||||
}
|
||||
}
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
else {
|
||||
for (j = 0; j < total_length; j++) {
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
#include "DNA_pointcloud_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
#include "BLI_alloca.h"
|
||||
#include "BLI_array_utils.hh"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_span.hh"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
@@ -97,7 +97,6 @@ static void mesh_calc_edges_mdata(const MVert * /*allvert*/,
|
||||
const MPoly *mpoly;
|
||||
const MFace *mface;
|
||||
MEdge *edges, *edge;
|
||||
EdgeHash *hash;
|
||||
EdgeSort *edsort, *ed;
|
||||
int a, totedge = 0;
|
||||
uint totedge_final = 0;
|
||||
@@ -177,9 +176,10 @@ static void mesh_calc_edges_mdata(const MVert * /*allvert*/,
|
||||
MEM_freeN(edsort);
|
||||
|
||||
/* set edge members of mloops */
|
||||
hash = BLI_edgehash_new_ex(__func__, totedge_final);
|
||||
blender::Map<blender::OrderedEdge, int> hash;
|
||||
hash.reserve(totedge_final);
|
||||
for (edge_index = 0, edge = edges; edge_index < totedge_final; edge_index++, edge++) {
|
||||
BLI_edgehash_insert(hash, edge->v1, edge->v2, POINTER_FROM_UINT(edge_index));
|
||||
hash.add({edge->v1, edge->v2}, edge_index);
|
||||
}
|
||||
|
||||
mpoly = allpoly;
|
||||
@@ -191,14 +191,12 @@ static void mesh_calc_edges_mdata(const MVert * /*allvert*/,
|
||||
ml = &ml_next[i - 1]; /* last loop */
|
||||
|
||||
while (i-- != 0) {
|
||||
ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(hash, ml->v, ml_next->v));
|
||||
ml->e = hash.lookup({ml->v, ml_next->v});
|
||||
ml = ml_next;
|
||||
ml_next++;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_edgehash_free(hash, nullptr);
|
||||
|
||||
*r_medge = edges;
|
||||
*r_totedge = totedge_final;
|
||||
}
|
||||
@@ -464,7 +462,6 @@ static void convert_mfaces_to_mpolys(ID *id,
|
||||
MFace *mf;
|
||||
MLoop *ml, *mloop;
|
||||
MPoly *poly, *mpoly;
|
||||
EdgeHash *eh;
|
||||
int numTex, numCol;
|
||||
int i, j, totloop, faces_num, *polyindex;
|
||||
|
||||
@@ -506,11 +503,12 @@ static void convert_mfaces_to_mpolys(ID *id,
|
||||
CustomData_external_read(fdata_legacy, id, CD_MASK_MDISPS, totface_i);
|
||||
}
|
||||
|
||||
eh = BLI_edgehash_new_ex(__func__, uint(totedge_i));
|
||||
blender::Map<blender::OrderedEdge, int> eh;
|
||||
eh.reserve(totedge_i);
|
||||
|
||||
/* build edge hash */
|
||||
for (i = 0; i < totedge_i; i++) {
|
||||
BLI_edgehash_insert(eh, edges[i][0], edges[i][1], POINTER_FROM_UINT(i));
|
||||
eh.add(edges[i], i);
|
||||
}
|
||||
|
||||
polyindex = (int *)CustomData_get_layer(fdata_legacy, CD_ORIGINDEX);
|
||||
@@ -530,7 +528,7 @@ static void convert_mfaces_to_mpolys(ID *id,
|
||||
#define ML(v1, v2) \
|
||||
{ \
|
||||
ml->v = mf->v1; \
|
||||
ml->e = POINTER_AS_UINT(BLI_edgehash_lookup(eh, mf->v1, mf->v2)); \
|
||||
ml->e = eh.lookup({mf->v1, mf->v2}); \
|
||||
ml++; \
|
||||
j++; \
|
||||
} \
|
||||
@@ -560,8 +558,6 @@ static void convert_mfaces_to_mpolys(ID *id,
|
||||
/* NOTE: we don't convert NGons at all, these are not even real ngons,
|
||||
* they have their own UVs, colors etc - it's more an editing feature. */
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
|
||||
*r_faces_num = faces_num;
|
||||
*r_totloop = totloop;
|
||||
}
|
||||
|
||||
@@ -13,17 +13,18 @@
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "DNA_mesh_types.h"
|
||||
#include "DNA_meshdata_types.h"
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_sys_types.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_sys_types.h"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
#include "BKE_customdata.h"
|
||||
@@ -227,6 +228,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
||||
const bool do_fixes,
|
||||
bool *r_changed)
|
||||
{
|
||||
using namespace blender;
|
||||
#define REMOVE_EDGE_TAG(_me) \
|
||||
{ \
|
||||
_me[0] = _me[1]; \
|
||||
@@ -286,7 +288,8 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
||||
int as_flag;
|
||||
} recalc_flag;
|
||||
|
||||
EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, totedge);
|
||||
Map<OrderedEdge, int> edge_hash;
|
||||
edge_hash.reserve(totedge);
|
||||
|
||||
BLI_assert(!(do_fixes && mesh == nullptr));
|
||||
|
||||
@@ -332,16 +335,14 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
||||
remove = do_fixes;
|
||||
}
|
||||
|
||||
if ((edge[0] != edge[1]) && BLI_edgehash_haskey(edge_hash, edge[0], edge[1])) {
|
||||
PRINT_ERR("\tEdge %u: is a duplicate of %d",
|
||||
i,
|
||||
POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, edge[0], edge[1])));
|
||||
if ((edge[0] != edge[1]) && edge_hash.contains(edge)) {
|
||||
PRINT_ERR("\tEdge %u: is a duplicate of %d", i, edge_hash.lookup(edge));
|
||||
remove = do_fixes;
|
||||
}
|
||||
|
||||
if (remove == false) {
|
||||
if (edge[0] != edge[1]) {
|
||||
BLI_edgehash_insert(edge_hash, edge[0], edge[1], POINTER_FROM_INT(i));
|
||||
edge_hash.add(edge, i);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -363,7 +364,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
||||
} \
|
||||
(void)0
|
||||
#define CHECK_FACE_EDGE(a, b) \
|
||||
if (!BLI_edgehash_haskey(edge_hash, mf->a, mf->b)) { \
|
||||
if (!edge_hash.contains({mf->a, mf->b})) { \
|
||||
PRINT_ERR(" face %u: edge " STRINGIFY(a) "/" STRINGIFY(b) " (%u,%u) is missing edge data", \
|
||||
i, \
|
||||
mf->a, \
|
||||
@@ -613,7 +614,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
||||
const int edge_i = corner_edges[corner];
|
||||
v1 = vert;
|
||||
v2 = corner_verts[sp->loopstart + (j + 1) % poly_size];
|
||||
if (!BLI_edgehash_haskey(edge_hash, v1, v2)) {
|
||||
if (!edge_hash.contains({v1, v2})) {
|
||||
/* Edge not existing. */
|
||||
PRINT_ERR("\tPoly %u needs missing edge (%d, %d)", sp->index, v1, v2);
|
||||
if (do_fixes) {
|
||||
@@ -628,7 +629,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
||||
* We already know from previous text that a valid edge exists, use it (if allowed)! */
|
||||
if (do_fixes) {
|
||||
int prev_e = edge_i;
|
||||
corner_edges[corner] = POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, v1, v2));
|
||||
corner_edges[corner] = edge_hash.lookup({v1, v2});
|
||||
fix_flag.loops_edge = true;
|
||||
PRINT_ERR("\tLoop %d has invalid edge reference (%d), fixed using edge %d",
|
||||
corner,
|
||||
@@ -650,7 +651,7 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
||||
* use it (if allowed)! */
|
||||
if (do_fixes) {
|
||||
int prev_e = edge_i;
|
||||
corner_edges[corner] = POINTER_AS_INT(BLI_edgehash_lookup(edge_hash, v1, v2));
|
||||
corner_edges[corner] = edge_hash.lookup({v1, v2});
|
||||
fix_flag.loops_edge = true;
|
||||
PRINT_ERR(
|
||||
"\tPoly %u has invalid edge reference (%d, is_removed: %d), fixed using edge "
|
||||
@@ -788,8 +789,6 @@ bool BKE_mesh_validate_arrays(Mesh *mesh,
|
||||
MEM_freeN(sort_polys);
|
||||
}
|
||||
|
||||
BLI_edgehash_free(edge_hash, nullptr);
|
||||
|
||||
/* fix deform verts */
|
||||
if (dverts) {
|
||||
MDeformVert *dv;
|
||||
@@ -1326,25 +1325,26 @@ void mesh_strip_edges(Mesh *me)
|
||||
void BKE_mesh_calc_edges_tessface(Mesh *mesh)
|
||||
{
|
||||
const int numFaces = mesh->totface_legacy;
|
||||
EdgeSet *eh = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_FACES(numFaces));
|
||||
blender::VectorSet<blender::OrderedEdge> eh;
|
||||
eh.reserve(numFaces);
|
||||
MFace *mfaces = (MFace *)CustomData_get_layer_for_write(
|
||||
&mesh->fdata_legacy, CD_MFACE, mesh->totface_legacy);
|
||||
|
||||
MFace *mf = mfaces;
|
||||
for (int i = 0; i < numFaces; i++, mf++) {
|
||||
BLI_edgeset_add(eh, mf->v1, mf->v2);
|
||||
BLI_edgeset_add(eh, mf->v2, mf->v3);
|
||||
eh.add({mf->v1, mf->v2});
|
||||
eh.add({mf->v2, mf->v3});
|
||||
|
||||
if (mf->v4) {
|
||||
BLI_edgeset_add(eh, mf->v3, mf->v4);
|
||||
BLI_edgeset_add(eh, mf->v4, mf->v1);
|
||||
eh.add({mf->v3, mf->v4});
|
||||
eh.add({mf->v4, mf->v1});
|
||||
}
|
||||
else {
|
||||
BLI_edgeset_add(eh, mf->v3, mf->v1);
|
||||
eh.add({mf->v3, mf->v1});
|
||||
}
|
||||
}
|
||||
|
||||
const int numEdges = BLI_edgeset_len(eh);
|
||||
const int numEdges = eh.size();
|
||||
|
||||
/* write new edges into a temporary CustomData */
|
||||
CustomData edgeData;
|
||||
@@ -1356,21 +1356,13 @@ void BKE_mesh_calc_edges_tessface(Mesh *mesh)
|
||||
&edgeData, CD_PROP_INT32_2D, ".edge_verts", mesh->totedge);
|
||||
int *index = (int *)CustomData_get_layer_for_write(&edgeData, CD_ORIGINDEX, mesh->totedge);
|
||||
|
||||
EdgeSetIterator *ehi = BLI_edgesetIterator_new(eh);
|
||||
for (int i = 0; BLI_edgesetIterator_isDone(ehi) == false;
|
||||
BLI_edgesetIterator_step(ehi), i++, ege++, index++)
|
||||
{
|
||||
BLI_edgesetIterator_getKey(ehi, &(*ege)[0], &(*ege)[1]);
|
||||
*index = ORIGINDEX_NONE;
|
||||
}
|
||||
BLI_edgesetIterator_free(ehi);
|
||||
memset(index, ORIGINDEX_NONE, sizeof(int) * numEdges);
|
||||
MutableSpan(ege, numEdges).copy_from(eh.as_span().cast<blender::int2>());
|
||||
|
||||
/* free old CustomData and assign new one */
|
||||
CustomData_free(&mesh->edge_data, mesh->totedge);
|
||||
mesh->edge_data = edgeData;
|
||||
mesh->totedge = numEdges;
|
||||
|
||||
BLI_edgeset_free(eh);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -30,7 +30,6 @@
|
||||
#include "DNA_texture_types.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_kdopbvh.h"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_linklist.h"
|
||||
@@ -1666,17 +1665,16 @@ static void sph_springs_modify(ParticleSystem *psys, float dtime)
|
||||
}
|
||||
}
|
||||
}
|
||||
static EdgeHash *sph_springhash_build(ParticleSystem *psys)
|
||||
static blender::Map<blender::OrderedEdge, int> sph_springhash_build(ParticleSystem *psys)
|
||||
{
|
||||
EdgeHash *springhash = nullptr;
|
||||
blender::Map<blender::OrderedEdge, int> springhash;
|
||||
springhash.reserve(psys->tot_fluidsprings);
|
||||
|
||||
ParticleSpring *spring;
|
||||
int i = 0;
|
||||
|
||||
springhash = BLI_edgehash_new_ex(__func__, psys->tot_fluidsprings);
|
||||
|
||||
for (i = 0, spring = psys->fluid_springs; i < psys->tot_fluidsprings; i++, spring++) {
|
||||
BLI_edgehash_insert(
|
||||
springhash, spring->particle_index[0], spring->particle_index[1], POINTER_FROM_INT(i + 1));
|
||||
springhash.add({spring->particle_index[0], spring->particle_index[1]}, i + 1);
|
||||
}
|
||||
|
||||
return springhash;
|
||||
@@ -1808,7 +1806,7 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa
|
||||
SPHRangeData pfr;
|
||||
SPHNeighbor *pfn;
|
||||
float *gravity = sphdata->gravity;
|
||||
EdgeHash *springhash = sphdata->eh;
|
||||
const blender::Map<blender::OrderedEdge, int> &springhash = sphdata->eh;
|
||||
|
||||
float q, u, rij, dv[3];
|
||||
float pressure, near_pressure;
|
||||
@@ -1892,9 +1890,9 @@ static void sph_force_cb(void *sphdata_v, ParticleKey *state, float *force, floa
|
||||
|
||||
if (spring_constant > 0.0f) {
|
||||
/* Viscoelastic spring force */
|
||||
if (pfn->psys == psys[0] && fluid->flag & SPH_VISCOELASTIC_SPRINGS && springhash) {
|
||||
/* BLI_edgehash_lookup appears to be thread-safe. - z0r */
|
||||
spring_index = POINTER_AS_INT(BLI_edgehash_lookup(springhash, index, pfn->index));
|
||||
if (pfn->psys == psys[0] && fluid->flag & SPH_VISCOELASTIC_SPRINGS && !springhash.is_empty())
|
||||
{
|
||||
spring_index = springhash.lookup({index, pfn->index});
|
||||
|
||||
if (spring_index) {
|
||||
spring = psys[0]->fluid_springs + spring_index - 1;
|
||||
@@ -2183,11 +2181,6 @@ static void psys_sph_flush_springs(SPHData *sphdata)
|
||||
void psys_sph_finalize(SPHData *sphdata)
|
||||
{
|
||||
psys_sph_flush_springs(sphdata);
|
||||
|
||||
if (sphdata->eh) {
|
||||
BLI_edgehash_free(sphdata->eh, nullptr);
|
||||
sphdata->eh = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void psys_sph_density(BVHTree *tree, SPHData *sphdata, float co[3], float vars[2])
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.hh"
|
||||
#include "BLI_math_vector.h"
|
||||
@@ -107,7 +110,8 @@ static rctf primitive_uv_bounds(const MLoopTri &looptri, const Span<float2> uv_m
|
||||
static void mesh_data_init_edges(MeshData &mesh_data)
|
||||
{
|
||||
mesh_data.edges.reserve(mesh_data.looptris.size() * 2);
|
||||
EdgeHash *eh = BLI_edgehash_new_ex(__func__, mesh_data.looptris.size() * 3);
|
||||
Map<OrderedEdge, int> eh;
|
||||
eh.reserve(mesh_data.looptris.size() * 3);
|
||||
for (int64_t i = 0; i < mesh_data.looptris.size(); i++) {
|
||||
const MLoopTri &tri = mesh_data.looptris[i];
|
||||
Vector<int, 3> edges;
|
||||
@@ -115,21 +119,19 @@ static void mesh_data_init_edges(MeshData &mesh_data)
|
||||
int v1 = mesh_data.corner_verts[tri.tri[j]];
|
||||
int v2 = mesh_data.corner_verts[tri.tri[(j + 1) % 3]];
|
||||
|
||||
void **edge_index_ptr;
|
||||
int64_t edge_index;
|
||||
if (BLI_edgehash_ensure_p(eh, v1, v2, &edge_index_ptr)) {
|
||||
edge_index = POINTER_AS_INT(*edge_index_ptr) - 1;
|
||||
*edge_index_ptr = POINTER_FROM_INT(edge_index);
|
||||
}
|
||||
else {
|
||||
edge_index = mesh_data.edges.size();
|
||||
*edge_index_ptr = POINTER_FROM_INT(edge_index + 1);
|
||||
MeshEdge edge;
|
||||
edge.vert1 = v1;
|
||||
edge.vert2 = v2;
|
||||
mesh_data.edges.append(edge);
|
||||
mesh_data.vert_to_edge_map.add(edge_index, v1, v2);
|
||||
}
|
||||
eh.add_or_modify(
|
||||
{v1, v2},
|
||||
[&](int *value) {
|
||||
edge_index = mesh_data.edges.size();
|
||||
*value = edge_index + 1;
|
||||
mesh_data.edges.append({v1, v2});
|
||||
mesh_data.vert_to_edge_map.add(edge_index, v1, v2);
|
||||
},
|
||||
[&](int *value) {
|
||||
edge_index = *value - 1;
|
||||
*value = edge_index;
|
||||
});
|
||||
|
||||
edges.append(edge_index);
|
||||
}
|
||||
@@ -142,8 +144,6 @@ static void mesh_data_init_edges(MeshData &mesh_data)
|
||||
mesh_data.edge_to_primitive_map.add(prim_i, edge_i);
|
||||
}
|
||||
}
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
static constexpr int INVALID_UV_ISLAND_ID = -1;
|
||||
/**
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include <optional>
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_matrix_types.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
@@ -24,8 +24,9 @@
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_task.h"
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_utildefines.h"
|
||||
@@ -264,7 +265,6 @@ static int ss_sync_from_uv(CCGSubSurf *ss,
|
||||
UvVertMap *vmap;
|
||||
blender::Vector<CCGVertHDL, 16> fverts;
|
||||
float limit[2];
|
||||
EdgeSet *eset;
|
||||
float uv[3] = {0.0f, 0.0f, 0.0f}; /* only first 2 values are written into */
|
||||
|
||||
limit[0] = limit[1] = STD_UV_CONNECT_LIMIT;
|
||||
@@ -308,7 +308,8 @@ static int ss_sync_from_uv(CCGSubSurf *ss,
|
||||
}
|
||||
|
||||
/* create edges */
|
||||
eset = BLI_edgeset_new_ex(__func__, BLI_EDGEHASH_SIZE_GUESS_FROM_FACES(totface));
|
||||
blender::Set<blender::OrderedEdge> eset;
|
||||
eset.reserve(totface);
|
||||
|
||||
for (i = 0; i < totface; i++) {
|
||||
const blender::IndexRange face = faces[i];
|
||||
@@ -325,7 +326,7 @@ static int ss_sync_from_uv(CCGSubSurf *ss,
|
||||
uint v0 = POINTER_AS_UINT(fverts[j_next]);
|
||||
uint v1 = POINTER_AS_UINT(fverts[j]);
|
||||
|
||||
if (BLI_edgeset_add(eset, v0, v1)) {
|
||||
if (eset.add({v0, v1})) {
|
||||
CCGEdge *e, *orige = ccgSubSurf_getFaceEdge(origf, j_next);
|
||||
CCGEdgeHDL ehdl = POINTER_FROM_INT(face[j_next]);
|
||||
float crease = ccgSubSurf_getEdgeCrease(orige);
|
||||
@@ -335,8 +336,6 @@ static int ss_sync_from_uv(CCGSubSurf *ss,
|
||||
}
|
||||
}
|
||||
|
||||
BLI_edgeset_free(eset);
|
||||
|
||||
/* create faces */
|
||||
for (i = 0; i < totface; i++) {
|
||||
const blender::IndexRange face = faces[i];
|
||||
@@ -912,10 +911,10 @@ static void copyFinalLoopArray_task_cb(void *__restrict userdata,
|
||||
corner_verts[loop_i + 3] = v4;
|
||||
}
|
||||
if (corner_edges) {
|
||||
corner_edges[loop_i + 0] = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v1, v2));
|
||||
corner_edges[loop_i + 1] = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v2, v3));
|
||||
corner_edges[loop_i + 2] = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v3, v4));
|
||||
corner_edges[loop_i + 3] = POINTER_AS_UINT(BLI_edgehash_lookup(ccgdm->ehash, v4, v1));
|
||||
corner_edges[loop_i + 0] = ccgdm->ehash->index_of({v1, v2});
|
||||
corner_edges[loop_i + 1] = ccgdm->ehash->index_of({v2, v3});
|
||||
corner_edges[loop_i + 2] = ccgdm->ehash->index_of({v3, v4});
|
||||
corner_edges[loop_i + 3] = ccgdm->ehash->index_of({v4, v1});
|
||||
}
|
||||
|
||||
loop_i += 4;
|
||||
@@ -953,15 +952,14 @@ static void ccgDM_copyFinalCornerEdgeArray(DerivedMesh *dm, int *r_corner_edges)
|
||||
if (!ccgdm->ehash) {
|
||||
BLI_mutex_lock(&ccgdm->loops_cache_lock);
|
||||
if (!ccgdm->ehash) {
|
||||
const blender::int2 *medge;
|
||||
EdgeHash *ehash;
|
||||
auto *ehash = new blender::VectorSet<blender::OrderedEdge>();
|
||||
ehash->reserve(ccgdm->dm.numEdgeData);
|
||||
|
||||
ehash = BLI_edgehash_new_ex(__func__, ccgdm->dm.numEdgeData);
|
||||
medge = reinterpret_cast<const blender::int2 *>(
|
||||
const blender::int2 *medge = reinterpret_cast<const blender::int2 *>(
|
||||
ccgdm->dm.getEdgeArray((DerivedMesh *)ccgdm));
|
||||
|
||||
for (int i = 0; i < ccgdm->dm.numEdgeData; i++) {
|
||||
BLI_edgehash_insert(ehash, medge[i][0], medge[i][1], POINTER_FROM_INT(i));
|
||||
ehash->add({medge[i][0], medge[i][1]});
|
||||
}
|
||||
|
||||
atomic_cas_ptr((void **)&ccgdm->ehash, ccgdm->ehash, ehash);
|
||||
@@ -1037,9 +1035,7 @@ static void ccgDM_release(DerivedMesh *dm)
|
||||
}
|
||||
}
|
||||
|
||||
if (ccgdm->ehash) {
|
||||
BLI_edgehash_free(ccgdm->ehash, nullptr);
|
||||
}
|
||||
delete ccgdm->ehash;
|
||||
|
||||
if (ccgdm->reverseFaceMap) {
|
||||
MEM_freeN(ccgdm->reverseFaceMap);
|
||||
|
||||
@@ -1,239 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
/** \file
|
||||
* \ingroup bli
|
||||
*/
|
||||
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct EdgeHash;
|
||||
typedef struct EdgeHash EdgeHash;
|
||||
|
||||
struct _EdgeHash_Edge {
|
||||
uint v_low, v_high;
|
||||
};
|
||||
|
||||
struct _EdgeHash_Entry {
|
||||
struct _EdgeHash_Edge edge;
|
||||
void *value;
|
||||
};
|
||||
|
||||
typedef struct EdgeHashIterator {
|
||||
struct _EdgeHash_Entry *entries;
|
||||
uint length;
|
||||
uint index;
|
||||
} EdgeHashIterator;
|
||||
|
||||
typedef void (*EdgeHashFreeFP)(void *key);
|
||||
|
||||
enum {
|
||||
/**
|
||||
* Only checked for in debug mode.
|
||||
*/
|
||||
EDGEHASH_FLAG_ALLOW_DUPES = (1 << 0),
|
||||
};
|
||||
|
||||
EdgeHash *BLI_edgehash_new_ex(const char *info, unsigned int nentries_reserve);
|
||||
EdgeHash *BLI_edgehash_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
|
||||
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value);
|
||||
void BLI_edgehash_print(EdgeHash *eh);
|
||||
/**
|
||||
* Insert edge (\a v0, \a v1) into hash with given value, does
|
||||
* not check for duplicates.
|
||||
*/
|
||||
void BLI_edgehash_insert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
|
||||
/**
|
||||
* Assign a new value to a key that may already be in edgehash.
|
||||
*/
|
||||
bool BLI_edgehash_reinsert(EdgeHash *eh, unsigned int v0, unsigned int v1, void *val);
|
||||
/**
|
||||
* Return value for given edge (\a v0, \a v1), or NULL if
|
||||
* if key does not exist in hash. (If need exists
|
||||
* to differentiate between key-value being NULL and
|
||||
* lack of key then see #BLI_edgehash_lookup_p().
|
||||
*/
|
||||
void *BLI_edgehash_lookup(const EdgeHash *eh,
|
||||
unsigned int v0,
|
||||
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* A version of #BLI_edgehash_lookup which accepts a fallback argument.
|
||||
*/
|
||||
void *BLI_edgehash_lookup_default(const EdgeHash *eh,
|
||||
unsigned int v0,
|
||||
unsigned int v1,
|
||||
void *default_value) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Return pointer to value for given edge (\a v0, \a v1),
|
||||
* or NULL if key does not exist in hash.
|
||||
*/
|
||||
void **BLI_edgehash_lookup_p(EdgeHash *eh,
|
||||
unsigned int v0,
|
||||
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Ensure \a (v0, v1) is exists in \a eh.
|
||||
*
|
||||
* This handles the common situation where the caller needs ensure a key is added to \a eh,
|
||||
* constructing a new value in the case the key isn't found.
|
||||
* Otherwise use the existing value.
|
||||
*
|
||||
* Such situations typically incur multiple lookups, however this function
|
||||
* avoids them by ensuring the key is added,
|
||||
* returning a pointer to the value so it can be used or initialized by the caller.
|
||||
*
|
||||
* \return true when the value didn't need to be added.
|
||||
* (when false, the caller _must_ initialize the value).
|
||||
*/
|
||||
bool BLI_edgehash_ensure_p(EdgeHash *eh, unsigned int v0, unsigned int v1, void ***r_val)
|
||||
ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Remove \a key (v0, v1) from \a eh, or return false if the key wasn't found.
|
||||
*
|
||||
* \param v0, v1: The key to remove.
|
||||
* \param free_value: Optional callback to free the value.
|
||||
* \return true if \a key was removed from \a eh.
|
||||
*/
|
||||
bool BLI_edgehash_remove(EdgeHash *eh,
|
||||
unsigned int v0,
|
||||
unsigned int v1,
|
||||
EdgeHashFreeFP free_value);
|
||||
|
||||
/**
|
||||
* Remove \a key (v0, v1) from \a eh, returning the value or NULL if the key wasn't found.
|
||||
*
|
||||
* \param v0, v1: The key to remove.
|
||||
* \return the value of \a key int \a eh or NULL.
|
||||
*/
|
||||
void *BLI_edgehash_popkey(EdgeHash *eh, unsigned int v0, unsigned int v1) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Return boolean true/false if edge (v0,v1) in hash.
|
||||
*/
|
||||
bool BLI_edgehash_haskey(const EdgeHash *eh,
|
||||
unsigned int v0,
|
||||
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Return number of keys in hash.
|
||||
*/
|
||||
int BLI_edgehash_len(const EdgeHash *eh) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Remove all edges from hash.
|
||||
*/
|
||||
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, uint reserve);
|
||||
/**
|
||||
* Wraps #BLI_edgehash_clear_ex with zero entries reserved.
|
||||
*/
|
||||
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value);
|
||||
|
||||
/**
|
||||
* Create a new #EdgeHashIterator. The hash table must not be mutated
|
||||
* while the iterator is in use, and the iterator will step exactly
|
||||
* #BLI_edgehash_len(eh) times before becoming done.
|
||||
*/
|
||||
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* Initialize an already allocated #EdgeHashIterator. The hash table must not
|
||||
* be mutated while the iterator is in use, and the iterator will
|
||||
* step exactly BLI_edgehash_len(eh) times before becoming done.
|
||||
*
|
||||
* \param ehi: The #EdgeHashIterator to initialize.
|
||||
* \param eh: The #EdgeHash to iterate over.
|
||||
*/
|
||||
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh);
|
||||
/**
|
||||
* Free an #EdgeHashIterator.
|
||||
*/
|
||||
void BLI_edgehashIterator_free(EdgeHashIterator *ehi);
|
||||
|
||||
BLI_INLINE void BLI_edgehashIterator_step(EdgeHashIterator *ehi)
|
||||
{
|
||||
ehi->index++;
|
||||
}
|
||||
BLI_INLINE bool BLI_edgehashIterator_isDone(const EdgeHashIterator *ehi)
|
||||
{
|
||||
return ehi->index >= ehi->length;
|
||||
}
|
||||
BLI_INLINE void BLI_edgehashIterator_getKey(EdgeHashIterator *ehi, int *r_v0, int *r_v1)
|
||||
{
|
||||
struct _EdgeHash_Edge edge = ehi->entries[ehi->index].edge;
|
||||
*r_v0 = edge.v_low;
|
||||
*r_v1 = edge.v_high;
|
||||
}
|
||||
BLI_INLINE void *BLI_edgehashIterator_getValue(EdgeHashIterator *ehi)
|
||||
{
|
||||
return ehi->entries[ehi->index].value;
|
||||
}
|
||||
BLI_INLINE void **BLI_edgehashIterator_getValue_p(EdgeHashIterator *ehi)
|
||||
{
|
||||
return &ehi->entries[ehi->index].value;
|
||||
}
|
||||
BLI_INLINE void BLI_edgehashIterator_setValue(EdgeHashIterator *ehi, void *val)
|
||||
{
|
||||
ehi->entries[ehi->index].value = val;
|
||||
}
|
||||
|
||||
#define BLI_EDGEHASH_SIZE_GUESS_FROM_LOOPS(totloop) ((totloop) / 2)
|
||||
#define BLI_EDGEHASH_SIZE_GUESS_FROM_FACES(faces_num) ((faces_num)*2)
|
||||
|
||||
/* *** EdgeSet *** */
|
||||
|
||||
struct EdgeSet;
|
||||
typedef struct EdgeSet EdgeSet;
|
||||
|
||||
typedef struct EdgeSetIterator {
|
||||
struct _EdgeHash_Edge *edges;
|
||||
uint length;
|
||||
uint index;
|
||||
} EdgeSetIterator;
|
||||
|
||||
EdgeSet *BLI_edgeset_new_ex(const char *info,
|
||||
unsigned int nentries_reserve) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
|
||||
EdgeSet *BLI_edgeset_new(const char *info) ATTR_MALLOC ATTR_WARN_UNUSED_RESULT;
|
||||
int BLI_edgeset_len(const EdgeSet *es) ATTR_WARN_UNUSED_RESULT;
|
||||
/**
|
||||
* A version of BLI_edgeset_insert which checks first if the key is in the set.
|
||||
* \returns true if a new key has been added.
|
||||
*
|
||||
* \note #EdgeHash has no equivalent to this because typically the value would be different.
|
||||
*/
|
||||
bool BLI_edgeset_add(EdgeSet *es, unsigned int v0, unsigned int v1);
|
||||
/**
|
||||
* Adds the key to the set (no checks for unique keys!).
|
||||
* Matching #BLI_edgehash_insert
|
||||
*/
|
||||
void BLI_edgeset_insert(EdgeSet *es, unsigned int v0, unsigned int v1);
|
||||
bool BLI_edgeset_haskey(const EdgeSet *es,
|
||||
unsigned int v0,
|
||||
unsigned int v1) ATTR_WARN_UNUSED_RESULT;
|
||||
void BLI_edgeset_free(EdgeSet *es);
|
||||
|
||||
/* rely on inline api for now */
|
||||
|
||||
EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *es);
|
||||
void BLI_edgesetIterator_free(EdgeSetIterator *esi);
|
||||
|
||||
BLI_INLINE void BLI_edgesetIterator_getKey(EdgeSetIterator *esi, int *r_v0, int *r_v1)
|
||||
{
|
||||
struct _EdgeHash_Edge edge = esi->edges[esi->index];
|
||||
*r_v0 = edge.v_low;
|
||||
*r_v1 = edge.v_high;
|
||||
}
|
||||
BLI_INLINE void BLI_edgesetIterator_step(EdgeSetIterator *esi)
|
||||
{
|
||||
esi->index++;
|
||||
}
|
||||
BLI_INLINE bool BLI_edgesetIterator_isDone(const EdgeSetIterator *esi)
|
||||
{
|
||||
return esi->index >= esi->length;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -63,7 +63,6 @@ set(SRC
|
||||
intern/dot_export.cc
|
||||
intern/dynlib.c
|
||||
intern/easing.c
|
||||
intern/edgehash.c
|
||||
intern/endian_switch.c
|
||||
intern/expr_pylike_eval.c
|
||||
intern/fileops.c
|
||||
@@ -221,7 +220,6 @@ set(SRC
|
||||
BLI_dynlib.h
|
||||
BLI_dynstr.h
|
||||
BLI_easing.h
|
||||
BLI_edgehash.h
|
||||
BLI_endian_defines.h
|
||||
BLI_endian_switch.h
|
||||
BLI_endian_switch_inline.h
|
||||
@@ -498,7 +496,6 @@ if(WITH_GTESTS)
|
||||
tests/BLI_cpp_type_test.cc
|
||||
tests/BLI_delaunay_2d_test.cc
|
||||
tests/BLI_disjoint_set_test.cc
|
||||
tests/BLI_edgehash_test.cc
|
||||
tests/BLI_expr_pylike_eval_test.cc
|
||||
tests/BLI_fileops_test.cc
|
||||
tests/BLI_function_ref_test.cc
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
/**
|
||||
* Next prime after `2^n` (skipping 2 & 3).
|
||||
*
|
||||
* \note Also used by: `BLI_edgehash` & `BLI_smallhash`.
|
||||
* \note Also used by: `BLI_smallhash`.
|
||||
*/
|
||||
extern const uint BLI_ghash_hash_sizes[]; /* Quiet warning, this is only used by smallhash.c */
|
||||
const uint BLI_ghash_hash_sizes[] = {
|
||||
|
||||
@@ -1,543 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup bli
|
||||
*
|
||||
* An (edge -> pointer) hash table.
|
||||
* Using unordered int-pairs as keys.
|
||||
*
|
||||
* \note The API matches BLI_ghash.c, but the implementation is different.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_strict_flags.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
typedef struct _EdgeHash_Edge Edge;
|
||||
typedef struct _EdgeHash_Entry EdgeHashEntry;
|
||||
|
||||
typedef struct EdgeHash {
|
||||
EdgeHashEntry *entries;
|
||||
int32_t *map;
|
||||
uint32_t slot_mask;
|
||||
uint capacity_exp;
|
||||
uint length;
|
||||
uint dummy_count;
|
||||
} EdgeHash;
|
||||
|
||||
typedef struct EdgeSet {
|
||||
Edge *entries;
|
||||
int32_t *map;
|
||||
uint32_t slot_mask;
|
||||
uint capacity_exp;
|
||||
uint length;
|
||||
} EdgeSet;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Helper Macros & Defines
|
||||
* \{ */
|
||||
|
||||
#define ENTRIES_CAPACITY(container) (uint)(1 << (container)->capacity_exp)
|
||||
#define MAP_CAPACITY(container) (uint)(1 << ((container)->capacity_exp + 1))
|
||||
#define CLEAR_MAP(container) \
|
||||
memset((container)->map, 0xFF, sizeof(int32_t) * MAP_CAPACITY(container))
|
||||
#define UPDATE_SLOT_MASK(container) \
|
||||
{ \
|
||||
(container)->slot_mask = MAP_CAPACITY(container) - 1; \
|
||||
} \
|
||||
((void)0)
|
||||
#define PERTURB_SHIFT 5
|
||||
|
||||
#define ITER_SLOTS(CONTAINER, EDGE, SLOT, INDEX) \
|
||||
uint32_t hash = calc_edge_hash(EDGE); \
|
||||
uint32_t mask = (CONTAINER)->slot_mask; \
|
||||
uint32_t perturb = hash; \
|
||||
int32_t *map = (CONTAINER)->map; \
|
||||
uint32_t SLOT = mask & hash; \
|
||||
int INDEX = map[SLOT]; \
|
||||
for (;; SLOT = mask & ((5 * SLOT) + 1 + perturb), perturb >>= PERTURB_SHIFT, INDEX = map[SLOT])
|
||||
|
||||
#define SLOT_EMPTY -1
|
||||
#define SLOT_DUMMY -2
|
||||
|
||||
#define CAPACITY_EXP_DEFAULT 3
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Edge API
|
||||
* \{ */
|
||||
|
||||
BLI_INLINE uint32_t calc_edge_hash(Edge edge)
|
||||
{
|
||||
return (edge.v_low << 8) ^ edge.v_high;
|
||||
}
|
||||
|
||||
BLI_INLINE Edge init_edge(uint v0, uint v1)
|
||||
{
|
||||
/* If there are use cases where we need this it could be removed (or flag to allow),
|
||||
* for now this helps avoid incorrect usage (creating degenerate geometry). */
|
||||
BLI_assert(v0 != v1);
|
||||
Edge edge;
|
||||
if (v0 < v1) {
|
||||
edge.v_low = v0;
|
||||
edge.v_high = v1;
|
||||
}
|
||||
else {
|
||||
edge.v_low = v1;
|
||||
edge.v_high = v0;
|
||||
}
|
||||
return edge;
|
||||
}
|
||||
|
||||
BLI_INLINE bool edges_equal(Edge e1, Edge e2)
|
||||
{
|
||||
return memcmp(&e1, &e2, sizeof(Edge)) == 0;
|
||||
}
|
||||
|
||||
static uint calc_capacity_exp_for_reserve(uint reserve)
|
||||
{
|
||||
uint result = 1;
|
||||
while (reserve >>= 1) {
|
||||
result++;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Utility API
|
||||
* \{ */
|
||||
|
||||
#define EH_INDEX_HAS_EDGE(eh, index, edge) \
|
||||
((index) >= 0 && edges_equal((edge), (eh)->entries[index].edge))
|
||||
|
||||
static void edgehash_free_values(EdgeHash *eh, EdgeHashFreeFP free_value)
|
||||
{
|
||||
if (free_value) {
|
||||
for (uint i = 0; i < eh->length; i++) {
|
||||
free_value(eh->entries[i].value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE void edgehash_insert_index(EdgeHash *eh, Edge edge, uint entry_index)
|
||||
{
|
||||
ITER_SLOTS (eh, edge, slot, index) {
|
||||
if (index == SLOT_EMPTY) {
|
||||
eh->map[slot] = (int32_t)entry_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE EdgeHashEntry *edgehash_insert_at_slot(EdgeHash *eh, uint slot, Edge edge, void *value)
|
||||
{
|
||||
EdgeHashEntry *entry = &eh->entries[eh->length];
|
||||
entry->edge = edge;
|
||||
entry->value = value;
|
||||
eh->map[slot] = (int32_t)eh->length;
|
||||
eh->length++;
|
||||
return entry;
|
||||
}
|
||||
|
||||
BLI_INLINE bool edgehash_ensure_can_insert(EdgeHash *eh)
|
||||
{
|
||||
if (UNLIKELY(ENTRIES_CAPACITY(eh) <= eh->length + eh->dummy_count)) {
|
||||
eh->capacity_exp++;
|
||||
UPDATE_SLOT_MASK(eh);
|
||||
eh->dummy_count = 0;
|
||||
eh->entries = MEM_reallocN(eh->entries, sizeof(EdgeHashEntry) * ENTRIES_CAPACITY(eh));
|
||||
eh->map = MEM_reallocN(eh->map, sizeof(int32_t) * MAP_CAPACITY(eh));
|
||||
CLEAR_MAP(eh);
|
||||
for (uint i = 0; i < eh->length; i++) {
|
||||
edgehash_insert_index(eh, eh->entries[i].edge, i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
BLI_INLINE EdgeHashEntry *edgehash_insert(EdgeHash *eh, Edge edge, void *value)
|
||||
{
|
||||
ITER_SLOTS (eh, edge, slot, index) {
|
||||
if (index == SLOT_EMPTY) {
|
||||
return edgehash_insert_at_slot(eh, slot, edge, value);
|
||||
}
|
||||
if (index == SLOT_DUMMY) {
|
||||
eh->dummy_count--;
|
||||
return edgehash_insert_at_slot(eh, slot, edge, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE EdgeHashEntry *edgehash_lookup_entry(const EdgeHash *eh, uint v0, uint v1)
|
||||
{
|
||||
Edge edge = init_edge(v0, v1);
|
||||
|
||||
ITER_SLOTS (eh, edge, slot, index) {
|
||||
if (EH_INDEX_HAS_EDGE(eh, index, edge)) {
|
||||
return &eh->entries[index];
|
||||
}
|
||||
if (index == SLOT_EMPTY) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE void edgehash_change_index(EdgeHash *eh, Edge edge, int new_index)
|
||||
{
|
||||
ITER_SLOTS (eh, edge, slot, index) {
|
||||
if (EH_INDEX_HAS_EDGE(eh, index, edge)) {
|
||||
eh->map[slot] = new_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Edge Hash API
|
||||
* \{ */
|
||||
|
||||
EdgeHash *BLI_edgehash_new_ex(const char *info, const uint reserve)
|
||||
{
|
||||
EdgeHash *eh = MEM_mallocN(sizeof(EdgeHash), info);
|
||||
eh->capacity_exp = calc_capacity_exp_for_reserve(reserve);
|
||||
UPDATE_SLOT_MASK(eh);
|
||||
eh->length = 0;
|
||||
eh->dummy_count = 0;
|
||||
eh->entries = MEM_calloc_arrayN(ENTRIES_CAPACITY(eh), sizeof(EdgeHashEntry), "eh entries");
|
||||
eh->map = MEM_malloc_arrayN(MAP_CAPACITY(eh), sizeof(int32_t), "eh map");
|
||||
CLEAR_MAP(eh);
|
||||
return eh;
|
||||
}
|
||||
|
||||
EdgeHash *BLI_edgehash_new(const char *info)
|
||||
{
|
||||
return BLI_edgehash_new_ex(info, 1 << CAPACITY_EXP_DEFAULT);
|
||||
}
|
||||
|
||||
void BLI_edgehash_free(EdgeHash *eh, EdgeHashFreeFP free_value)
|
||||
{
|
||||
edgehash_free_values(eh, free_value);
|
||||
MEM_freeN(eh->map);
|
||||
MEM_freeN(eh->entries);
|
||||
MEM_freeN(eh);
|
||||
}
|
||||
|
||||
void BLI_edgehash_print(EdgeHash *eh)
|
||||
{
|
||||
printf("Edgehash at %p:\n", eh);
|
||||
printf(" Map:\n");
|
||||
for (uint i = 0; i < MAP_CAPACITY(eh); i++) {
|
||||
int index = eh->map[i];
|
||||
printf(" %u: %d", i, index);
|
||||
if (index >= 0) {
|
||||
EdgeHashEntry entry = eh->entries[index];
|
||||
printf(" -> (%u, %u) -> %p", entry.edge.v_low, entry.edge.v_high, entry.value);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf(" Entries:\n");
|
||||
for (uint i = 0; i < ENTRIES_CAPACITY(eh); i++) {
|
||||
if (i == eh->length) {
|
||||
printf(" **** below is rest capacity ****\n");
|
||||
}
|
||||
EdgeHashEntry entry = eh->entries[i];
|
||||
printf(" %u: (%u, %u) -> %p\n", i, entry.edge.v_low, entry.edge.v_high, entry.value);
|
||||
}
|
||||
}
|
||||
|
||||
void BLI_edgehash_insert(EdgeHash *eh, uint v0, uint v1, void *value)
|
||||
{
|
||||
edgehash_ensure_can_insert(eh);
|
||||
Edge edge = init_edge(v0, v1);
|
||||
edgehash_insert(eh, edge, value);
|
||||
}
|
||||
|
||||
bool BLI_edgehash_reinsert(EdgeHash *eh, uint v0, uint v1, void *value)
|
||||
{
|
||||
Edge edge = init_edge(v0, v1);
|
||||
|
||||
ITER_SLOTS (eh, edge, slot, index) {
|
||||
if (EH_INDEX_HAS_EDGE(eh, index, edge)) {
|
||||
eh->entries[index].value = value;
|
||||
return false;
|
||||
}
|
||||
if (index == SLOT_EMPTY) {
|
||||
if (edgehash_ensure_can_insert(eh)) {
|
||||
edgehash_insert(eh, edge, value);
|
||||
}
|
||||
else {
|
||||
edgehash_insert_at_slot(eh, slot, edge, value);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void *BLI_edgehash_lookup_default(const EdgeHash *eh, uint v0, uint v1, void *default_value)
|
||||
{
|
||||
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
|
||||
return entry ? entry->value : default_value;
|
||||
}
|
||||
|
||||
void *BLI_edgehash_lookup(const EdgeHash *eh, uint v0, uint v1)
|
||||
{
|
||||
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
|
||||
return entry ? entry->value : NULL;
|
||||
}
|
||||
|
||||
void **BLI_edgehash_lookup_p(EdgeHash *eh, uint v0, uint v1)
|
||||
{
|
||||
EdgeHashEntry *entry = edgehash_lookup_entry(eh, v0, v1);
|
||||
return entry ? &entry->value : NULL;
|
||||
}
|
||||
|
||||
bool BLI_edgehash_ensure_p(EdgeHash *eh, uint v0, uint v1, void ***r_value)
|
||||
{
|
||||
Edge edge = init_edge(v0, v1);
|
||||
|
||||
ITER_SLOTS (eh, edge, slot, index) {
|
||||
if (EH_INDEX_HAS_EDGE(eh, index, edge)) {
|
||||
*r_value = &eh->entries[index].value;
|
||||
return true;
|
||||
}
|
||||
if (index == SLOT_EMPTY) {
|
||||
if (edgehash_ensure_can_insert(eh)) {
|
||||
*r_value = &edgehash_insert(eh, edge, NULL)->value;
|
||||
}
|
||||
else {
|
||||
*r_value = &edgehash_insert_at_slot(eh, slot, edge, NULL)->value;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BLI_edgehash_remove(EdgeHash *eh, uint v0, uint v1, EdgeHashFreeFP free_value)
|
||||
{
|
||||
uint old_length = eh->length;
|
||||
void *value = BLI_edgehash_popkey(eh, v0, v1);
|
||||
if (free_value && value) {
|
||||
free_value(value);
|
||||
}
|
||||
return old_length > eh->length;
|
||||
}
|
||||
|
||||
void *BLI_edgehash_popkey(EdgeHash *eh, uint v0, uint v1)
|
||||
{
|
||||
/* Same as #BLI_edgehash_remove but return the value,
|
||||
* no free value argument since it will be returned */
|
||||
|
||||
Edge edge = init_edge(v0, v1);
|
||||
|
||||
ITER_SLOTS (eh, edge, slot, index) {
|
||||
if (EH_INDEX_HAS_EDGE(eh, index, edge)) {
|
||||
void *value = eh->entries[index].value;
|
||||
eh->length--;
|
||||
eh->dummy_count++;
|
||||
eh->map[slot] = SLOT_DUMMY;
|
||||
eh->entries[index] = eh->entries[eh->length];
|
||||
if ((uint)index < eh->length) {
|
||||
edgehash_change_index(eh, eh->entries[index].edge, index);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
if (index == SLOT_EMPTY) {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BLI_edgehash_haskey(const EdgeHash *eh, uint v0, uint v1)
|
||||
{
|
||||
return edgehash_lookup_entry(eh, v0, v1) != NULL;
|
||||
}
|
||||
|
||||
int BLI_edgehash_len(const EdgeHash *eh)
|
||||
{
|
||||
return (int)eh->length;
|
||||
}
|
||||
|
||||
void BLI_edgehash_clear_ex(EdgeHash *eh, EdgeHashFreeFP free_value, const uint UNUSED(reserve))
|
||||
{
|
||||
/* TODO: handle reserve */
|
||||
edgehash_free_values(eh, free_value);
|
||||
eh->length = 0;
|
||||
eh->dummy_count = 0;
|
||||
eh->capacity_exp = CAPACITY_EXP_DEFAULT;
|
||||
CLEAR_MAP(eh);
|
||||
}
|
||||
|
||||
void BLI_edgehash_clear(EdgeHash *eh, EdgeHashFreeFP free_value)
|
||||
{
|
||||
BLI_edgehash_clear_ex(eh, free_value, 0);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Edge Hash Iterator API
|
||||
* \{ */
|
||||
|
||||
EdgeHashIterator *BLI_edgehashIterator_new(EdgeHash *eh)
|
||||
{
|
||||
EdgeHashIterator *ehi = MEM_mallocN(sizeof(EdgeHashIterator), __func__);
|
||||
BLI_edgehashIterator_init(ehi, eh);
|
||||
return ehi;
|
||||
}
|
||||
|
||||
void BLI_edgehashIterator_init(EdgeHashIterator *ehi, EdgeHash *eh)
|
||||
{
|
||||
ehi->entries = eh->entries;
|
||||
ehi->length = eh->length;
|
||||
ehi->index = 0;
|
||||
}
|
||||
|
||||
void BLI_edgehashIterator_free(EdgeHashIterator *ehi)
|
||||
{
|
||||
MEM_freeN(ehi);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name EdgeSet API
|
||||
*
|
||||
* Use edgehash API to give 'set' functionality
|
||||
* \{ */
|
||||
|
||||
#define ES_INDEX_HAS_EDGE(es, index, edge) \
|
||||
(index) >= 0 && edges_equal((edge), (es)->entries[index])
|
||||
|
||||
EdgeSet *BLI_edgeset_new_ex(const char *info, const uint reserve)
|
||||
{
|
||||
EdgeSet *es = MEM_mallocN(sizeof(EdgeSet), info);
|
||||
es->capacity_exp = calc_capacity_exp_for_reserve(reserve);
|
||||
UPDATE_SLOT_MASK(es);
|
||||
es->length = 0;
|
||||
es->entries = MEM_malloc_arrayN(ENTRIES_CAPACITY(es), sizeof(Edge), "es entries");
|
||||
es->map = MEM_malloc_arrayN(MAP_CAPACITY(es), sizeof(int32_t), "es map");
|
||||
CLEAR_MAP(es);
|
||||
return es;
|
||||
}
|
||||
|
||||
EdgeSet *BLI_edgeset_new(const char *info)
|
||||
{
|
||||
return BLI_edgeset_new_ex(info, 1 << CAPACITY_EXP_DEFAULT);
|
||||
}
|
||||
|
||||
void BLI_edgeset_free(EdgeSet *es)
|
||||
{
|
||||
MEM_freeN(es->entries);
|
||||
MEM_freeN(es->map);
|
||||
MEM_freeN(es);
|
||||
}
|
||||
|
||||
int BLI_edgeset_len(const EdgeSet *es)
|
||||
{
|
||||
return (int)es->length;
|
||||
}
|
||||
|
||||
static void edgeset_insert_index(EdgeSet *es, Edge edge, uint entry_index)
|
||||
{
|
||||
ITER_SLOTS (es, edge, slot, index) {
|
||||
if (index == SLOT_EMPTY) {
|
||||
es->map[slot] = (int)entry_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE void edgeset_ensure_can_insert(EdgeSet *es)
|
||||
{
|
||||
if (UNLIKELY(ENTRIES_CAPACITY(es) <= es->length)) {
|
||||
es->capacity_exp++;
|
||||
UPDATE_SLOT_MASK(es);
|
||||
es->entries = MEM_reallocN(es->entries, sizeof(Edge) * ENTRIES_CAPACITY(es));
|
||||
es->map = MEM_reallocN(es->map, sizeof(int32_t) * MAP_CAPACITY(es));
|
||||
CLEAR_MAP(es);
|
||||
for (uint i = 0; i < es->length; i++) {
|
||||
edgeset_insert_index(es, es->entries[i], i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BLI_INLINE void edgeset_insert_at_slot(EdgeSet *es, uint slot, Edge edge)
|
||||
{
|
||||
es->entries[es->length] = edge;
|
||||
es->map[slot] = (int)es->length;
|
||||
es->length++;
|
||||
}
|
||||
|
||||
bool BLI_edgeset_add(EdgeSet *es, uint v0, uint v1)
|
||||
{
|
||||
edgeset_ensure_can_insert(es);
|
||||
Edge edge = init_edge(v0, v1);
|
||||
|
||||
ITER_SLOTS (es, edge, slot, index) {
|
||||
if (ES_INDEX_HAS_EDGE(es, index, edge)) {
|
||||
return false;
|
||||
}
|
||||
if (index == SLOT_EMPTY) {
|
||||
edgeset_insert_at_slot(es, slot, edge);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BLI_edgeset_insert(EdgeSet *es, uint v0, uint v1)
|
||||
{
|
||||
edgeset_ensure_can_insert(es);
|
||||
Edge edge = init_edge(v0, v1);
|
||||
|
||||
ITER_SLOTS (es, edge, slot, index) {
|
||||
if (index == SLOT_EMPTY) {
|
||||
edgeset_insert_at_slot(es, slot, edge);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BLI_edgeset_haskey(const EdgeSet *es, uint v0, uint v1)
|
||||
{
|
||||
Edge edge = init_edge(v0, v1);
|
||||
|
||||
ITER_SLOTS (es, edge, slot, index) {
|
||||
if (ES_INDEX_HAS_EDGE(es, index, edge)) {
|
||||
return true;
|
||||
}
|
||||
if (index == SLOT_EMPTY) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EdgeSetIterator *BLI_edgesetIterator_new(EdgeSet *es)
|
||||
{
|
||||
EdgeSetIterator *esi = MEM_mallocN(sizeof(EdgeSetIterator), __func__);
|
||||
esi->edges = es->entries;
|
||||
esi->length = es->length;
|
||||
esi->index = 0;
|
||||
return esi;
|
||||
}
|
||||
|
||||
void BLI_edgesetIterator_free(EdgeSetIterator *esi)
|
||||
{
|
||||
MEM_freeN(esi);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -1,410 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#include "testing/testing.h"
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#define VALUE_1 POINTER_FROM_INT(1)
|
||||
#define VALUE_2 POINTER_FROM_INT(2)
|
||||
#define VALUE_3 POINTER_FROM_INT(3)
|
||||
|
||||
TEST(edgehash, InsertIncreasesLength)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 0);
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, ReinsertNewIncreasesLength)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 0);
|
||||
BLI_edgehash_reinsert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, ReinsertExistingDoesNotIncreaseLength)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 0);
|
||||
BLI_edgehash_reinsert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
BLI_edgehash_reinsert(eh, 1, 2, VALUE_2);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
BLI_edgehash_reinsert(eh, 2, 1, VALUE_2);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, ReinsertCanChangeValue)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_1);
|
||||
BLI_edgehash_reinsert(eh, 2, 1, VALUE_2);
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_2);
|
||||
BLI_edgehash_reinsert(eh, 1, 2, VALUE_3);
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 2, 1), VALUE_3);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, LookupExisting)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 2, 1), VALUE_1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, LookupNonExisting)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), nullptr);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, LookupNonExistingWithDefault)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_lookup_default(eh, 1, 2, VALUE_1), VALUE_1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, LookupExistingWithDefault)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_lookup_default(eh, 1, 2, VALUE_2), VALUE_1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, LookupPExisting)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
void *value = VALUE_1;
|
||||
BLI_edgehash_insert(eh, 1, 2, value);
|
||||
void **value_p = BLI_edgehash_lookup_p(eh, 1, 2);
|
||||
ASSERT_EQ(*value_p, VALUE_1);
|
||||
*value_p = VALUE_2;
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_2);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, LookupPNonExisting)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_lookup_p(eh, 1, 2), nullptr);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, EnsurePNonExisting)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
void **value_p;
|
||||
bool existed = BLI_edgehash_ensure_p(eh, 1, 2, &value_p);
|
||||
ASSERT_FALSE(existed);
|
||||
*value_p = VALUE_1;
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, EnsurePExisting)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
void **value_p;
|
||||
bool existed = BLI_edgehash_ensure_p(eh, 1, 2, &value_p);
|
||||
ASSERT_TRUE(existed);
|
||||
ASSERT_EQ(*value_p, VALUE_1);
|
||||
*value_p = VALUE_2;
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 1, 2), VALUE_2);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, RemoveExistingDecreasesLength)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
bool has_been_removed = BLI_edgehash_remove(eh, 1, 2, nullptr);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 0);
|
||||
ASSERT_TRUE(has_been_removed);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, RemoveNonExistingDoesNotDecreaseLength)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
bool has_been_removed = BLI_edgehash_remove(eh, 4, 5, nullptr);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
ASSERT_FALSE(has_been_removed);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, PopKeyTwice)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_popkey(eh, 1, 2), VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_popkey(eh, 1, 2), nullptr);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, LookupInvertedIndices)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_EQ(BLI_edgehash_lookup(eh, 2, 1), VALUE_1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, HasKeyExisting)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
ASSERT_TRUE(BLI_edgehash_haskey(eh, 1, 2));
|
||||
ASSERT_TRUE(BLI_edgehash_haskey(eh, 2, 1));
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, HasKeyNonExisting)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
ASSERT_FALSE(BLI_edgehash_haskey(eh, 1, 2));
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, ClearSetsLengthToZero)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_2);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 2);
|
||||
BLI_edgehash_clear(eh, nullptr);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 0);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, IteratorFindsAllValues)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
BLI_edgehash_insert(eh, 1, 3, VALUE_2);
|
||||
BLI_edgehash_insert(eh, 1, 4, VALUE_3);
|
||||
|
||||
EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh);
|
||||
auto *a = BLI_edgehashIterator_getValue(ehi);
|
||||
BLI_edgehashIterator_step(ehi);
|
||||
auto *b = BLI_edgehashIterator_getValue(ehi);
|
||||
BLI_edgehashIterator_step(ehi);
|
||||
auto *c = BLI_edgehashIterator_getValue(ehi);
|
||||
BLI_edgehashIterator_step(ehi);
|
||||
|
||||
ASSERT_NE(a, b);
|
||||
ASSERT_NE(b, c);
|
||||
ASSERT_NE(a, c);
|
||||
ASSERT_TRUE(ELEM(a, VALUE_1, VALUE_2, VALUE_3));
|
||||
ASSERT_TRUE(ELEM(b, VALUE_1, VALUE_2, VALUE_3));
|
||||
ASSERT_TRUE(ELEM(c, VALUE_1, VALUE_2, VALUE_3));
|
||||
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, IterateIsDone)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
BLI_edgehash_insert(eh, 1, 3, VALUE_2);
|
||||
BLI_edgehash_insert(eh, 1, 4, VALUE_3);
|
||||
|
||||
EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh);
|
||||
ASSERT_FALSE(BLI_edgehashIterator_isDone(ehi));
|
||||
BLI_edgehashIterator_step(ehi);
|
||||
ASSERT_FALSE(BLI_edgehashIterator_isDone(ehi));
|
||||
BLI_edgehashIterator_step(ehi);
|
||||
ASSERT_FALSE(BLI_edgehashIterator_isDone(ehi));
|
||||
BLI_edgehashIterator_step(ehi);
|
||||
ASSERT_TRUE(BLI_edgehashIterator_isDone(ehi));
|
||||
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgehash, DoubleRemove)
|
||||
{
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
BLI_edgehash_insert(eh, 1, 2, VALUE_1);
|
||||
BLI_edgehash_insert(eh, 1, 3, VALUE_2);
|
||||
BLI_edgehash_insert(eh, 1, 4, VALUE_3);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 3);
|
||||
|
||||
BLI_edgehash_remove(eh, 1, 2, nullptr);
|
||||
BLI_edgehash_remove(eh, 1, 3, nullptr);
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 1);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
struct Edge {
|
||||
uint v1, v2;
|
||||
};
|
||||
|
||||
TEST(edgehash, StressTest)
|
||||
{
|
||||
std::srand(0);
|
||||
int amount = 10000;
|
||||
|
||||
std::vector<Edge> edges;
|
||||
for (int i = 0; i < amount; i++) {
|
||||
edges.push_back({uint(i), amount + uint(std::rand()) % 12345});
|
||||
}
|
||||
|
||||
EdgeHash *eh = BLI_edgehash_new(__func__);
|
||||
|
||||
/* first insert all the edges */
|
||||
for (int i = 0; i < edges.size(); i++) {
|
||||
BLI_edgehash_insert(eh, edges[i].v1, edges[i].v2, POINTER_FROM_INT(i));
|
||||
}
|
||||
|
||||
std::vector<Edge> shuffled = edges;
|
||||
std::shuffle(shuffled.begin(), shuffled.end(), std::default_random_engine());
|
||||
|
||||
/* then remove half of them */
|
||||
int remove_until = shuffled.size() / 2;
|
||||
for (int i = 0; i < remove_until; i++) {
|
||||
BLI_edgehash_remove(eh, shuffled[i].v2, shuffled[i].v1, nullptr);
|
||||
}
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), edges.size() - remove_until);
|
||||
|
||||
/* check if the right ones have been removed */
|
||||
for (int i = 0; i < shuffled.size(); i++) {
|
||||
bool haskey = BLI_edgehash_haskey(eh, shuffled[i].v1, shuffled[i].v2);
|
||||
if (i < remove_until) {
|
||||
ASSERT_FALSE(haskey);
|
||||
}
|
||||
else {
|
||||
ASSERT_TRUE(haskey);
|
||||
}
|
||||
}
|
||||
|
||||
/* reinsert all edges */
|
||||
for (int i = 0; i < edges.size(); i++) {
|
||||
BLI_edgehash_reinsert(eh, edges[i].v1, edges[i].v2, POINTER_FROM_INT(i));
|
||||
}
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), edges.size());
|
||||
|
||||
/* pop all edges */
|
||||
for (int i = 0; i < edges.size(); i++) {
|
||||
int value = POINTER_AS_INT(BLI_edgehash_popkey(eh, edges[i].v1, edges[i].v2));
|
||||
ASSERT_EQ(i, value);
|
||||
}
|
||||
|
||||
ASSERT_EQ(BLI_edgehash_len(eh), 0);
|
||||
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
}
|
||||
|
||||
TEST(edgeset, AddNonExistingIncreasesLength)
|
||||
{
|
||||
EdgeSet *es = BLI_edgeset_new(__func__);
|
||||
|
||||
ASSERT_EQ(BLI_edgeset_len(es), 0);
|
||||
BLI_edgeset_add(es, 1, 2);
|
||||
ASSERT_EQ(BLI_edgeset_len(es), 1);
|
||||
BLI_edgeset_add(es, 1, 3);
|
||||
ASSERT_EQ(BLI_edgeset_len(es), 2);
|
||||
BLI_edgeset_add(es, 1, 4);
|
||||
ASSERT_EQ(BLI_edgeset_len(es), 3);
|
||||
|
||||
BLI_edgeset_free(es);
|
||||
}
|
||||
|
||||
TEST(edgeset, AddExistingDoesNotIncreaseLength)
|
||||
{
|
||||
EdgeSet *es = BLI_edgeset_new(__func__);
|
||||
|
||||
ASSERT_EQ(BLI_edgeset_len(es), 0);
|
||||
BLI_edgeset_add(es, 1, 2);
|
||||
ASSERT_EQ(BLI_edgeset_len(es), 1);
|
||||
BLI_edgeset_add(es, 2, 1);
|
||||
ASSERT_EQ(BLI_edgeset_len(es), 1);
|
||||
BLI_edgeset_add(es, 1, 2);
|
||||
ASSERT_EQ(BLI_edgeset_len(es), 1);
|
||||
|
||||
BLI_edgeset_free(es);
|
||||
}
|
||||
|
||||
TEST(edgeset, HasKeyNonExisting)
|
||||
{
|
||||
EdgeSet *es = BLI_edgeset_new(__func__);
|
||||
|
||||
ASSERT_FALSE(BLI_edgeset_haskey(es, 1, 2));
|
||||
|
||||
BLI_edgeset_free(es);
|
||||
}
|
||||
|
||||
TEST(edgeset, HasKeyExisting)
|
||||
{
|
||||
EdgeSet *es = BLI_edgeset_new(__func__);
|
||||
|
||||
BLI_edgeset_insert(es, 1, 2);
|
||||
ASSERT_TRUE(BLI_edgeset_haskey(es, 1, 2));
|
||||
|
||||
BLI_edgeset_free(es);
|
||||
}
|
||||
@@ -14,8 +14,9 @@
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_array_utils.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_polyfill_2d.h"
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
@@ -92,42 +93,29 @@ static void test_polyfill_topology(const float /*poly*/[][2],
|
||||
const uint tris[][3],
|
||||
const uint tris_num)
|
||||
{
|
||||
EdgeHash *edgehash = BLI_edgehash_new(__func__);
|
||||
EdgeHashIterator *ehi;
|
||||
blender::Map<blender::OrderedEdge, int> edgehash;
|
||||
uint i;
|
||||
for (i = 0; i < tris_num; i++) {
|
||||
uint j;
|
||||
for (j = 0; j < 3; j++) {
|
||||
const uint v1 = tris[i][j];
|
||||
const uint v2 = tris[i][(j + 1) % 3];
|
||||
void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
|
||||
if (p) {
|
||||
*p = (void *)(intptr_t(*p) + intptr_t(1));
|
||||
}
|
||||
else {
|
||||
BLI_edgehash_insert(edgehash, v1, v2, (void *)intptr_t(1));
|
||||
}
|
||||
edgehash.add_or_modify(
|
||||
{v1, v2}, [](int *value) { *value = 1; }, [](int *value) { (*value)++; });
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(BLI_edgehash_len(edgehash), poly_num + (poly_num - 3));
|
||||
EXPECT_EQ(edgehash.size(), poly_num + (poly_num - 3));
|
||||
|
||||
for (i = 0; i < poly_num; i++) {
|
||||
const uint v1 = i;
|
||||
const uint v2 = (i + 1) % poly_num;
|
||||
void **p = BLI_edgehash_lookup_p(edgehash, v1, v2);
|
||||
EXPECT_NE((void *)p, nullptr);
|
||||
EXPECT_EQ(intptr_t(*p), 1);
|
||||
EXPECT_TRUE(edgehash.contains({v1, v2}));
|
||||
EXPECT_EQ(edgehash.lookup({v1, v2}), 1);
|
||||
}
|
||||
|
||||
for (ehi = BLI_edgehashIterator_new(edgehash), i = 0; BLI_edgehashIterator_isDone(ehi) == false;
|
||||
BLI_edgehashIterator_step(ehi), i++)
|
||||
{
|
||||
void **p = BLI_edgehashIterator_getValue_p(ehi);
|
||||
EXPECT_TRUE(ELEM(intptr_t(*p), 1, 2));
|
||||
for (const int value : edgehash.values()) {
|
||||
EXPECT_TRUE(ELEM(value, 1, 2));
|
||||
}
|
||||
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
BLI_edgehash_free(edgehash, nullptr);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -11,7 +11,8 @@
|
||||
/* debug builds only */
|
||||
#ifdef DEBUG
|
||||
|
||||
# include "BLI_edgehash.h"
|
||||
# include "BLI_map.hh"
|
||||
# include "BLI_ordered_edge.hh"
|
||||
# include "BLI_utildefines.h"
|
||||
|
||||
# include "bmesh.h"
|
||||
@@ -37,7 +38,8 @@
|
||||
|
||||
bool BM_mesh_validate(BMesh *bm)
|
||||
{
|
||||
EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, bm->totedge);
|
||||
blender::Map<blender::OrderedEdge, BMEdge *> edge_hash;
|
||||
edge_hash.reserve(bm->totedge);
|
||||
int errtot;
|
||||
|
||||
BMIter iter;
|
||||
@@ -70,21 +72,17 @@ bool BM_mesh_validate(BMesh *bm)
|
||||
|
||||
/* check edges */
|
||||
BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
|
||||
void **val_p;
|
||||
|
||||
if (e->v1 == e->v2) {
|
||||
ERRMSG("edge %d: duplicate index: %d", i, BM_elem_index_get(e->v1));
|
||||
}
|
||||
|
||||
/* build edgehash at the same time */
|
||||
if (BLI_edgehash_ensure_p(
|
||||
edge_hash, BM_elem_index_get(e->v1), BM_elem_index_get(e->v2), &val_p)) {
|
||||
BMEdge *e_other = static_cast<BMEdge *>(*val_p);
|
||||
ERRMSG("edge %d, %d: are duplicates", i, BM_elem_index_get(e_other));
|
||||
}
|
||||
else {
|
||||
*val_p = e;
|
||||
}
|
||||
edge_hash.add_or_modify(
|
||||
{BM_elem_index_get(e->v1), BM_elem_index_get(e->v2)},
|
||||
[&](BMEdge **value) { *value = e; },
|
||||
[&](BMEdge **value) {
|
||||
ERRMSG("edge %d, %d: are duplicates", i, BM_elem_index_get(*value));
|
||||
});
|
||||
}
|
||||
|
||||
/* edge radial structure */
|
||||
@@ -192,8 +190,6 @@ bool BM_mesh_validate(BMesh *bm)
|
||||
} while ((l_iter = l_iter->next) != l_first);
|
||||
}
|
||||
|
||||
BLI_edgehash_free(edge_hash, nullptr);
|
||||
|
||||
const bool is_valid = (errtot == 0);
|
||||
ERRMSG("Finished - errors %d", errtot);
|
||||
return is_valid;
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
#include "BLI_bitmap.h"
|
||||
#include "BLI_buffer.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_map.hh"
|
||||
|
||||
@@ -6,7 +6,8 @@
|
||||
* \ingroup draw
|
||||
*/
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
@@ -24,7 +25,7 @@ namespace blender::draw {
|
||||
|
||||
struct MeshExtract_LineAdjacency_Data {
|
||||
GPUIndexBufBuilder elb;
|
||||
EdgeHash *eh;
|
||||
Map<OrderedEdge, int> *eh;
|
||||
bool is_manifold;
|
||||
/* Array to convert vert index to any loop index of this vert. */
|
||||
uint *vert_to_loop;
|
||||
@@ -38,7 +39,8 @@ static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data,
|
||||
data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * vert_len, __func__));
|
||||
|
||||
GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, loop_len);
|
||||
data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len);
|
||||
data->eh = new Map<OrderedEdge, int>();
|
||||
data->eh->reserve(tess_edge_len);
|
||||
data->is_manifold = true;
|
||||
}
|
||||
|
||||
@@ -66,34 +68,41 @@ BLI_INLINE void lines_adjacency_triangle(
|
||||
SHIFT3(uint, l3, l2, l1);
|
||||
|
||||
bool inv_indices = (v2 > v3);
|
||||
void **pval;
|
||||
bool value_is_init = BLI_edgehash_ensure_p(data->eh, v2, v3, &pval);
|
||||
int v_data = POINTER_AS_INT(*pval);
|
||||
if (!value_is_init || v_data == NO_EDGE) {
|
||||
/* Save the winding order inside the sign bit. Because the
|
||||
* Edge-hash sort the keys and we need to compare winding later. */
|
||||
int value = int(l1) + 1; /* 0 cannot be signed so add one. */
|
||||
*pval = POINTER_FROM_INT((inv_indices) ? -value : value);
|
||||
/* Store loop indices for remaining non-manifold edges. */
|
||||
data->vert_to_loop[v2] = l2;
|
||||
data->vert_to_loop[v3] = l3;
|
||||
}
|
||||
else {
|
||||
/* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
|
||||
*pval = POINTER_FROM_INT(NO_EDGE);
|
||||
bool inv_opposite = (v_data < 0);
|
||||
uint l_opposite = uint(abs(v_data)) - 1;
|
||||
/* TODO: Make this part thread-safe. */
|
||||
if (inv_opposite == inv_indices) {
|
||||
/* Don't share edge if triangles have non matching winding. */
|
||||
GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1);
|
||||
GPU_indexbuf_add_line_adj_verts(elb, l_opposite, l2, l3, l_opposite);
|
||||
data->is_manifold = false;
|
||||
}
|
||||
else {
|
||||
GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l_opposite);
|
||||
}
|
||||
}
|
||||
data->eh->add_or_modify(
|
||||
{v2, v3},
|
||||
[&](int *value) {
|
||||
int new_value = int(l1) + 1; /* 0 cannot be signed so add one. */
|
||||
*value = inv_indices ? -new_value : new_value;
|
||||
/* Store loop indices for remaining non-manifold edges. */
|
||||
data->vert_to_loop[v2] = l2;
|
||||
data->vert_to_loop[v3] = l3;
|
||||
},
|
||||
[&](int *value) {
|
||||
int v_data = *value;
|
||||
if (v_data == NO_EDGE) {
|
||||
int new_value = int(l1) + 1; /* 0 cannot be signed so add one. */
|
||||
*value = inv_indices ? -new_value : new_value;
|
||||
/* Store loop indices for remaining non-manifold edges. */
|
||||
data->vert_to_loop[v2] = l2;
|
||||
data->vert_to_loop[v3] = l3;
|
||||
}
|
||||
else {
|
||||
/* HACK Tag as not used. Prevent overhead of BLI_edgehash_remove. */
|
||||
*value = NO_EDGE;
|
||||
bool inv_opposite = (v_data < 0);
|
||||
uint l_opposite = uint(abs(v_data)) - 1;
|
||||
/* TODO: Make this part thread-safe. */
|
||||
if (inv_opposite == inv_indices) {
|
||||
/* Don't share edge if triangles have non matching winding. */
|
||||
GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l1);
|
||||
GPU_indexbuf_add_line_adj_verts(elb, l_opposite, l2, l3, l_opposite);
|
||||
data->is_manifold = false;
|
||||
}
|
||||
else {
|
||||
GPU_indexbuf_add_line_adj_verts(elb, l1, l2, l3, l_opposite);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,24 +151,25 @@ static void extract_lines_adjacency_finish(const MeshRenderData & /*mr*/,
|
||||
GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf);
|
||||
MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data);
|
||||
/* Create edges for remaining non manifold edges. */
|
||||
EdgeHashIterator *ehi = BLI_edgehashIterator_new(data->eh);
|
||||
for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
|
||||
int v2, v3, l1, l2, l3;
|
||||
int v_data = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
|
||||
if (v_data != NO_EDGE) {
|
||||
BLI_edgehashIterator_getKey(ehi, &v2, &v3);
|
||||
l1 = uint(abs(v_data)) - 1;
|
||||
if (v_data < 0) { /* `inv_opposite`. */
|
||||
std::swap(v2, v3);
|
||||
}
|
||||
l2 = data->vert_to_loop[v2];
|
||||
l3 = data->vert_to_loop[v3];
|
||||
GPU_indexbuf_add_line_adj_verts(&data->elb, l1, l2, l3, l1);
|
||||
data->is_manifold = false;
|
||||
for (const auto item : data->eh->items()) {
|
||||
int v_data = item.value;
|
||||
if (v_data == NO_EDGE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int v2 = item.key.v_low;
|
||||
int v3 = item.key.v_high;
|
||||
|
||||
int l1 = uint(abs(v_data)) - 1;
|
||||
if (v_data < 0) { /* `inv_opposite`. */
|
||||
std::swap(v2, v3);
|
||||
}
|
||||
int l2 = data->vert_to_loop[v2];
|
||||
int l3 = data->vert_to_loop[v3];
|
||||
GPU_indexbuf_add_line_adj_verts(&data->elb, l1, l2, l3, l1);
|
||||
data->is_manifold = false;
|
||||
}
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
BLI_edgehash_free(data->eh, nullptr);
|
||||
delete data->eh;
|
||||
|
||||
cache.is_manifold = data->is_manifold;
|
||||
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_jitter_2d.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
|
||||
#include "BKE_bvhutils.h"
|
||||
#include "BKE_editmesh_bvh.h"
|
||||
@@ -534,7 +534,8 @@ static void statvis_calc_sharp(const MeshRenderData &mr, float *r_sharp)
|
||||
else {
|
||||
/* first assign float values to verts */
|
||||
|
||||
EdgeHash *eh = BLI_edgehash_new_ex(__func__, mr.edge_len);
|
||||
Map<OrderedEdge, int> eh;
|
||||
eh.reserve(mr.edge_len);
|
||||
|
||||
for (int face_index = 0; face_index < mr.face_len; face_index++) {
|
||||
const IndexRange face = mr.faces[face_index];
|
||||
@@ -542,28 +543,28 @@ static void statvis_calc_sharp(const MeshRenderData &mr, float *r_sharp)
|
||||
const int vert_curr = mr.corner_verts[face.start() + (i + 0) % face.size()];
|
||||
const int vert_next = mr.corner_verts[face.start() + (i + 1) % face.size()];
|
||||
float angle;
|
||||
void **pval;
|
||||
bool value_is_init = BLI_edgehash_ensure_p(eh, vert_curr, vert_next, &pval);
|
||||
if (!value_is_init) {
|
||||
*pval = (void *)&mr.face_normals[face_index];
|
||||
/* non-manifold edge, yet... */
|
||||
continue;
|
||||
}
|
||||
if (*pval != nullptr) {
|
||||
const float *f1_no = mr.face_normals[face_index];
|
||||
const float *f2_no = static_cast<const float *>(*pval);
|
||||
angle = angle_normalized_v3v3(f1_no, f2_no);
|
||||
angle = is_edge_convex_v3(
|
||||
mr.vert_positions[vert_curr], mr.vert_positions[vert_next], f1_no, f2_no) ?
|
||||
angle :
|
||||
-angle;
|
||||
/* Tag as manifold. */
|
||||
*pval = nullptr;
|
||||
}
|
||||
else {
|
||||
/* non-manifold edge */
|
||||
angle = DEG2RADF(90.0f);
|
||||
}
|
||||
eh.add_or_modify(
|
||||
{vert_curr, vert_next},
|
||||
[&](int *value) { *value = face_index; },
|
||||
[&](int *value) {
|
||||
const int other_face_index = *value;
|
||||
if (other_face_index == -1) {
|
||||
/* non-manifold edge */
|
||||
angle = DEG2RADF(90.0f);
|
||||
return;
|
||||
}
|
||||
const float *f1_no = mr.face_normals[face_index];
|
||||
const float *f2_no = mr.face_normals[other_face_index];
|
||||
angle = angle_normalized_v3v3(f1_no, f2_no);
|
||||
angle = is_edge_convex_v3(mr.vert_positions[vert_curr],
|
||||
mr.vert_positions[vert_next],
|
||||
f1_no,
|
||||
f2_no) ?
|
||||
angle :
|
||||
-angle;
|
||||
/* Tag as manifold. */
|
||||
*value = -1;
|
||||
});
|
||||
float *col1 = &vert_angles[vert_curr];
|
||||
float *col2 = &vert_angles[vert_next];
|
||||
*col1 = max_ff(*col1, angle);
|
||||
@@ -571,20 +572,13 @@ static void statvis_calc_sharp(const MeshRenderData &mr, float *r_sharp)
|
||||
}
|
||||
}
|
||||
/* Remaining non manifold edges. */
|
||||
EdgeHashIterator *ehi = BLI_edgehashIterator_new(eh);
|
||||
for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
|
||||
if (BLI_edgehashIterator_getValue(ehi) != nullptr) {
|
||||
int v1, v2;
|
||||
const float angle = DEG2RADF(90.0f);
|
||||
BLI_edgehashIterator_getKey(ehi, &v1, &v2);
|
||||
float *col1 = &vert_angles[v1];
|
||||
float *col2 = &vert_angles[v2];
|
||||
*col1 = max_ff(*col1, angle);
|
||||
*col2 = max_ff(*col2, angle);
|
||||
}
|
||||
for (const OrderedEdge &edge : eh.keys()) {
|
||||
const float angle = DEG2RADF(90.0f);
|
||||
float *col1 = &vert_angles[edge.v_low];
|
||||
float *col2 = &vert_angles[edge.v_high];
|
||||
*col1 = max_ff(*col1, angle);
|
||||
*col2 = max_ff(*col2, angle);
|
||||
}
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
BLI_edgehash_free(eh, nullptr);
|
||||
|
||||
for (int l_index = 0; l_index < mr.loop_len; l_index++) {
|
||||
const int vert = mr.corner_verts[l_index];
|
||||
|
||||
@@ -14,12 +14,13 @@
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_scene_types.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_memarena.h"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
#include "BLI_string.h"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
@@ -67,7 +68,7 @@ struct LaplacianSystem {
|
||||
int storeweights; /* store cotangent weights in fweights */
|
||||
bool variablesdone; /* variables set in linear system */
|
||||
|
||||
EdgeHash *edgehash; /* edge hash for construction */
|
||||
blender::Map<blender::OrderedEdge, int> edgehash; /* edge hash for construction */
|
||||
|
||||
struct HeatWeighting {
|
||||
const MLoopTri *mlooptri;
|
||||
@@ -100,21 +101,19 @@ struct LaplacianSystem {
|
||||
* vertex and adjacent faces, since we don't store this adjacency. Also, the
|
||||
* formulas are tweaked a bit to work for non-manifold meshes. */
|
||||
|
||||
static void laplacian_increase_edge_count(EdgeHash *edgehash, int v1, int v2)
|
||||
static void laplacian_increase_edge_count(blender::Map<blender::OrderedEdge, int> &edgehash,
|
||||
int v1,
|
||||
int v2)
|
||||
{
|
||||
void **p;
|
||||
|
||||
if (BLI_edgehash_ensure_p(edgehash, v1, v2, &p)) {
|
||||
*p = (void *)(intptr_t(*p) + intptr_t(1));
|
||||
}
|
||||
else {
|
||||
*p = (void *)intptr_t(1);
|
||||
}
|
||||
edgehash.add_or_modify(
|
||||
{v1, v2}, [](int *value) { *value = 1; }, [](int *value) { (*value)++; });
|
||||
}
|
||||
|
||||
static int laplacian_edge_count(EdgeHash *edgehash, int v1, int v2)
|
||||
static int laplacian_edge_count(const blender::Map<blender::OrderedEdge, int> &edgehash,
|
||||
int v1,
|
||||
int v2)
|
||||
{
|
||||
return int(intptr_t(BLI_edgehash_lookup(edgehash, v1, v2)));
|
||||
return edgehash.lookup({v1, v2});
|
||||
}
|
||||
|
||||
static void laplacian_triangle_area(LaplacianSystem *sys, int i1, int i2, int i3)
|
||||
@@ -253,8 +252,7 @@ static void laplacian_system_construct_end(LaplacianSystem *sys)
|
||||
sys->varea = static_cast<float *>(
|
||||
MEM_callocN(sizeof(float) * verts_num, "LaplacianSystemVarea"));
|
||||
|
||||
sys->edgehash = BLI_edgehash_new_ex(__func__,
|
||||
BLI_EDGEHASH_SIZE_GUESS_FROM_FACES(sys->faces_num));
|
||||
sys->edgehash.reserve(sys->faces_num);
|
||||
for (a = 0, face = sys->faces; a < sys->faces_num; a++, face++) {
|
||||
laplacian_increase_edge_count(sys->edgehash, (*face)[0], (*face)[1]);
|
||||
laplacian_increase_edge_count(sys->edgehash, (*face)[1], (*face)[2]);
|
||||
@@ -296,9 +294,6 @@ static void laplacian_system_construct_end(LaplacianSystem *sys)
|
||||
sys->faces = nullptr;
|
||||
|
||||
MEM_SAFE_FREE(sys->varea);
|
||||
|
||||
BLI_edgehash_free(sys->edgehash, nullptr);
|
||||
sys->edgehash = nullptr;
|
||||
}
|
||||
|
||||
static void laplacian_system_delete(LaplacianSystem *sys)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_gsqueue.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
@@ -154,7 +153,7 @@ static bool cloth_brush_sim_has_length_constraint(SculptClothSimulation *cloth_s
|
||||
const int v1,
|
||||
const int v2)
|
||||
{
|
||||
return BLI_edgeset_haskey(cloth_sim->created_length_constraints, v1, v2);
|
||||
return cloth_sim->created_length_constraints.contains({v1, v2});
|
||||
}
|
||||
|
||||
static void cloth_brush_reallocate_constraints(SculptClothSimulation *cloth_sim)
|
||||
@@ -207,7 +206,7 @@ static void cloth_brush_add_length_constraint(SculptSession *ss,
|
||||
cloth_brush_reallocate_constraints(cloth_sim);
|
||||
|
||||
/* Add the constraint to the #GSet to avoid creating it again. */
|
||||
BLI_edgeset_add(cloth_sim->created_length_constraints, v1, v2);
|
||||
cloth_sim->created_length_constraints.add({v1, v2});
|
||||
}
|
||||
|
||||
static void cloth_brush_add_softbody_constraint(SculptClothSimulation *cloth_sim,
|
||||
@@ -1011,7 +1010,7 @@ SculptClothSimulation *SCULPT_cloth_brush_simulation_create(Object *ob,
|
||||
const int totverts = SCULPT_vertex_count_get(ss);
|
||||
SculptClothSimulation *cloth_sim;
|
||||
|
||||
cloth_sim = MEM_cnew<SculptClothSimulation>(__func__);
|
||||
cloth_sim = MEM_new<SculptClothSimulation>(__func__);
|
||||
|
||||
cloth_sim->length_constraints = MEM_cnew_array<SculptClothLengthConstraint>(
|
||||
CLOTH_LENGTH_CONSTRAINTS_BLOCK, __func__);
|
||||
@@ -1065,14 +1064,14 @@ void SCULPT_cloth_brush_ensure_nodes_constraints(
|
||||
/* Currently all constrains are added to the same global array which can't be accessed from
|
||||
* different threads. */
|
||||
|
||||
cloth_sim->created_length_constraints = BLI_edgeset_new("created length constraints");
|
||||
cloth_sim->created_length_constraints.clear();
|
||||
|
||||
for (const int i : nodes.index_range()) {
|
||||
do_cloth_brush_build_constraints_task(
|
||||
ob, brush, cloth_sim, initial_location, radius, nodes[i]);
|
||||
}
|
||||
|
||||
BLI_edgeset_free(cloth_sim->created_length_constraints);
|
||||
cloth_sim->created_length_constraints.clear_and_shrink();
|
||||
}
|
||||
|
||||
void SCULPT_cloth_brush_simulation_init(SculptSession *ss, SculptClothSimulation *cloth_sim)
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "MOD_gpencil_legacy_lineart.h"
|
||||
#include "MOD_lineart.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_linklist.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_geom.h"
|
||||
|
||||
@@ -22,10 +22,10 @@
|
||||
#include "DNA_object_types.h"
|
||||
|
||||
#include "BLI_compiler_compat.h"
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_index_range.hh"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_math_geom.h"
|
||||
#include "BLI_ordered_edge.hh"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
@@ -994,37 +994,26 @@ static void read_edge_creases(Mesh *mesh,
|
||||
}
|
||||
|
||||
MutableSpan<int2> edges = mesh->edges_for_write();
|
||||
EdgeHash *edge_hash = BLI_edgehash_new_ex(__func__, edges.size());
|
||||
Map<OrderedEdge, int> edge_hash;
|
||||
edge_hash.reserve(edges.size());
|
||||
|
||||
float *creases = static_cast<float *>(CustomData_add_layer_named(
|
||||
&mesh->edge_data, CD_PROP_FLOAT, CD_SET_DEFAULT, edges.size(), "crease_edge"));
|
||||
|
||||
for (const int i : edges.index_range()) {
|
||||
int2 &edge = edges[i];
|
||||
BLI_edgehash_insert(edge_hash, edge[0], edge[1], &edge);
|
||||
edge_hash.add(edges[i], i);
|
||||
}
|
||||
|
||||
for (int i = 0, s = 0, e = indices->size(); i < e; i += 2, s++) {
|
||||
int v1 = (*indices)[i];
|
||||
int v2 = (*indices)[i + 1];
|
||||
|
||||
if (v2 < v1) {
|
||||
/* It appears to be common to store edges with the smallest index first, in which case this
|
||||
* prevents us from doing the second search below. */
|
||||
std::swap(v1, v2);
|
||||
const int *index = edge_hash.lookup_ptr({v1, v2});
|
||||
if (!index) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int2 *edge = static_cast<int2 *>(BLI_edgehash_lookup(edge_hash, v1, v2));
|
||||
if (edge == nullptr) {
|
||||
edge = static_cast<int2 *>(BLI_edgehash_lookup(edge_hash, v2, v1));
|
||||
}
|
||||
|
||||
if (edge) {
|
||||
creases[edge - edges.data()] = unit_float_to_uchar_clamp((*sharpnesses)[s]);
|
||||
}
|
||||
creases[*index] = unit_float_to_uchar_clamp((*sharpnesses)[s]);
|
||||
}
|
||||
|
||||
BLI_edgehash_free(edge_hash, nullptr);
|
||||
}
|
||||
|
||||
/* ************************************************************************** */
|
||||
|
||||
@@ -27,7 +27,6 @@
|
||||
#include "BKE_mesh.hh"
|
||||
#include "BKE_object.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_string.h"
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#include "ArmatureImporter.h"
|
||||
#include "collada_utils.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
|
||||
#include "DNA_material_types.h"
|
||||
|
||||
@@ -10,12 +10,12 @@
|
||||
|
||||
#include "BLI_utildefines.h"
|
||||
|
||||
#include "BLI_edgehash.h"
|
||||
#include "BLI_kdtree.h"
|
||||
#include "BLI_math_matrix.h"
|
||||
#include "BLI_math_rotation.h"
|
||||
#include "BLI_math_vector.h"
|
||||
#include "BLI_rand.h"
|
||||
#include "BLI_vector_set.hh"
|
||||
|
||||
#include "BLT_translation.h"
|
||||
|
||||
@@ -208,9 +208,9 @@ static void createFacepa(ExplodeModifierData *emd, ParticleSystemModifierData *p
|
||||
BLI_rng_free(rng);
|
||||
}
|
||||
|
||||
static int edgecut_get(EdgeHash *edgehash, uint v1, uint v2)
|
||||
static int edgecut_get(const blender::VectorSet<blender::OrderedEdge> &edgehash, uint v1, uint v2)
|
||||
{
|
||||
return POINTER_AS_INT(BLI_edgehash_lookup(edgehash, v1, v2));
|
||||
return edgehash.index_of({int(v1), int(v2)});
|
||||
}
|
||||
|
||||
static const short add_faces[24] = {
|
||||
@@ -249,7 +249,7 @@ static void remap_faces_3_6_9_12(Mesh *mesh,
|
||||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
EdgeHash *eh,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
@@ -319,7 +319,7 @@ static void remap_faces_5_10(Mesh *mesh,
|
||||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
EdgeHash *eh,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
@@ -377,7 +377,7 @@ static void remap_faces_15(Mesh *mesh,
|
||||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
EdgeHash *eh,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
@@ -463,7 +463,7 @@ static void remap_faces_7_11_13_14(Mesh *mesh,
|
||||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
EdgeHash *eh,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
@@ -534,7 +534,7 @@ static void remap_faces_19_21_22(Mesh *mesh,
|
||||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
EdgeHash *eh,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
@@ -590,7 +590,7 @@ static void remap_faces_23(Mesh *mesh,
|
||||
int *facepa,
|
||||
const int *vertpa,
|
||||
int i,
|
||||
EdgeHash *eh,
|
||||
const blender::VectorSet<blender::OrderedEdge> &eh,
|
||||
int cur,
|
||||
int v1,
|
||||
int v2,
|
||||
@@ -659,21 +659,18 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
||||
MFace *mface = static_cast<MFace *>(
|
||||
CustomData_get_layer_for_write(&mesh->fdata_legacy, CD_MFACE, mesh->totface_legacy));
|
||||
float *dupve;
|
||||
EdgeHash *edgehash;
|
||||
EdgeHashIterator *ehi;
|
||||
int totvert = mesh->totvert;
|
||||
int totface = mesh->totface_legacy;
|
||||
|
||||
int *facesplit = static_cast<int *>(MEM_calloc_arrayN(totface, sizeof(int), __func__));
|
||||
int *vertpa = static_cast<int *>(MEM_calloc_arrayN(totvert, sizeof(int), __func__));
|
||||
int *facepa = emd->facepa;
|
||||
int *fs, totesplit = 0, totfsplit = 0, curdupface = 0;
|
||||
int i, v1, v2, v3, v4, esplit, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */
|
||||
uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */
|
||||
int *fs, totfsplit = 0, curdupface = 0;
|
||||
int i, v1, v2, v3, v4, v[4] = {0, 0, 0, 0}, /* To quite gcc barking... */
|
||||
uv[4] = {0, 0, 0, 0}; /* To quite gcc barking... */
|
||||
int layers_num;
|
||||
int ed_v1, ed_v2;
|
||||
|
||||
edgehash = BLI_edgehash_new(__func__);
|
||||
blender::VectorSet<blender::OrderedEdge> edgehash;
|
||||
|
||||
/* recreate vertpa from facepa calculation */
|
||||
for (i = 0, mf = mface; i < totface; i++, mf++) {
|
||||
@@ -692,12 +689,12 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
||||
v3 = vertpa[mf->v3];
|
||||
|
||||
if (v1 != v2) {
|
||||
BLI_edgehash_reinsert(edgehash, mf->v1, mf->v2, nullptr);
|
||||
edgehash.add({mf->v1, mf->v2});
|
||||
(*fs) |= 1;
|
||||
}
|
||||
|
||||
if (v2 != v3) {
|
||||
BLI_edgehash_reinsert(edgehash, mf->v2, mf->v3, nullptr);
|
||||
edgehash.add({mf->v2, mf->v3});
|
||||
(*fs) |= 2;
|
||||
}
|
||||
|
||||
@@ -705,38 +702,31 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
||||
v4 = vertpa[mf->v4];
|
||||
|
||||
if (v3 != v4) {
|
||||
BLI_edgehash_reinsert(edgehash, mf->v3, mf->v4, nullptr);
|
||||
edgehash.add({mf->v3, mf->v4});
|
||||
(*fs) |= 4;
|
||||
}
|
||||
|
||||
if (v1 != v4) {
|
||||
BLI_edgehash_reinsert(edgehash, mf->v1, mf->v4, nullptr);
|
||||
edgehash.add({mf->v1, mf->v4});
|
||||
(*fs) |= 8;
|
||||
}
|
||||
|
||||
/* mark center vertex as a fake edge split */
|
||||
if (*fs == 15) {
|
||||
BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, nullptr);
|
||||
edgehash.add({mf->v1, mf->v3});
|
||||
}
|
||||
}
|
||||
else {
|
||||
(*fs) |= 16; /* mark face as tri */
|
||||
|
||||
if (v1 != v3) {
|
||||
BLI_edgehash_reinsert(edgehash, mf->v1, mf->v3, nullptr);
|
||||
edgehash.add({mf->v1, mf->v3});
|
||||
(*fs) |= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* count splits & create indexes for new verts */
|
||||
ehi = BLI_edgehashIterator_new(edgehash);
|
||||
totesplit = totvert;
|
||||
for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
|
||||
BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totesplit));
|
||||
totesplit++;
|
||||
}
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
|
||||
/* count new faces due to splitting */
|
||||
for (i = 0, fs = facesplit; i < totface; i++, fs++) {
|
||||
@@ -744,7 +734,7 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
||||
}
|
||||
|
||||
split_m = BKE_mesh_new_nomain_from_template_ex(
|
||||
mesh, totesplit, 0, totface + totfsplit, 0, 0, CD_MASK_EVERYTHING);
|
||||
mesh, totvert + edgehash.size(), 0, totface + totfsplit, 0, 0, CD_MASK_EVERYTHING);
|
||||
|
||||
layers_num = CustomData_number_of_layers(&split_m->fdata_legacy, CD_MTFACE);
|
||||
|
||||
@@ -767,10 +757,9 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
||||
emd->facepa = facepa;
|
||||
|
||||
/* create new verts */
|
||||
ehi = BLI_edgehashIterator_new(edgehash);
|
||||
for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
|
||||
BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2);
|
||||
esplit = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
|
||||
for (const int esplit : edgehash.index_range()) {
|
||||
const int ed_v1 = edgehash[esplit].v_low;
|
||||
const int ed_v2 = edgehash[esplit].v_high;
|
||||
|
||||
CustomData_copy_data(&split_m->vert_data, &split_m->vert_data, ed_v2, esplit, 1);
|
||||
|
||||
@@ -779,7 +768,6 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
||||
|
||||
mid_v3_v3v3(dupve, dupve, split_m_positions[ed_v1]);
|
||||
}
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
|
||||
/* create new faces */
|
||||
curdupface = 0; //=totface;
|
||||
@@ -897,7 +885,6 @@ static Mesh *cutEdges(ExplodeModifierData *emd, Mesh *mesh)
|
||||
mf, &split_m->fdata_legacy, i, ((mf->flag & ME_FACE_SEL) ? 4 : 3));
|
||||
}
|
||||
|
||||
BLI_edgehash_free(edgehash, nullptr);
|
||||
MEM_freeN(facesplit);
|
||||
MEM_freeN(vertpa);
|
||||
|
||||
@@ -919,16 +906,14 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
||||
ParticleSimulationData sim = {nullptr};
|
||||
ParticleData *pa = nullptr, *pars = psmd->psys->particles;
|
||||
ParticleKey state, birth;
|
||||
EdgeHash *vertpahash;
|
||||
EdgeHashIterator *ehi;
|
||||
float *vertco = nullptr, imat[4][4];
|
||||
float rot[4];
|
||||
float ctime;
|
||||
// float timestep;
|
||||
const int *facepa = emd->facepa;
|
||||
int totdup = 0, totvert = 0, totface = 0, totpart = 0, delface = 0;
|
||||
int i, v, u;
|
||||
int ed_v1, ed_v2, mindex = 0;
|
||||
int totvert = 0, totface = 0, totpart = 0, delface = 0;
|
||||
int i, u;
|
||||
uint mindex = 0;
|
||||
|
||||
totface = mesh->totface_legacy;
|
||||
totvert = mesh->totvert;
|
||||
@@ -947,7 +932,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
||||
ctime = BKE_scene_ctime_get(scene);
|
||||
|
||||
/* hash table for vertex <-> particle relations */
|
||||
vertpahash = BLI_edgehash_new(__func__);
|
||||
blender::VectorSet<blender::OrderedEdge> vertpahash;
|
||||
|
||||
for (i = 0; i < totface; i++) {
|
||||
if (facepa[i] != totpart) {
|
||||
@@ -965,8 +950,7 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
||||
pa = nullptr;
|
||||
}
|
||||
|
||||
/* do mindex + totvert to ensure the vertex index to be the first
|
||||
* with BLI_edgehashIterator_getKey */
|
||||
/* do mindex + totvert to ensure the vertex index to be the first. */
|
||||
if (pa == nullptr || ctime < pa->time) {
|
||||
mindex = totvert + totpart;
|
||||
}
|
||||
@@ -977,25 +961,17 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
||||
mf = &mface[i];
|
||||
|
||||
/* set face vertices to exist in particle group */
|
||||
BLI_edgehash_reinsert(vertpahash, mf->v1, mindex, nullptr);
|
||||
BLI_edgehash_reinsert(vertpahash, mf->v2, mindex, nullptr);
|
||||
BLI_edgehash_reinsert(vertpahash, mf->v3, mindex, nullptr);
|
||||
vertpahash.add({mf->v1, mindex});
|
||||
vertpahash.add({mf->v2, mindex});
|
||||
vertpahash.add({mf->v3, mindex});
|
||||
if (mf->v4) {
|
||||
BLI_edgehash_reinsert(vertpahash, mf->v4, mindex, nullptr);
|
||||
vertpahash.add({mf->v4, mindex});
|
||||
}
|
||||
}
|
||||
|
||||
/* make new vertex indexes & count total vertices after duplication */
|
||||
ehi = BLI_edgehashIterator_new(vertpahash);
|
||||
for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
|
||||
BLI_edgehashIterator_setValue(ehi, POINTER_FROM_INT(totdup));
|
||||
totdup++;
|
||||
}
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
|
||||
/* the final duplicated vertices */
|
||||
explode = BKE_mesh_new_nomain_from_template_ex(
|
||||
mesh, totdup, 0, totface - delface, 0, 0, CD_MASK_EVERYTHING);
|
||||
mesh, vertpahash.size(), 0, totface - delface, 0, 0, CD_MASK_EVERYTHING);
|
||||
|
||||
MTFace *mtface = static_cast<MTFace *>(CustomData_get_layer_named_for_write(
|
||||
&explode->fdata_legacy, CD_MTFACE, emd->uvname, explode->totface_legacy));
|
||||
@@ -1008,14 +984,11 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
||||
const blender::Span<blender::float3> positions = mesh->vert_positions();
|
||||
blender::MutableSpan<blender::float3> explode_positions = explode->vert_positions_for_write();
|
||||
|
||||
/* duplicate & displace vertices */
|
||||
ehi = BLI_edgehashIterator_new(vertpahash);
|
||||
for (; !BLI_edgehashIterator_isDone(ehi); BLI_edgehashIterator_step(ehi)) {
|
||||
|
||||
for (const int v : vertpahash.index_range()) {
|
||||
/* get particle + vertex from hash */
|
||||
BLI_edgehashIterator_getKey(ehi, &ed_v1, &ed_v2);
|
||||
int ed_v1 = vertpahash[v].v_low;
|
||||
int ed_v2 = vertpahash[v].v_high;
|
||||
ed_v2 -= totvert;
|
||||
v = POINTER_AS_INT(BLI_edgehashIterator_getValue(ehi));
|
||||
|
||||
copy_v3_v3(explode_positions[v], positions[ed_v1]);
|
||||
|
||||
@@ -1053,7 +1026,6 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
||||
pa = nullptr;
|
||||
}
|
||||
}
|
||||
BLI_edgehashIterator_free(ehi);
|
||||
|
||||
/* Map new vertices to faces. */
|
||||
MFace *explode_mface = static_cast<MFace *>(
|
||||
@@ -1119,9 +1091,6 @@ static Mesh *explodeMesh(ExplodeModifierData *emd,
|
||||
u++;
|
||||
}
|
||||
|
||||
/* cleanup */
|
||||
BLI_edgehash_free(vertpahash, nullptr);
|
||||
|
||||
/* finalization */
|
||||
BKE_mesh_calc_edges_tessface(explode);
|
||||
BKE_mesh_convert_mfaces_to_mpolys(explode);
|
||||
|
||||
Reference in New Issue
Block a user