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/editors/mesh/editmesh_rip.c')
-rw-r--r--source/blender/editors/mesh/editmesh_rip.c1811
1 files changed, 900 insertions, 911 deletions
diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c
index 2117c2bb689..42521d04008 100644
--- a/source/blender/editors/mesh/editmesh_rip.c
+++ b/source/blender/editors/mesh/editmesh_rip.c
@@ -46,7 +46,7 @@
#include "bmesh.h"
#include "bmesh_tools.h"
-#include "mesh_intern.h" /* own include */
+#include "mesh_intern.h" /* own include */
/**
* helper to find edge for edge_rip,
@@ -56,30 +56,32 @@
* point and would result in the same distance.
*/
#define INSET_DEFAULT 0.00001f
-static float edbm_rip_edgedist_squared(
- ARegion *ar, float mat[4][4],
- const float co1[3], const float co2[3], const float mvalf[2],
- const float inset)
+static float edbm_rip_edgedist_squared(ARegion *ar,
+ float mat[4][4],
+ const float co1[3],
+ const float co2[3],
+ const float mvalf[2],
+ const float inset)
{
- float vec1[2], vec2[2], dist_sq;
+ float vec1[2], vec2[2], dist_sq;
- ED_view3d_project_float_v2_m4(ar, co1, vec1, mat);
- ED_view3d_project_float_v2_m4(ar, co2, vec2, mat);
+ ED_view3d_project_float_v2_m4(ar, co1, vec1, mat);
+ ED_view3d_project_float_v2_m4(ar, co2, vec2, mat);
- if (inset != 0.0f) {
- const float dist_2d = len_v2v2(vec1, vec2);
- if (dist_2d > FLT_EPSILON) {
- const float dist = inset / dist_2d;
- BLI_assert(isfinite(dist));
- interp_v2_v2v2(vec1, vec1, vec2, dist);
- interp_v2_v2v2(vec2, vec2, vec1, dist);
- }
- }
+ if (inset != 0.0f) {
+ const float dist_2d = len_v2v2(vec1, vec2);
+ if (dist_2d > FLT_EPSILON) {
+ const float dist = inset / dist_2d;
+ BLI_assert(isfinite(dist));
+ interp_v2_v2v2(vec1, vec1, vec2, dist);
+ interp_v2_v2v2(vec2, vec2, vec1, dist);
+ }
+ }
- dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2);
- BLI_assert(isfinite(dist_sq));
+ dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2);
+ BLI_assert(isfinite(dist_sq));
- return dist_sq;
+ return dist_sq;
}
#if 0
@@ -87,83 +89,78 @@ static float edbm_rip_linedist(
ARegion *ar, float mat[4][4],
const float co1[3], const float co2[3], const float mvalf[2])
{
- float vec1[2], vec2[2];
+ float vec1[2], vec2[2];
- ED_view3d_project_float_v2_m4(ar, co1, vec1, mat);
- ED_view3d_project_float_v2_m4(ar, co2, vec2, mat);
+ ED_view3d_project_float_v2_m4(ar, co1, vec1, mat);
+ ED_view3d_project_float_v2_m4(ar, co2, vec2, mat);
- return dist_to_line_v2(mvalf, vec1, vec2);
+ return dist_to_line_v2(mvalf, vec1, vec2);
}
#endif
/* calculaters a point along the loop tangent which can be used to measure against edges */
static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3])
{
- BM_loop_calc_face_tangent(l, l_mid_co);
+ BM_loop_calc_face_tangent(l, l_mid_co);
- /* scale to average of surrounding edge size, only needs to be approx, but should
- * be roughly equivalent to the check below which uses the middle of the edge. */
- mul_v3_fl(l_mid_co, (BM_edge_calc_length(l->e) + BM_edge_calc_length(l->prev->e)) / 2.0f);
+ /* scale to average of surrounding edge size, only needs to be approx, but should
+ * be roughly equivalent to the check below which uses the middle of the edge. */
+ mul_v3_fl(l_mid_co, (BM_edge_calc_length(l->e) + BM_edge_calc_length(l->prev->e)) / 2.0f);
- add_v3_v3(l_mid_co, l->v->co);
+ add_v3_v3(l_mid_co, l->v->co);
}
-
static float edbm_rip_edge_side_measure(
- BMEdge *e, BMLoop *e_l,
- ARegion *ar,
- float projectMat[4][4], const float fmval[2])
+ BMEdge *e, BMLoop *e_l, ARegion *ar, float projectMat[4][4], const float fmval[2])
{
- float cent[3] = {0, 0, 0}, mid[3];
+ float cent[3] = {0, 0, 0}, mid[3];
- float vec[2];
- float fmval_tweak[2];
- float e_v1_co[2], e_v2_co[2];
- float score;
+ float vec[2];
+ float fmval_tweak[2];
+ float e_v1_co[2], e_v2_co[2];
+ float score;
- BMVert *v1_other;
- BMVert *v2_other;
+ BMVert *v1_other;
+ BMVert *v2_other;
- BLI_assert(BM_vert_in_edge(e, e_l->v));
+ BLI_assert(BM_vert_in_edge(e, e_l->v));
- /* method for calculating distance:
- *
- * for each edge: calculate face center, then made a vector
- * from edge midpoint to face center. offset edge midpoint
- * by a small amount along this vector. */
+ /* method for calculating distance:
+ *
+ * for each edge: calculate face center, then made a vector
+ * from edge midpoint to face center. offset edge midpoint
+ * by a small amount along this vector. */
- /* rather then the face center, get the middle of
- * both edge verts connected to this one */
- v1_other = BM_face_other_vert_loop(e_l->f, e->v2, e->v1)->v;
- v2_other = BM_face_other_vert_loop(e_l->f, e->v1, e->v2)->v;
- mid_v3_v3v3(cent, v1_other->co, v2_other->co);
- mid_v3_v3v3(mid, e->v1->co, e->v2->co);
+ /* rather then the face center, get the middle of
+ * both edge verts connected to this one */
+ v1_other = BM_face_other_vert_loop(e_l->f, e->v2, e->v1)->v;
+ v2_other = BM_face_other_vert_loop(e_l->f, e->v1, e->v2)->v;
+ mid_v3_v3v3(cent, v1_other->co, v2_other->co);
+ mid_v3_v3v3(mid, e->v1->co, e->v2->co);
- ED_view3d_project_float_v2_m4(ar, cent, cent, projectMat);
- ED_view3d_project_float_v2_m4(ar, mid, mid, projectMat);
+ ED_view3d_project_float_v2_m4(ar, cent, cent, projectMat);
+ ED_view3d_project_float_v2_m4(ar, mid, mid, projectMat);
- ED_view3d_project_float_v2_m4(ar, e->v1->co, e_v1_co, projectMat);
- ED_view3d_project_float_v2_m4(ar, e->v2->co, e_v2_co, projectMat);
+ ED_view3d_project_float_v2_m4(ar, e->v1->co, e_v1_co, projectMat);
+ ED_view3d_project_float_v2_m4(ar, e->v2->co, e_v2_co, projectMat);
- sub_v2_v2v2(vec, cent, mid);
- normalize_v2_length(vec, 0.01f);
+ sub_v2_v2v2(vec, cent, mid);
+ normalize_v2_length(vec, 0.01f);
- /* rather then adding to both verts, subtract from the mouse */
- sub_v2_v2v2(fmval_tweak, fmval, vec);
+ /* rather then adding to both verts, subtract from the mouse */
+ sub_v2_v2v2(fmval_tweak, fmval, vec);
- score = len_v2v2(e_v1_co, e_v2_co);
+ score = len_v2v2(e_v1_co, e_v2_co);
- if (dist_squared_to_line_segment_v2(fmval_tweak, e_v1_co, e_v2_co) >
- dist_squared_to_line_segment_v2(fmval, e_v1_co, e_v2_co))
- {
- return score;
- }
- else {
- return -score;
- }
+ if (dist_squared_to_line_segment_v2(fmval_tweak, e_v1_co, e_v2_co) >
+ dist_squared_to_line_segment_v2(fmval, e_v1_co, e_v2_co)) {
+ return score;
+ }
+ else {
+ return -score;
+ }
}
-
/* - Advanced selection handling 'ripsel' functions ----- */
/**
@@ -195,195 +192,189 @@ static float edbm_rip_edge_side_measure(
* - campbell.
*/
-
-#define IS_VISIT_POSSIBLE(e) (BM_edge_is_manifold(e) && BM_elem_flag_test(e, BM_ELEM_TAG))
+#define IS_VISIT_POSSIBLE(e) (BM_edge_is_manifold(e) && BM_elem_flag_test(e, BM_ELEM_TAG))
#define IS_VISIT_DONE(e) ((e)->l && (BM_elem_index_get((e)->l) != INVALID_UID))
#define INVALID_UID INT_MIN
/* mark, assign uid and step */
static BMEdge *edbm_ripsel_edge_mark_step(BMVert *v, const int uid)
{
- BMIter iter;
- BMEdge *e;
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) {
- BMLoop *l_a, *l_b;
-
- BM_edge_loop_pair(e, &l_a, &l_b); /* no need to check, we know this will be true */
-
- /* so (IS_VISIT_DONE == true) */
- BM_elem_index_set(l_a, uid); /* set_dirty */
- BM_elem_index_set(l_b, uid); /* set_dirty */
-
- return e;
- }
- }
- return NULL;
+ BMIter iter;
+ BMEdge *e;
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) {
+ BMLoop *l_a, *l_b;
+
+ BM_edge_loop_pair(e, &l_a, &l_b); /* no need to check, we know this will be true */
+
+ /* so (IS_VISIT_DONE == true) */
+ BM_elem_index_set(l_a, uid); /* set_dirty */
+ BM_elem_index_set(l_b, uid); /* set_dirty */
+
+ return e;
+ }
+ }
+ return NULL;
}
typedef struct EdgeLoopPair {
- BMLoop *l_a;
- BMLoop *l_b;
+ BMLoop *l_a;
+ BMLoop *l_b;
} EdgeLoopPair;
static EdgeLoopPair *edbm_ripsel_looptag_helper(BMesh *bm)
{
- BMIter fiter;
- BMIter liter;
-
- BMFace *f;
- BMLoop *l;
-
- int uid_start;
- int uid_end;
- int uid = bm->totedge; /* can start anywhere */
-
- EdgeLoopPair *eloop_pairs = NULL;
- BLI_array_declare(eloop_pairs);
- EdgeLoopPair *lp;
-
- /* initialize loops with dummy invalid index values */
- BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
- BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
- BM_elem_index_set(l, INVALID_UID); /* set_dirty */
- }
- }
- bm->elem_index_dirty |= BM_LOOP;
-
- /* set contiguous loops ordered 'uid' values for walking after split */
- while (true) {
- int tot = 0;
- BMIter eiter;
- BMEdge *e_step;
- BMVert *v_step;
- BMEdge *e;
- BMEdge *e_first;
- BMEdge *e_last;
-
- e_first = NULL;
- BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
- if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) {
- e_first = e;
- break;
- }
- }
-
- if (e_first == NULL) {
- break;
- }
-
- /* initialize */
- e_first = e;
- v_step = e_first->v1;
- e_step = NULL; /* quiet warning, will never remain this value */
-
- uid_start = uid;
- while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) {
- v_step = BM_edge_other_vert((e_step = e), v_step);
- uid++; /* only different line */
- tot++;
- }
-
- /* this edges loops have the highest uid's, store this to walk down later */
- e_last = e_step;
-
- /* always store the highest 'uid' edge for the stride */
- uid_end = uid - 1;
- uid = uid_start - 1;
-
- /* initialize */
- v_step = e_first->v1;
-
- while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) {
- v_step = BM_edge_other_vert((e_step = e), v_step);
- uid--; /* only different line */
- tot++;
- }
-
- /* stride far enough not to _ever_ overlap range */
- uid_start = uid;
- uid = uid_end + bm->totedge;
-
- lp = BLI_array_append_ret(eloop_pairs);
- /* no need to check, we know this will be true */
- BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b);
-
-
- BLI_assert(tot == uid_end - uid_start);
+ BMIter fiter;
+ BMIter liter;
+
+ BMFace *f;
+ BMLoop *l;
+
+ int uid_start;
+ int uid_end;
+ int uid = bm->totedge; /* can start anywhere */
+
+ EdgeLoopPair *eloop_pairs = NULL;
+ BLI_array_declare(eloop_pairs);
+ EdgeLoopPair *lp;
+
+ /* initialize loops with dummy invalid index values */
+ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
+ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
+ BM_elem_index_set(l, INVALID_UID); /* set_dirty */
+ }
+ }
+ bm->elem_index_dirty |= BM_LOOP;
+
+ /* set contiguous loops ordered 'uid' values for walking after split */
+ while (true) {
+ int tot = 0;
+ BMIter eiter;
+ BMEdge *e_step;
+ BMVert *v_step;
+ BMEdge *e;
+ BMEdge *e_first;
+ BMEdge *e_last;
+
+ e_first = NULL;
+ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
+ if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) {
+ e_first = e;
+ break;
+ }
+ }
+
+ if (e_first == NULL) {
+ break;
+ }
+
+ /* initialize */
+ e_first = e;
+ v_step = e_first->v1;
+ e_step = NULL; /* quiet warning, will never remain this value */
+
+ uid_start = uid;
+ while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) {
+ v_step = BM_edge_other_vert((e_step = e), v_step);
+ uid++; /* only different line */
+ tot++;
+ }
+
+ /* this edges loops have the highest uid's, store this to walk down later */
+ e_last = e_step;
+
+ /* always store the highest 'uid' edge for the stride */
+ uid_end = uid - 1;
+ uid = uid_start - 1;
+
+ /* initialize */
+ v_step = e_first->v1;
+
+ while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) {
+ v_step = BM_edge_other_vert((e_step = e), v_step);
+ uid--; /* only different line */
+ tot++;
+ }
+
+ /* stride far enough not to _ever_ overlap range */
+ uid_start = uid;
+ uid = uid_end + bm->totedge;
+
+ lp = BLI_array_append_ret(eloop_pairs);
+ /* no need to check, we know this will be true */
+ BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b);
+
+ BLI_assert(tot == uid_end - uid_start);
#if 0
- printf("%s: found contiguous edge loop of (%d)\n", __func__, uid_end - uid_start);
+ printf("%s: found contiguous edge loop of (%d)\n", __func__, uid_end - uid_start);
#endif
+ }
- }
-
- /* null terminate */
- lp = BLI_array_append_ret(eloop_pairs);
- lp->l_a = lp->l_b = NULL;
+ /* null terminate */
+ lp = BLI_array_append_ret(eloop_pairs);
+ lp->l_a = lp->l_b = NULL;
- return eloop_pairs;
+ return eloop_pairs;
}
-
/* - De-Select the worst rip-edge side -------------------------------- */
-
static BMEdge *edbm_ripsel_edge_uid_step(BMEdge *e_orig, BMVert **v_prev)
{
- BMIter eiter;
- BMEdge *e;
- BMVert *v = BM_edge_other_vert(e_orig, *v_prev);
- const int uid_cmp = BM_elem_index_get(e_orig->l) - 1;
-
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
- if (BM_elem_index_get(e->l) == uid_cmp) {
- *v_prev = v;
- return e;
- }
- }
- return NULL;
+ BMIter eiter;
+ BMEdge *e;
+ BMVert *v = BM_edge_other_vert(e_orig, *v_prev);
+ const int uid_cmp = BM_elem_index_get(e_orig->l) - 1;
+
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_index_get(e->l) == uid_cmp) {
+ *v_prev = v;
+ return e;
+ }
+ }
+ return NULL;
}
static BMVert *edbm_ripsel_edloop_pair_start_vert(BMEdge *e)
{
- /* try step in a direction, if it fails we know do go the other way */
- BMVert *v_test = e->v1;
- return (edbm_ripsel_edge_uid_step(e, &v_test)) ? e->v1 : e->v2;
+ /* try step in a direction, if it fails we know do go the other way */
+ BMVert *v_test = e->v1;
+ return (edbm_ripsel_edge_uid_step(e, &v_test)) ? e->v1 : e->v2;
}
-static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs,
- ARegion *ar, float projectMat[4][4], float fmval[2])
+static void edbm_ripsel_deselect_helper(
+ BMesh *bm, EdgeLoopPair *eloop_pairs, ARegion *ar, float projectMat[4][4], float fmval[2])
{
- EdgeLoopPair *lp;
-
- for (lp = eloop_pairs; lp->l_a; lp++) {
- BMEdge *e;
- BMVert *v_prev;
-
- float score_a = 0.0f;
- float score_b = 0.0f;
-
- e = lp->l_a->e;
- v_prev = edbm_ripsel_edloop_pair_start_vert(e);
- for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
- score_a += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval);
- }
- e = lp->l_b->e;
- v_prev = edbm_ripsel_edloop_pair_start_vert(e);
- for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
- score_b += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval);
- }
-
- e = (score_a > score_b) ? lp->l_a->e : lp->l_b->e;
- v_prev = edbm_ripsel_edloop_pair_start_vert(e);
- for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
- BM_edge_select_set(bm, e, false);
- }
- }
+ EdgeLoopPair *lp;
+
+ for (lp = eloop_pairs; lp->l_a; lp++) {
+ BMEdge *e;
+ BMVert *v_prev;
+
+ float score_a = 0.0f;
+ float score_b = 0.0f;
+
+ e = lp->l_a->e;
+ v_prev = edbm_ripsel_edloop_pair_start_vert(e);
+ for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
+ score_a += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval);
+ }
+ e = lp->l_b->e;
+ v_prev = edbm_ripsel_edloop_pair_start_vert(e);
+ for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
+ score_b += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval);
+ }
+
+ e = (score_a > score_b) ? lp->l_a->e : lp->l_b->e;
+ v_prev = edbm_ripsel_edloop_pair_start_vert(e);
+ for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
+ BM_edge_select_set(bm, e, false);
+ }
+ }
}
/* --- end 'ripsel' selection handling code --- */
-
/* --- face-fill code --- */
/**
* return an un-ordered array of loop pairs
@@ -396,120 +387,121 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs,
*/
typedef struct UnorderedLoopPair {
- BMLoop *l_pair[2];
- char flag;
+ BMLoop *l_pair[2];
+ char flag;
} UnorderedLoopPair;
enum {
- ULP_FLIP_0 = (1 << 0),
- ULP_FLIP_1 = (1 << 1),
+ ULP_FLIP_0 = (1 << 0),
+ ULP_FLIP_1 = (1 << 1),
};
static UnorderedLoopPair *edbm_tagged_loop_pairs_to_fill(BMesh *bm)
{
- BMIter iter;
- BMEdge *e;
-
- unsigned int total_tag = 0;
- /* count tags, could be pre-calculated */
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- total_tag++;
- }
- }
-
- if (total_tag) {
- UnorderedLoopPair *uloop_pairs = MEM_mallocN(total_tag * sizeof(UnorderedLoopPair), __func__);
- UnorderedLoopPair *ulp = uloop_pairs;
-
- BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
- if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
- BMLoop *l1, *l2;
- if (BM_edge_loop_pair(e, &l1, &l2)) {
- BMVert *v_cmp = l1->e->v1;
- ulp->flag = (((l1->v != v_cmp) ? ULP_FLIP_0 : 0) |
- ((l2->v == v_cmp) ? ULP_FLIP_1 : 0));
- }
- else {
- ulp->flag = 0;
- }
- ulp->l_pair[0] = l1;
- ulp->l_pair[1] = l2;
-
- ulp++;
- }
- }
-
- return uloop_pairs;
- }
- else {
- return NULL;
- }
+ BMIter iter;
+ BMEdge *e;
+
+ unsigned int total_tag = 0;
+ /* count tags, could be pre-calculated */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ total_tag++;
+ }
+ }
+
+ if (total_tag) {
+ UnorderedLoopPair *uloop_pairs = MEM_mallocN(total_tag * sizeof(UnorderedLoopPair), __func__);
+ UnorderedLoopPair *ulp = uloop_pairs;
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_TAG)) {
+ BMLoop *l1, *l2;
+ if (BM_edge_loop_pair(e, &l1, &l2)) {
+ BMVert *v_cmp = l1->e->v1;
+ ulp->flag = (((l1->v != v_cmp) ? ULP_FLIP_0 : 0) | ((l2->v == v_cmp) ? ULP_FLIP_1 : 0));
+ }
+ else {
+ ulp->flag = 0;
+ }
+ ulp->l_pair[0] = l1;
+ ulp->l_pair[1] = l2;
+
+ ulp++;
+ }
+ }
+
+ return uloop_pairs;
+ }
+ else {
+ return NULL;
+ }
}
static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *uloop_pairs)
{
- UnorderedLoopPair *ulp;
- unsigned int total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair);
- unsigned int i;
-
- for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) {
- if ((ulp->l_pair[0] && ulp->l_pair[1]) &&
- (ulp->l_pair[0]->e != ulp->l_pair[1]->e))
- {
- /* time has come to make a face! */
- BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e);
- BMFace *f, *f_example = ulp->l_pair[0]->f;
- BMLoop *l_iter;
- BMVert *f_verts[4];
-
- if (v_shared == NULL) {
- /* quad */
- f_verts[0] = ulp->l_pair[0]->e->v1;
- f_verts[1] = ulp->l_pair[1]->e->v1;
- f_verts[2] = ulp->l_pair[1]->e->v2;
- f_verts[3] = ulp->l_pair[0]->e->v2;
-
- if (ulp->flag & ULP_FLIP_0) {
- SWAP(BMVert *, f_verts[0], f_verts[3]);
- }
- if (ulp->flag & ULP_FLIP_1) {
- SWAP(BMVert *, f_verts[1], f_verts[2]);
- }
- }
- else {
- /* tri */
- f_verts[0] = v_shared;
- f_verts[1] = BM_edge_other_vert(ulp->l_pair[0]->e, v_shared);
- f_verts[2] = BM_edge_other_vert(ulp->l_pair[1]->e, v_shared);
- f_verts[3] = NULL;
-
- /* don't use the flip flags */
- if (v_shared == ulp->l_pair[0]->v) {
- SWAP(BMVert *, f_verts[0], f_verts[1]);
- }
- }
-
- /* face should never exist */
- BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3));
-
- f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true);
-
- l_iter = BM_FACE_FIRST_LOOP(f);
-
- if (f_verts[3]) {
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
- }
- else {
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter); l_iter = l_iter->next;
- BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
- }
-
- }
- }
+ UnorderedLoopPair *ulp;
+ unsigned int total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair);
+ unsigned int i;
+
+ for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) {
+ if ((ulp->l_pair[0] && ulp->l_pair[1]) && (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) {
+ /* time has come to make a face! */
+ BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e);
+ BMFace *f, *f_example = ulp->l_pair[0]->f;
+ BMLoop *l_iter;
+ BMVert *f_verts[4];
+
+ if (v_shared == NULL) {
+ /* quad */
+ f_verts[0] = ulp->l_pair[0]->e->v1;
+ f_verts[1] = ulp->l_pair[1]->e->v1;
+ f_verts[2] = ulp->l_pair[1]->e->v2;
+ f_verts[3] = ulp->l_pair[0]->e->v2;
+
+ if (ulp->flag & ULP_FLIP_0) {
+ SWAP(BMVert *, f_verts[0], f_verts[3]);
+ }
+ if (ulp->flag & ULP_FLIP_1) {
+ SWAP(BMVert *, f_verts[1], f_verts[2]);
+ }
+ }
+ else {
+ /* tri */
+ f_verts[0] = v_shared;
+ f_verts[1] = BM_edge_other_vert(ulp->l_pair[0]->e, v_shared);
+ f_verts[2] = BM_edge_other_vert(ulp->l_pair[1]->e, v_shared);
+ f_verts[3] = NULL;
+
+ /* don't use the flip flags */
+ if (v_shared == ulp->l_pair[0]->v) {
+ SWAP(BMVert *, f_verts[0], f_verts[1]);
+ }
+ }
+
+ /* face should never exist */
+ BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3));
+
+ f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true);
+
+ l_iter = BM_FACE_FIRST_LOOP(f);
+
+ if (f_verts[3]) {
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
+ l_iter = l_iter->next;
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
+ l_iter = l_iter->next;
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
+ l_iter = l_iter->next;
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
+ }
+ else {
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
+ l_iter = l_iter->next;
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
+ l_iter = l_iter->next;
+ BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
+ }
+ }
+ }
}
/* --- end 'face-fill' code --- */
@@ -519,357 +511,355 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u
*/
static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obedit, bool do_fill)
{
- UnorderedLoopPair *fill_uloop_pairs = NULL;
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMIter iter, liter;
- BMLoop *l;
- BMEdge *e_best;
- BMVert *v;
- const int totvert_orig = bm->totvert;
- int i;
- float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
- float dist_sq = FLT_MAX;
- float d;
- bool is_wire, is_manifold_region;
-
- BMEditSelection ese;
- int totboundary_edge = 0;
-
- ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
-
- /* find selected vert - same some time and check history first */
- if (BM_select_history_active_get(bm, &ese) && ese.htype == BM_VERT) {
- v = (BMVert *)ese.ele;
- }
- else {
- ese.ele = NULL;
-
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT))
- break;
- }
- }
-
- /* (v == NULL) should be impossible */
- if ((v == NULL) || (v->e == NULL)) {
- return OPERATOR_CANCELLED;
- }
-
- is_wire = BM_vert_is_wire(v);
- is_manifold_region = BM_vert_is_manifold_region(v);
-
- e_best = NULL;
-
- {
- BMEdge *e;
- /* find closest edge to mouse cursor */
- BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
- /* consider wire as boundary for this purpose,
- * otherwise we can't a face away from a wire edge */
- totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e));
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- if ((is_manifold_region == false) || BM_edge_is_manifold(e)) {
- d = edbm_rip_edgedist_squared(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT);
- if ((e_best == NULL) || (d < dist_sq)) {
- dist_sq = d;
- e_best = e;
- }
- }
- }
- }
- }
-
- if (e_best && e_best->l && (is_manifold_region == false)) {
- /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
- BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next;
- BMVert *v_new;
-
- BLI_assert(l_sep->v == v);
- v_new = BM_face_loop_separate_multi_isolated(bm, l_sep);
- BLI_assert(BM_vert_find_first_loop(v));
-
- BM_vert_select_set(bm, v, false);
- BM_select_history_remove(bm, v);
-
- BM_vert_select_set(bm, v_new, true);
- if (ese.ele) {
- BM_select_history_store(bm, v_new);
- }
-
- if (do_fill) {
- BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP);
- }
-
- return OPERATOR_FINISHED;
- }
-
- /* if we are ripping a single vertex from 3 faces,
- * then measure the distance to the face corner as well as the edge */
- if (BM_vert_face_count_is_equal(v, 3) &&
- BM_vert_edge_count_is_equal(v, 3))
- {
- BMEdge *e_all[3];
- BMLoop *l_all[3];
- int i1, i2;
-
- BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
- BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
-
- /* not do a loop similar to the one above, but test against loops */
- for (i1 = 0; i1 < 3; i1++) {
- /* consider wire as boundary for this purpose,
- * otherwise we can't a face away from a wire edge */
- float l_mid_co[3];
- l = l_all[i1];
- edbm_calc_loop_co(l, l_mid_co);
- d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
- if ((e_best == NULL) || (d < dist_sq)) {
- dist_sq = d;
-
- /* find the edge that is not in this loop */
- e_best = NULL;
- for (i2 = 0; i2 < 3; i2++) {
- if (!BM_edge_in_loop(e_all[i2], l)) {
- e_best = e_all[i2];
- break;
- }
- }
- BLI_assert(e_best != NULL);
- }
- }
- }
-
- /* should we go ahead with edge rip or do we need to do special case, split off vertex?:
- * split off vertex if...
- * - we cant find an edge - this means we are ripping a faces vert that is connected to other
- * geometry only at the vertex.
- * - the boundary edge total is greater than 2,
- * in this case edge split _can_ work but we get far nicer results if we use this special case.
- * - there are only 2 edges but we are a wire vert. */
- if ((is_wire == false && totboundary_edge > 2) ||
- (is_wire == true && totboundary_edge > 1))
- {
- BMVert **vout;
- int vout_len;
-
- BM_vert_select_set(bm, v, false);
-
- bmesh_kernel_vert_separate(bm, v, &vout, &vout_len, true);
-
- if (vout_len < 2) {
- MEM_freeN(vout);
- /* set selection back to avoid active-unselected vertex */
- BM_vert_select_set(bm, v, true);
- /* should never happen */
- return OPERATOR_CANCELLED;
- }
- else {
- int vi_best = 0;
-
- if (ese.ele) {
- BM_select_history_remove(bm, ese.ele);
- }
-
- dist_sq = FLT_MAX;
-
- /* in the loop below we find the best vertex to drag based on its connected geometry,
- * either by its face corner, or connected edge (when no faces are attached) */
- for (i = 0; i < vout_len; i++) {
-
- if (BM_vert_is_wire(vout[i]) == false) {
- /* find the best face corner */
- BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) {
- if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) {
- float l_mid_co[3];
-
- edbm_calc_loop_co(l, l_mid_co);
- d = edbm_rip_edgedist_squared(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT);
-
- if (d < dist_sq) {
- dist_sq = d;
- vi_best = i;
- }
- }
- }
- }
- else {
- BMEdge *e;
- /* a wire vert, find the best edge */
- BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) {
- if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
- float e_mid_co[3];
-
- mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co);
- d = edbm_rip_edgedist_squared(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT);
-
- if (d < dist_sq) {
- dist_sq = d;
- vi_best = i;
- }
- }
- }
- }
- }
-
- /* vout[0] == best
- * vout[1] == glue
- * vout[2+] == splice with glue (when vout_len > 2)
- */
- if (vi_best != 0) {
- SWAP(BMVert *, vout[0], vout[vi_best]);
- vi_best = 0;
- }
-
- /* select the vert from the best region */
- v = vout[vi_best];
- BM_vert_select_set(bm, v, true);
-
- if (ese.ele) {
- BM_select_history_store(bm, v);
- }
-
- /* splice all others back together */
- if (vout_len > 2) {
- for (i = 2; i < vout_len; i++) {
- BM_vert_splice(bm, vout[1], vout[i]);
- }
- }
-
- if (do_fill) {
- /* match extrude vert-order */
- BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
- }
-
- MEM_freeN(vout);
-
- return OPERATOR_FINISHED;
- }
- }
-
- if (!e_best) {
- return OPERATOR_CANCELLED;
- }
-
- /* *** Execute the split! *** */
- /* unlike edge split, for single vertex split we only use the operator in one of the cases
- * but both allocate fill */
-
- {
- BMVert *v_rip;
- BMLoop *larr[2];
- int larr_len = 0;
-
- /* rip two adjacent edges */
- if (BM_edge_is_boundary(e_best) || BM_vert_face_count_is_equal(v, 2)) {
- /* Don't run the edge split operator in this case */
-
- l = BM_edge_vert_share_loop(e_best->l, v);
- larr[larr_len] = l;
- larr_len++;
-
- /* only tag for face-fill (we don't call the operator) */
- if (BM_edge_is_boundary(e_best)) {
- BM_elem_flag_enable(e_best, BM_ELEM_TAG);
- }
- else {
- BM_elem_flag_enable(l->e, BM_ELEM_TAG);
- BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
- }
- }
- else {
- if (BM_edge_is_manifold(e_best)) {
- BMLoop *l_iter, *l_first;
- l_iter = l_first = e_best->l;
- do {
- larr[larr_len] = BM_edge_vert_share_loop(l_iter, v);
-
- if (do_fill) {
- /* Only needed when filling...
- * Also, we never want to tag best edge,
- * that one won't change during split. See T44618. */
- if (larr[larr_len]->e == e_best) {
- BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG);
- }
- else {
- BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG);
- }
- }
- larr_len++;
- } while ((l_iter = l_iter->radial_next) != l_first);
- }
- else {
- /* looks like there are no split edges, we could just return/report-error? - Campbell */
- }
- }
-
- /* keep directly before edgesplit */
- if (do_fill) {
- fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
- }
-
- if (larr_len) {
- v_rip = BM_face_loop_separate_multi(bm, larr, larr_len);
- }
- else {
- v_rip = NULL;
- }
-
- if (v_rip) {
- BM_vert_select_set(bm, v_rip, true);
- }
- else {
- if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs);
- return OPERATOR_CANCELLED;
- }
- }
-
- {
- /* --- select which vert --- */
- BMVert *v_best = NULL;
- float l_corner_co[3];
-
- dist_sq = FLT_MAX;
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
- /* disable by default, re-enable winner at end */
- BM_vert_select_set(bm, v, false);
- BM_select_history_remove(bm, v);
-
- BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
-
- /* check if v_best is null in the _rare_ case there are numeric issues */
- edbm_calc_loop_co(l, l_corner_co);
- d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT);
- if ((v_best == NULL) || (d < dist_sq)) {
- v_best = v;
- dist_sq = d;
- }
- }
- }
- }
-
- if (v_best) {
- BM_vert_select_set(bm, v_best, true);
- if (ese.ele) {
- BM_select_history_store(bm, v_best);
- }
- }
- }
-
- if (do_fill && fill_uloop_pairs) {
- edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs);
- MEM_freeN(fill_uloop_pairs);
- }
-
-
- if (totvert_orig == bm->totvert) {
- return OPERATOR_CANCELLED;
- }
-
- return OPERATOR_FINISHED;
+ UnorderedLoopPair *fill_uloop_pairs = NULL;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMIter iter, liter;
+ BMLoop *l;
+ BMEdge *e_best;
+ BMVert *v;
+ const int totvert_orig = bm->totvert;
+ int i;
+ float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
+ float dist_sq = FLT_MAX;
+ float d;
+ bool is_wire, is_manifold_region;
+
+ BMEditSelection ese;
+ int totboundary_edge = 0;
+
+ ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
+
+ /* find selected vert - same some time and check history first */
+ if (BM_select_history_active_get(bm, &ese) && ese.htype == BM_VERT) {
+ v = (BMVert *)ese.ele;
+ }
+ else {
+ ese.ele = NULL;
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT))
+ break;
+ }
+ }
+
+ /* (v == NULL) should be impossible */
+ if ((v == NULL) || (v->e == NULL)) {
+ return OPERATOR_CANCELLED;
+ }
+
+ is_wire = BM_vert_is_wire(v);
+ is_manifold_region = BM_vert_is_manifold_region(v);
+
+ e_best = NULL;
+
+ {
+ BMEdge *e;
+ /* find closest edge to mouse cursor */
+ BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
+ /* consider wire as boundary for this purpose,
+ * otherwise we can't a face away from a wire edge */
+ totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e));
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ if ((is_manifold_region == false) || BM_edge_is_manifold(e)) {
+ d = edbm_rip_edgedist_squared(
+ ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT);
+ if ((e_best == NULL) || (d < dist_sq)) {
+ dist_sq = d;
+ e_best = e;
+ }
+ }
+ }
+ }
+ }
+
+ if (e_best && e_best->l && (is_manifold_region == false)) {
+ /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
+ BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next;
+ BMVert *v_new;
+
+ BLI_assert(l_sep->v == v);
+ v_new = BM_face_loop_separate_multi_isolated(bm, l_sep);
+ BLI_assert(BM_vert_find_first_loop(v));
+
+ BM_vert_select_set(bm, v, false);
+ BM_select_history_remove(bm, v);
+
+ BM_vert_select_set(bm, v_new, true);
+ if (ese.ele) {
+ BM_select_history_store(bm, v_new);
+ }
+
+ if (do_fill) {
+ BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP);
+ }
+
+ return OPERATOR_FINISHED;
+ }
+
+ /* if we are ripping a single vertex from 3 faces,
+ * then measure the distance to the face corner as well as the edge */
+ if (BM_vert_face_count_is_equal(v, 3) && BM_vert_edge_count_is_equal(v, 3)) {
+ BMEdge *e_all[3];
+ BMLoop *l_all[3];
+ int i1, i2;
+
+ BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
+ BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
+
+ /* not do a loop similar to the one above, but test against loops */
+ for (i1 = 0; i1 < 3; i1++) {
+ /* consider wire as boundary for this purpose,
+ * otherwise we can't a face away from a wire edge */
+ float l_mid_co[3];
+ l = l_all[i1];
+ edbm_calc_loop_co(l, l_mid_co);
+ d = edbm_rip_edgedist_squared(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
+ if ((e_best == NULL) || (d < dist_sq)) {
+ dist_sq = d;
+
+ /* find the edge that is not in this loop */
+ e_best = NULL;
+ for (i2 = 0; i2 < 3; i2++) {
+ if (!BM_edge_in_loop(e_all[i2], l)) {
+ e_best = e_all[i2];
+ break;
+ }
+ }
+ BLI_assert(e_best != NULL);
+ }
+ }
+ }
+
+ /* should we go ahead with edge rip or do we need to do special case, split off vertex?:
+ * split off vertex if...
+ * - we cant find an edge - this means we are ripping a faces vert that is connected to other
+ * geometry only at the vertex.
+ * - the boundary edge total is greater than 2,
+ * in this case edge split _can_ work but we get far nicer results if we use this special case.
+ * - there are only 2 edges but we are a wire vert. */
+ if ((is_wire == false && totboundary_edge > 2) || (is_wire == true && totboundary_edge > 1)) {
+ BMVert **vout;
+ int vout_len;
+
+ BM_vert_select_set(bm, v, false);
+
+ bmesh_kernel_vert_separate(bm, v, &vout, &vout_len, true);
+
+ if (vout_len < 2) {
+ MEM_freeN(vout);
+ /* set selection back to avoid active-unselected vertex */
+ BM_vert_select_set(bm, v, true);
+ /* should never happen */
+ return OPERATOR_CANCELLED;
+ }
+ else {
+ int vi_best = 0;
+
+ if (ese.ele) {
+ BM_select_history_remove(bm, ese.ele);
+ }
+
+ dist_sq = FLT_MAX;
+
+ /* in the loop below we find the best vertex to drag based on its connected geometry,
+ * either by its face corner, or connected edge (when no faces are attached) */
+ for (i = 0; i < vout_len; i++) {
+
+ if (BM_vert_is_wire(vout[i]) == false) {
+ /* find the best face corner */
+ BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) {
+ if (!BM_elem_flag_test(l->f, BM_ELEM_HIDDEN)) {
+ float l_mid_co[3];
+
+ edbm_calc_loop_co(l, l_mid_co);
+ d = edbm_rip_edgedist_squared(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT);
+
+ if (d < dist_sq) {
+ dist_sq = d;
+ vi_best = i;
+ }
+ }
+ }
+ }
+ else {
+ BMEdge *e;
+ /* a wire vert, find the best edge */
+ BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) {
+ if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ float e_mid_co[3];
+
+ mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co);
+ d = edbm_rip_edgedist_squared(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT);
+
+ if (d < dist_sq) {
+ dist_sq = d;
+ vi_best = i;
+ }
+ }
+ }
+ }
+ }
+
+ /* vout[0] == best
+ * vout[1] == glue
+ * vout[2+] == splice with glue (when vout_len > 2)
+ */
+ if (vi_best != 0) {
+ SWAP(BMVert *, vout[0], vout[vi_best]);
+ vi_best = 0;
+ }
+
+ /* select the vert from the best region */
+ v = vout[vi_best];
+ BM_vert_select_set(bm, v, true);
+
+ if (ese.ele) {
+ BM_select_history_store(bm, v);
+ }
+
+ /* splice all others back together */
+ if (vout_len > 2) {
+ for (i = 2; i < vout_len; i++) {
+ BM_vert_splice(bm, vout[1], vout[i]);
+ }
+ }
+
+ if (do_fill) {
+ /* match extrude vert-order */
+ BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
+ }
+
+ MEM_freeN(vout);
+
+ return OPERATOR_FINISHED;
+ }
+ }
+
+ if (!e_best) {
+ return OPERATOR_CANCELLED;
+ }
+
+ /* *** Execute the split! *** */
+ /* unlike edge split, for single vertex split we only use the operator in one of the cases
+ * but both allocate fill */
+
+ {
+ BMVert *v_rip;
+ BMLoop *larr[2];
+ int larr_len = 0;
+
+ /* rip two adjacent edges */
+ if (BM_edge_is_boundary(e_best) || BM_vert_face_count_is_equal(v, 2)) {
+ /* Don't run the edge split operator in this case */
+
+ l = BM_edge_vert_share_loop(e_best->l, v);
+ larr[larr_len] = l;
+ larr_len++;
+
+ /* only tag for face-fill (we don't call the operator) */
+ if (BM_edge_is_boundary(e_best)) {
+ BM_elem_flag_enable(e_best, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(l->e, BM_ELEM_TAG);
+ BM_elem_flag_enable(l->prev->e, BM_ELEM_TAG);
+ }
+ }
+ else {
+ if (BM_edge_is_manifold(e_best)) {
+ BMLoop *l_iter, *l_first;
+ l_iter = l_first = e_best->l;
+ do {
+ larr[larr_len] = BM_edge_vert_share_loop(l_iter, v);
+
+ if (do_fill) {
+ /* Only needed when filling...
+ * Also, we never want to tag best edge,
+ * that one won't change during split. See T44618. */
+ if (larr[larr_len]->e == e_best) {
+ BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG);
+ }
+ else {
+ BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG);
+ }
+ }
+ larr_len++;
+ } while ((l_iter = l_iter->radial_next) != l_first);
+ }
+ else {
+ /* looks like there are no split edges, we could just return/report-error? - Campbell */
+ }
+ }
+
+ /* keep directly before edgesplit */
+ if (do_fill) {
+ fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
+ }
+
+ if (larr_len) {
+ v_rip = BM_face_loop_separate_multi(bm, larr, larr_len);
+ }
+ else {
+ v_rip = NULL;
+ }
+
+ if (v_rip) {
+ BM_vert_select_set(bm, v_rip, true);
+ }
+ else {
+ if (fill_uloop_pairs)
+ MEM_freeN(fill_uloop_pairs);
+ return OPERATOR_CANCELLED;
+ }
+ }
+
+ {
+ /* --- select which vert --- */
+ BMVert *v_best = NULL;
+ float l_corner_co[3];
+
+ dist_sq = FLT_MAX;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ /* disable by default, re-enable winner at end */
+ BM_vert_select_set(bm, v, false);
+ BM_select_history_remove(bm, v);
+
+ BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
+
+ /* check if v_best is null in the _rare_ case there are numeric issues */
+ edbm_calc_loop_co(l, l_corner_co);
+ d = edbm_rip_edgedist_squared(
+ ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT);
+ if ((v_best == NULL) || (d < dist_sq)) {
+ v_best = v;
+ dist_sq = d;
+ }
+ }
+ }
+ }
+
+ if (v_best) {
+ BM_vert_select_set(bm, v_best, true);
+ if (ese.ele) {
+ BM_select_history_store(bm, v_best);
+ }
+ }
+ }
+
+ if (do_fill && fill_uloop_pairs) {
+ edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs);
+ MEM_freeN(fill_uloop_pairs);
+ }
+
+ if (totvert_orig == bm->totvert) {
+ return OPERATOR_CANCELLED;
+ }
+
+ return OPERATOR_FINISHED;
}
/**
@@ -877,247 +867,246 @@ static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obed
*/
static int edbm_rip_invoke__edge(bContext *C, const wmEvent *event, Object *obedit, bool do_fill)
{
- UnorderedLoopPair *fill_uloop_pairs = NULL;
- ARegion *ar = CTX_wm_region(C);
- RegionView3D *rv3d = CTX_wm_region_view3d(C);
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
- BMesh *bm = em->bm;
- BMIter iter, eiter;
- BMLoop *l;
- BMEdge *e_best;
- BMVert *v;
- const int totedge_orig = bm->totedge;
- float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
-
- EdgeLoopPair *eloop_pairs;
-
- ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
-
- /* important this runs on the original selection, before tampering with tagging */
- eloop_pairs = edbm_ripsel_looptag_helper(bm);
-
- /* expand edge selection */
- BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
- BMEdge *e;
- bool all_manifold;
- int totedge_manifold; /* manifold, visible edges */
- int i;
-
- e_best = NULL;
- i = 0;
- totedge_manifold = 0;
- all_manifold = true;
- BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
-
- if (!BM_edge_is_wire(e) &&
- !BM_elem_flag_test(e, BM_ELEM_HIDDEN))
- {
- /* important to check selection rather then tag here
- * else we get feedback loop */
- if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
- e_best = e;
- i++;
- }
- totedge_manifold++;
- }
-
- /** #BM_vert_other_disk_edge has no hidden checks so don't check hidden here */
- if ((all_manifold == true) && (BM_edge_is_manifold(e) == false)) {
- all_manifold = false;
- }
- }
-
- /* single edge, extend */
- if (i == 1 && e_best->l) {
- /* note: if the case of 3 edges has one change in loop stepping,
- * if this becomes more involved we may be better off splitting
- * the 3 edge case into its own else-if branch */
- if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) {
- BMLoop *l_a = e_best->l;
- BMLoop *l_b = l_a->radial_next;
-
- /* find the best face to follow, this way the edge won't point away from
- * the mouse when there are more than 4 (takes the shortest face fan around) */
- l = (edbm_rip_edge_side_measure(e_best, l_a, ar, projectMat, fmval) <
- edbm_rip_edge_side_measure(e_best, l_b, ar, projectMat, fmval)) ? l_a : l_b;
-
- l = BM_loop_other_edge_loop(l, v);
- /* important edge is manifold else we can be attempting to split off a fan that don't budge,
- * not crashing but adds duplicate edge. */
- if (BM_edge_is_manifold(l->e)) {
- l = l->radial_next;
-
- if (totedge_manifold != 3)
- l = BM_loop_other_edge_loop(l, v);
-
- if (l) {
- BLI_assert(!BM_elem_flag_test(l->e, BM_ELEM_TAG));
- BM_elem_flag_enable(l->e, BM_ELEM_TAG);
- }
- }
- }
- else {
- e = BM_vert_other_disk_edge(v, e_best);
-
- if (e) {
- BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG));
- BM_elem_flag_enable(e, BM_ELEM_TAG);
- }
- }
- }
- }
-
- /* keep directly before edgesplit */
- if (do_fill) {
- fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
- }
-
- BM_mesh_edgesplit(em->bm, true, true, true);
-
- /* note: the output of the bmesh operator is ignored, since we built
- * the contiguous loop pairs to split already, its possible that some
- * edge did not split even though it was tagged which would not work
- * as expected (but not crash), however there are checks to ensure
- * tagged edges will split. So far its not been an issue. */
- edbm_ripsel_deselect_helper(bm, eloop_pairs,
- ar, projectMat, fmval);
- MEM_freeN(eloop_pairs);
-
- /* deselect loose verts */
- BM_mesh_select_mode_clean_ex(bm, SCE_SELECT_EDGE);
-
- if (do_fill && fill_uloop_pairs) {
- edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs);
- MEM_freeN(fill_uloop_pairs);
- }
-
- if (totedge_orig == bm->totedge) {
- return OPERATOR_CANCELLED;
- }
-
- BM_select_history_validate(bm);
-
- return OPERATOR_FINISHED;
+ UnorderedLoopPair *fill_uloop_pairs = NULL;
+ ARegion *ar = CTX_wm_region(C);
+ RegionView3D *rv3d = CTX_wm_region_view3d(C);
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+ BMesh *bm = em->bm;
+ BMIter iter, eiter;
+ BMLoop *l;
+ BMEdge *e_best;
+ BMVert *v;
+ const int totedge_orig = bm->totedge;
+ float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
+
+ EdgeLoopPair *eloop_pairs;
+
+ ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
+
+ /* important this runs on the original selection, before tampering with tagging */
+ eloop_pairs = edbm_ripsel_looptag_helper(bm);
+
+ /* expand edge selection */
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ BMEdge *e;
+ bool all_manifold;
+ int totedge_manifold; /* manifold, visible edges */
+ int i;
+
+ e_best = NULL;
+ i = 0;
+ totedge_manifold = 0;
+ all_manifold = true;
+ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
+
+ if (!BM_edge_is_wire(e) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) {
+ /* important to check selection rather then tag here
+ * else we get feedback loop */
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ e_best = e;
+ i++;
+ }
+ totedge_manifold++;
+ }
+
+ /** #BM_vert_other_disk_edge has no hidden checks so don't check hidden here */
+ if ((all_manifold == true) && (BM_edge_is_manifold(e) == false)) {
+ all_manifold = false;
+ }
+ }
+
+ /* single edge, extend */
+ if (i == 1 && e_best->l) {
+ /* note: if the case of 3 edges has one change in loop stepping,
+ * if this becomes more involved we may be better off splitting
+ * the 3 edge case into its own else-if branch */
+ if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) {
+ BMLoop *l_a = e_best->l;
+ BMLoop *l_b = l_a->radial_next;
+
+ /* find the best face to follow, this way the edge won't point away from
+ * the mouse when there are more than 4 (takes the shortest face fan around) */
+ l = (edbm_rip_edge_side_measure(e_best, l_a, ar, projectMat, fmval) <
+ edbm_rip_edge_side_measure(e_best, l_b, ar, projectMat, fmval)) ?
+ l_a :
+ l_b;
+
+ l = BM_loop_other_edge_loop(l, v);
+ /* important edge is manifold else we can be attempting to split off a fan that don't budge,
+ * not crashing but adds duplicate edge. */
+ if (BM_edge_is_manifold(l->e)) {
+ l = l->radial_next;
+
+ if (totedge_manifold != 3)
+ l = BM_loop_other_edge_loop(l, v);
+
+ if (l) {
+ BLI_assert(!BM_elem_flag_test(l->e, BM_ELEM_TAG));
+ BM_elem_flag_enable(l->e, BM_ELEM_TAG);
+ }
+ }
+ }
+ else {
+ e = BM_vert_other_disk_edge(v, e_best);
+
+ if (e) {
+ BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG));
+ BM_elem_flag_enable(e, BM_ELEM_TAG);
+ }
+ }
+ }
+ }
+
+ /* keep directly before edgesplit */
+ if (do_fill) {
+ fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
+ }
+
+ BM_mesh_edgesplit(em->bm, true, true, true);
+
+ /* note: the output of the bmesh operator is ignored, since we built
+ * the contiguous loop pairs to split already, its possible that some
+ * edge did not split even though it was tagged which would not work
+ * as expected (but not crash), however there are checks to ensure
+ * tagged edges will split. So far its not been an issue. */
+ edbm_ripsel_deselect_helper(bm, eloop_pairs, ar, projectMat, fmval);
+ MEM_freeN(eloop_pairs);
+
+ /* deselect loose verts */
+ BM_mesh_select_mode_clean_ex(bm, SCE_SELECT_EDGE);
+
+ if (do_fill && fill_uloop_pairs) {
+ edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs);
+ MEM_freeN(fill_uloop_pairs);
+ }
+
+ if (totedge_orig == bm->totedge) {
+ return OPERATOR_CANCELLED;
+ }
+
+ BM_select_history_validate(bm);
+
+ return OPERATOR_FINISHED;
}
/* based on mouse cursor position, it defines how is being ripped */
static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
- ViewLayer *view_layer = CTX_data_view_layer(C);
- uint objects_len = 0;
- Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, CTX_wm_view3d(C), &objects_len);
- const bool do_fill = RNA_boolean_get(op->ptr, "use_fill");
-
- bool no_vertex_selected = true;
- bool error_face_selected = true;
- bool error_disconnected_vertices = true;
- bool error_rip_failed = true;
-
- for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
- Object *obedit = objects[ob_index];
- BMEditMesh *em = BKE_editmesh_from_object(obedit);
-
- BMesh *bm = em->bm;
- BMIter iter;
- BMEdge *e;
- const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0);
- int ret;
-
- if (em->bm->totvertsel == 0) {
- continue;
- }
- no_vertex_selected = false;
-
- /* running in face mode hardly makes sense, so convert to region loop and rip */
- if (bm->totfacesel) {
- /* highly nifty but hard to support since the operator can fail and we're left
- * with modified selection */
- // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL);
- continue;
- }
- error_face_selected = false;
-
- /* we could support this, but not for now */
- if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) {
- continue;
- }
- error_disconnected_vertices = false;
-
- /* note on selection:
- * When calling edge split we operate on tagged edges rather then selected
- * this is important because the edges to operate on are extended by one,
- * but the selection is left alone.
- *
- * After calling edge split - the duplicated edges have the same selection state as the
- * original, so all we do is de-select the far side from the mouse and we have a
- * useful selection for grabbing.
- */
-
- /* BM_ELEM_SELECT --> BM_ELEM_TAG */
- BM_ITER_MESH(e, &iter, bm, BM_EDGES_OF_MESH) {
- BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
- }
-
- /* split 2 main parts of this operator out into vertex and edge ripping */
- if (singlesel) {
- ret = edbm_rip_invoke__vert(C, event, obedit, do_fill);
- }
- else {
- ret = edbm_rip_invoke__edge(C, event, obedit, do_fill);
- }
-
- if (ret != OPERATOR_FINISHED) {
- continue;
- }
-
- BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0));
-
- if (bm->totvertsel == 0) {
- continue;
- }
- error_rip_failed = false;
-
- EDBM_update_generic(em, true, true);
- }
-
- MEM_freeN(objects);
-
- if (no_vertex_selected) {
- /* Ignore it. */
- return OPERATOR_CANCELLED;
- }
- else if (error_face_selected) {
- BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces");
- return OPERATOR_CANCELLED;
- }
- else if (error_disconnected_vertices) {
- BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices");
- return OPERATOR_CANCELLED;
- }
- else if (error_rip_failed) {
- BKE_report(op->reports, RPT_ERROR, "Rip failed");
- return OPERATOR_CANCELLED;
- }
- /* No errors, everything went fine. */
- return OPERATOR_FINISHED;
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ uint objects_len = 0;
+ Object **objects = BKE_view_layer_array_from_objects_in_edit_mode_unique_data(
+ view_layer, CTX_wm_view3d(C), &objects_len);
+ const bool do_fill = RNA_boolean_get(op->ptr, "use_fill");
+
+ bool no_vertex_selected = true;
+ bool error_face_selected = true;
+ bool error_disconnected_vertices = true;
+ bool error_rip_failed = true;
+
+ for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
+ Object *obedit = objects[ob_index];
+ BMEditMesh *em = BKE_editmesh_from_object(obedit);
+
+ BMesh *bm = em->bm;
+ BMIter iter;
+ BMEdge *e;
+ const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0);
+ int ret;
+
+ if (em->bm->totvertsel == 0) {
+ continue;
+ }
+ no_vertex_selected = false;
+
+ /* running in face mode hardly makes sense, so convert to region loop and rip */
+ if (bm->totfacesel) {
+ /* highly nifty but hard to support since the operator can fail and we're left
+ * with modified selection */
+ // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL);
+ continue;
+ }
+ error_face_selected = false;
+
+ /* we could support this, but not for now */
+ if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) {
+ continue;
+ }
+ error_disconnected_vertices = false;
+
+ /* note on selection:
+ * When calling edge split we operate on tagged edges rather then selected
+ * this is important because the edges to operate on are extended by one,
+ * but the selection is left alone.
+ *
+ * After calling edge split - the duplicated edges have the same selection state as the
+ * original, so all we do is de-select the far side from the mouse and we have a
+ * useful selection for grabbing.
+ */
+
+ /* BM_ELEM_SELECT --> BM_ELEM_TAG */
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, BM_elem_flag_test(e, BM_ELEM_SELECT));
+ }
+
+ /* split 2 main parts of this operator out into vertex and edge ripping */
+ if (singlesel) {
+ ret = edbm_rip_invoke__vert(C, event, obedit, do_fill);
+ }
+ else {
+ ret = edbm_rip_invoke__edge(C, event, obedit, do_fill);
+ }
+
+ if (ret != OPERATOR_FINISHED) {
+ continue;
+ }
+
+ BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0));
+
+ if (bm->totvertsel == 0) {
+ continue;
+ }
+ error_rip_failed = false;
+
+ EDBM_update_generic(em, true, true);
+ }
+
+ MEM_freeN(objects);
+
+ if (no_vertex_selected) {
+ /* Ignore it. */
+ return OPERATOR_CANCELLED;
+ }
+ else if (error_face_selected) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces");
+ return OPERATOR_CANCELLED;
+ }
+ else if (error_disconnected_vertices) {
+ BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices");
+ return OPERATOR_CANCELLED;
+ }
+ else if (error_rip_failed) {
+ BKE_report(op->reports, RPT_ERROR, "Rip failed");
+ return OPERATOR_CANCELLED;
+ }
+ /* No errors, everything went fine. */
+ return OPERATOR_FINISHED;
}
-
void MESH_OT_rip(wmOperatorType *ot)
{
- /* identifiers */
- ot->name = "Rip";
- ot->idname = "MESH_OT_rip";
- ot->description = "Disconnect vertex or edges from connected geometry";
+ /* identifiers */
+ ot->name = "Rip";
+ ot->idname = "MESH_OT_rip";
+ ot->description = "Disconnect vertex or edges from connected geometry";
- /* api callbacks */
- ot->invoke = edbm_rip_invoke;
- ot->poll = EDBM_view3d_poll;
+ /* api callbacks */
+ ot->invoke = edbm_rip_invoke;
+ ot->poll = EDBM_view3d_poll;
- /* flags */
- ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
- /* to give to transform */
- Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
- RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill the ripped region");
+ /* to give to transform */
+ Transform_Properties(ot, P_PROPORTIONAL | P_MIRROR_DUMMY);
+ RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill the ripped region");
}