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:
authorCampbell Barton <ideasman42@gmail.com>2013-03-09 18:14:20 +0400
committerCampbell Barton <ideasman42@gmail.com>2013-03-09 18:14:20 +0400
commit6a59f71d043b8cc6fa9556eb611beba00a7ed7e7 (patch)
treeb16e20d838b63c111ee0f7cb7dc519c64c877ebe /source/blender/editors/mesh
parent964cead5b1826f859ac3371ad7f0d9f4665c229f (diff)
bmesh: face creation from a single selected vertex/edge, now extends the selection along wire/boundary edges and makes a face.
Selection is specifically so you can continuously fill in holes by tapping the Fkey. Similar functionality to the F2 addon, however the mouse location isn't used.
Diffstat (limited to 'source/blender/editors/mesh')
-rw-r--r--source/blender/editors/mesh/editmesh_tools.c152
1 files changed, 150 insertions, 2 deletions
diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c
index ffedef6c0b5..5da01daff55 100644
--- a/source/blender/editors/mesh/editmesh_tools.c
+++ b/source/blender/editors/mesh/editmesh_tools.c
@@ -76,6 +76,8 @@
#include "mesh_intern.h"
+#define USE_FACE_CREATE_SEL_EXTEND
+
#define MVAL_PIXEL_MARGIN 5.0f
/* allow accumulated normals to form a new direction but don't
@@ -1098,6 +1100,129 @@ static int edbm_add_edge_face__smooth_get(BMesh *bm)
return (vote_on_smooth[0] < vote_on_smooth[1]);
}
+#ifdef USE_FACE_CREATE_SEL_EXTEND
+/**
+ * Function used to get a fixed number of edges linked to a vertex that passes a test function.
+ * This is used so we can request all boundary edges connected to a vertex for eg.
+ */
+static int edbm_add_edge_face_exec__vert_edge_lookup(BMVert *v, BMEdge *e_used, BMEdge **e_arr, const int e_arr_len,
+ bool (* func)(BMEdge *))
+{
+ BMIter iter;
+ BMEdge *e_iter;
+ int i = 0;
+ BM_ITER_ELEM (e_iter, &iter, v, BM_EDGES_OF_VERT) {
+ if (BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) {
+ if ((e_used == NULL) || (e_used != e_iter)) {
+ if (func(e_iter)) {
+ e_arr[i++] = e_iter;
+ if (i >= e_arr_len) {
+ break;
+ }
+ }
+ }
+ }
+ }
+ return i;
+}
+
+static BMElem *edbm_add_edge_face_exec__tricky_extend_sel(BMesh *bm)
+{
+ BMIter iter;
+ bool found = false;
+
+ if (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0) {
+ /* first look for 2 boundary edges */
+ BMVert *v;
+
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ found = true;
+ break;
+ }
+ }
+
+ if (found) {
+ BMEdge *ed_pair[3] = {NULL};
+ if (
+ ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_wire) == 2) &&
+ (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false)) ||
+
+ ((edbm_add_edge_face_exec__vert_edge_lookup(v, NULL, ed_pair, 3, BM_edge_is_boundary) == 2) &&
+ (BM_edge_share_face_check(ed_pair[0], ed_pair[1]) == false))
+ )
+ {
+ BM_edge_select_set(bm, ed_pair[0], true);
+ BM_edge_select_set(bm, ed_pair[1], true);
+ return (BMElem *)v;
+ }
+ }
+ }
+ else if (bm->totvertsel == 2 && bm->totedgesel == 1 && bm->totfacesel == 0) {
+ /* first look for 2 boundary edges */
+ BMEdge *e;
+
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ found = true;
+ break;
+ }
+ }
+ if (found) {
+ BMEdge *ed_pair_a[2] = {NULL};
+ BMEdge *ed_pair_b[2] = {NULL};
+ if (
+ ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_a, 2, BM_edge_is_wire) == 1) &&
+ (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_b, 2, BM_edge_is_wire) == 1) &&
+ (BM_edge_share_face_check(e, ed_pair_a[0]) == false) &&
+ (BM_edge_share_face_check(e, ed_pair_b[0]) == false)) ||
+
+ ((edbm_add_edge_face_exec__vert_edge_lookup(e->v1, e, ed_pair_a, 2, BM_edge_is_boundary) == 1) &&
+ (edbm_add_edge_face_exec__vert_edge_lookup(e->v2, e, ed_pair_b, 2, BM_edge_is_boundary) == 1) &&
+ (BM_edge_share_face_check(e, ed_pair_a[0]) == false) &&
+ (BM_edge_share_face_check(e, ed_pair_b[0]) == false))
+ )
+ {
+ BM_edge_select_set(bm, ed_pair_a[0], true);
+ BM_edge_select_set(bm, ed_pair_b[0], true);
+ return (BMElem *)e;
+ }
+ }
+ }
+
+ return NULL;
+}
+static void edbm_add_edge_face_exec__tricky_finalize_sel(BMesh *bm, BMElem *ele_desel, BMFace *f)
+{
+ /* now we need to find the edge that isnt connected to this element */
+ BM_select_history_clear(bm);
+
+ if (ele_desel->head.htype == BM_VERT) {
+ BMLoop *l = BM_face_vert_share_loop(f, (BMVert *)ele_desel);
+ BLI_assert(f->len == 3);
+ BM_face_select_set(bm, f, false);
+ BM_vert_select_set(bm, (BMVert *)ele_desel, false);
+
+ BM_edge_select_set(bm, l->next->e, true);
+ BM_select_history_store(bm, l->next->e);
+ }
+ else {
+ BMLoop *l = BM_face_edge_share_loop(f, (BMEdge *)ele_desel);
+ BLI_assert(f->len == 4 || f->len == 3);
+ BM_face_select_set(bm, f, false);
+ BM_edge_select_set(bm, (BMEdge *)ele_desel, false);
+ if (f->len == 4) {
+ BM_edge_select_set(bm, l->next->next->e, true);
+ BM_select_history_store(bm, l->next->next->e);
+ }
+ else {
+ BM_vert_select_set(bm, l->next->next->v, true);
+ BM_select_history_store(bm, l->next->next->v);
+ }
+ }
+}
+#endif /* USE_FACE_CREATE_SEL_EXTEND */
+
static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
{
BMOperator bmop;
@@ -1106,6 +1231,15 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
const short use_smooth = edbm_add_edge_face__smooth_get(em->bm);
/* when this is used to dissolve we could avoid this, but checking isnt too slow */
+#ifdef USE_FACE_CREATE_SEL_EXTEND
+ BMElem *ele_desel;
+ BMFace *ele_desel_face;
+
+ /* be extra clever, figure out if a partial selection should be extended so we can create geometry
+ * with single vert or single edge selection */
+ ele_desel = edbm_add_edge_face_exec__tricky_extend_sel(em->bm);
+#endif
+
if (!EDBM_op_init(em, &bmop, op,
"contextual_create geom=%hfev mat_nr=%i use_smooth=%b",
BM_ELEM_SELECT, em->mat_nr, use_smooth))
@@ -1114,8 +1248,22 @@ static int edbm_add_edge_face_exec(bContext *C, wmOperator *op)
}
BMO_op_exec(em->bm, &bmop);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, TRUE);
- BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, TRUE);
+
+#ifdef USE_FACE_CREATE_SEL_EXTEND
+ /* normally we would want to leave the new geometry selected,
+ * but being able to press F many times to add geometry is too useful! */
+ if (ele_desel &&
+ (BMO_slot_buffer_count(bmop.slots_out, "faces.out") == 1) &&
+ (ele_desel_face = BMO_slot_buffer_get_first(bmop.slots_out, "faces.out")))
+ {
+ edbm_add_edge_face_exec__tricky_finalize_sel(em->bm, ele_desel, ele_desel_face);
+ }
+ else
+#endif
+ {
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "faces.out", BM_FACE, BM_ELEM_SELECT, true);
+ BMO_slot_buffer_hflag_enable(em->bm, bmop.slots_out, "edges.out", BM_EDGE, BM_ELEM_SELECT, true);
+ }
if (!EDBM_op_finish(em, &bmop, op, TRUE)) {
return OPERATOR_CANCELLED;