Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/bmesh/tools/bmesh_boolean.cc')
-rw-r--r--source/blender/bmesh/tools/bmesh_boolean.cc91
1 files changed, 57 insertions, 34 deletions
diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc
index d2f73dd63ec..39b425a41df 100644
--- a/source/blender/bmesh/tools/bmesh_boolean.cc
+++ b/source/blender/bmesh/tools/bmesh_boolean.cc
@@ -30,8 +30,7 @@
#include "bmesh_boolean.h"
#include "bmesh_edgesplit.h"
-namespace blender {
-namespace meshintersect {
+namespace blender::meshintersect {
#ifdef WITH_GMP
@@ -117,11 +116,24 @@ static bool bmvert_attached_to_wire(const BMVert *bmv)
return BM_vert_is_wire(bmv);
}
+static bool bmvert_attached_to_hidden_face(BMVert *bmv)
+{
+ BMIter iter;
+ for (BMFace *bmf = static_cast<BMFace *>(BM_iter_new(&iter, nullptr, BM_FACES_OF_VERT, bmv));
+ bmf;
+ bmf = static_cast<BMFace *>(BM_iter_step(&iter))) {
+ if (BM_elem_flag_test(bmf, BM_ELEM_HIDDEN)) {
+ return true;
+ }
+ }
+ return false;
+}
+
static bool face_has_verts_in_order(BMesh *bm, BMFace *bmf, const BMVert *v1, const BMVert *v2)
{
BMIter liter;
BMLoop *l = static_cast<BMLoop *>(BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, bmf));
- while (l != NULL) {
+ while (l != nullptr) {
if (l->v == v1 && l->next->v == v2) {
return true;
}
@@ -140,17 +152,19 @@ constexpr uint KEEP_FLAG = (1 << 6);
* Also, the #BM_ELEM_TAG header flag is set for those #BMEdge's that come from intersections
* resulting from the intersection needed by the Boolean operation.
*/
-static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out)
+static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out, bool keep_hidden)
{
bool any_change = false;
m_out.populate_vert();
/* Initially mark all existing verts as "don't keep", except hidden verts
- * and verts attached to wire edges. */
+ * (if keep_hidden is true), and verts attached to wire edges. */
for (int v = 0; v < bm->totvert; ++v) {
BMVert *bmv = BM_vert_at_index(bm, v);
- if (BM_elem_flag_test(bmv, BM_ELEM_HIDDEN) || bmvert_attached_to_wire(bmv)) {
+ if ((keep_hidden &&
+ (BM_elem_flag_test(bmv, BM_ELEM_HIDDEN) || bmvert_attached_to_hidden_face(bmv))) ||
+ bmvert_attached_to_wire(bmv)) {
BM_elem_flag_enable(bmv, KEEP_FLAG);
}
else {
@@ -184,20 +198,21 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out)
for (int i = 0; i < 3; ++i) {
co[i] = static_cast<float>(d_co[i]);
}
- BMVert *bmv = BM_vert_create(bm, co, NULL, BM_CREATE_NOP);
+ BMVert *bmv = BM_vert_create(bm, co, nullptr, BM_CREATE_NOP);
new_bmvs[v] = bmv;
BM_elem_flag_enable(bmv, KEEP_FLAG);
any_change = true;
}
}
- /* Initially mark all existing faces as "don't keep", except hidden faces.
+ /* Initially mark all existing faces as "don't keep", except hidden faces (if keep_hidden).
* Also, save current #BMFace pointers as creating faces will disturb the table. */
Array<BMFace *> old_bmfs(bm->totface);
+ BM_mesh_elem_index_ensure(bm, BM_FACE);
for (int f = 0; f < bm->totface; ++f) {
BMFace *bmf = BM_face_at_index(bm, f);
old_bmfs[f] = bmf;
- if (BM_elem_flag_test(bmf, BM_ELEM_HIDDEN)) {
+ if (keep_hidden && BM_elem_flag_test(bmf, BM_ELEM_HIDDEN)) {
BM_elem_flag_enable(bmf, KEEP_FLAG);
}
else {
@@ -230,7 +245,7 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out)
BMFace *bmf = BM_face_exists(face_bmverts.data(), flen);
/* #BM_face_exists checks if the face exists with the vertices in either order.
* We can only reuse the face if the orientations are the same. */
- if (bmf != NULL && face_has_verts_in_order(bm, bmf, face_bmverts[0], face_bmverts[1])) {
+ if (bmf != nullptr && face_has_verts_in_order(bm, bmf, face_bmverts[0], face_bmverts[1])) {
BM_elem_flag_enable(bmf, KEEP_FLAG);
}
else {
@@ -241,20 +256,20 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out)
orig_face = old_bmfs[orig];
}
else {
- orig_face = NULL;
+ orig_face = nullptr;
}
/* Make or find #BMEdge's. */
for (int i = 0; i < flen; ++i) {
BMVert *bmv1 = face_bmverts[i];
BMVert *bmv2 = face_bmverts[(i + 1) % flen];
BMEdge *bme = BM_edge_exists(bmv1, bmv2);
- if (bme == NULL) {
- BMEdge *orig_edge = NULL;
+ if (bme == nullptr) {
+ BMEdge *orig_edge = nullptr;
if (face.edge_orig[i] != NO_INDEX) {
orig_edge = old_edges[face.edge_orig[i]];
}
bme = BM_edge_create(bm, bmv1, bmv2, orig_edge, BM_CREATE_NOP);
- if (orig_edge != NULL) {
+ if (orig_edge != nullptr) {
BM_elem_select_copy(bm, bme, orig_edge);
}
}
@@ -268,15 +283,15 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out)
}
BMFace *bmf = BM_face_create(
bm, face_bmverts.data(), face_bmedges.data(), flen, orig_face, BM_CREATE_NOP);
- if (orig_face != NULL) {
+ if (orig_face != nullptr) {
BM_elem_select_copy(bm, bmf, orig_face);
}
BM_elem_flag_enable(bmf, KEEP_FLAG);
/* Now do interpolation of loop data (e.g., UV's) using the example face. */
- if (orig_face != NULL) {
+ if (orig_face != nullptr) {
BMIter liter;
BMLoop *l = static_cast<BMLoop *>(BM_iter_new(&liter, bm, BM_LOOPS_OF_FACE, bmf));
- while (l != NULL) {
+ while (l != nullptr) {
BM_loop_interp_from_face(bm, l, orig_face, true, true);
l = static_cast<BMLoop *>(BM_iter_step(&liter));
}
@@ -289,8 +304,8 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out)
/* #BM_ITER_MESH_MUTABLE macro needs type casts for C++, so expand here.
* TODO(howard): make some nice C++ iterators for #BMesh. */
BMIter iter;
- BMFace *bmf = static_cast<BMFace *>(BM_iter_new(&iter, bm, BM_FACES_OF_MESH, NULL));
- while (bmf != NULL) {
+ BMFace *bmf = static_cast<BMFace *>(BM_iter_new(&iter, bm, BM_FACES_OF_MESH, nullptr));
+ while (bmf != nullptr) {
# ifdef DEBUG
iter.count = BM_iter_mesh_count(BM_FACES_OF_MESH, bm);
# endif
@@ -307,8 +322,8 @@ static bool apply_mesh_output_to_bmesh(BMesh *bm, IMesh &m_out)
}
bmf = bmf_next;
}
- BMVert *bmv = static_cast<BMVert *>(BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, NULL));
- while (bmv != NULL) {
+ BMVert *bmv = static_cast<BMVert *>(BM_iter_new(&iter, bm, BM_VERTS_OF_MESH, nullptr));
+ while (bmv != nullptr) {
# ifdef DEBUG
iter.count = BM_iter_mesh_count(BM_VERTS_OF_MESH, bm);
# endif
@@ -331,18 +346,19 @@ static bool bmesh_boolean(BMesh *bm,
const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
+ int nshapes,
const bool use_self,
const bool use_separate_all,
+ const bool keep_hidden,
const BoolOpType boolean_mode)
{
IMeshArena arena;
IMesh m_triangulated;
IMesh m_in = mesh_from_bm(bm, looptris, looptris_tot, &m_triangulated, &arena);
std::function<int(int)> shape_fn;
- int nshapes;
if (use_self && boolean_mode == BoolOpType::None) {
/* Unary knife operation. Want every face where test_fn doesn't return -1. */
- nshapes = 1;
+ BLI_assert(nshapes == 1);
shape_fn = [bm, test_fn, user_data](int f) {
BMFace *bmf = BM_face_at_index(bm, f);
if (test_fn(bmf, user_data) != -1) {
@@ -352,22 +368,18 @@ static bool bmesh_boolean(BMesh *bm,
};
}
else {
- nshapes = 2;
shape_fn = [bm, test_fn, user_data](int f) {
BMFace *bmf = BM_face_at_index(bm, f);
int test_val = test_fn(bmf, user_data);
- if (test_val == 0) {
- return 0;
- }
- if (test_val == 1) {
- return 1;
+ if (test_val >= 0) {
+ return test_val;
}
return -1;
};
}
IMesh m_out = boolean_mesh(
m_in, boolean_mode, nshapes, shape_fn, use_self, &m_triangulated, &arena);
- bool any_change = apply_mesh_output_to_bmesh(bm, m_out);
+ bool any_change = apply_mesh_output_to_bmesh(bm, m_out, keep_hidden);
if (use_separate_all) {
/* We are supposed to separate all faces that are incident on intersection edges. */
BM_mesh_edgesplit(bm, false, true, false);
@@ -377,8 +389,7 @@ static bool bmesh_boolean(BMesh *bm,
#endif // WITH_GMP
-} // namespace meshintersect
-} // namespace blender
+} // namespace blender::meshintersect
extern "C" {
/**
@@ -403,7 +414,9 @@ bool BM_mesh_boolean(BMesh *bm,
const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
+ const int nshapes,
const bool use_self,
+ const bool keep_hidden,
const int boolean_mode)
{
return blender::meshintersect::bmesh_boolean(
@@ -412,8 +425,10 @@ bool BM_mesh_boolean(BMesh *bm,
looptris_tot,
test_fn,
user_data,
+ nshapes,
use_self,
false,
+ keep_hidden,
static_cast<blender::meshintersect::BoolOpType>(boolean_mode));
}
@@ -430,16 +445,20 @@ bool BM_mesh_boolean_knife(BMesh *bm,
const int looptris_tot,
int (*test_fn)(BMFace *f, void *user_data),
void *user_data,
+ const int nshapes,
const bool use_self,
- const bool use_separate_all)
+ const bool use_separate_all,
+ const bool keep_hidden)
{
return blender::meshintersect::bmesh_boolean(bm,
looptris,
looptris_tot,
test_fn,
user_data,
+ nshapes,
use_self,
use_separate_all,
+ keep_hidden,
blender::meshintersect::BoolOpType::None);
}
#else
@@ -448,7 +467,9 @@ bool BM_mesh_boolean(BMesh *UNUSED(bm),
const int UNUSED(looptris_tot),
int (*test_fn)(BMFace *, void *),
void *UNUSED(user_data),
+ const int UNUSED(nshapes),
const bool UNUSED(use_self),
+ const bool UNUSED(keep_hidden),
const int UNUSED(boolean_mode))
{
UNUSED_VARS(looptris, test_fn);
@@ -468,8 +489,10 @@ bool BM_mesh_boolean_knife(BMesh *UNUSED(bm),
const int UNUSED(looptris_tot),
int (*test_fn)(BMFace *, void *),
void *UNUSED(user_data),
+ const int UNUSED(nshapes),
const bool UNUSED(use_self),
- const bool UNUSED(use_separate_all))
+ const bool UNUSED(use_separate_all),
+ const bool UNUSED(keep_hidden))
{
UNUSED_VARS(looptris, test_fn);
return false;