[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [55136] trunk/blender/source/blender: bmesh: face creation from a single selected vertex/edge, now extends the selection along wire/boundary edges and makes a face.

Campbell Barton ideasman42 at gmail.com
Sat Mar 9 15:14:21 CET 2013


Revision: 55136
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=55136
Author:   campbellbarton
Date:     2013-03-09 14:14:20 +0000 (Sat, 09 Mar 2013)
Log Message:
-----------
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.

Modified Paths:
--------------
    trunk/blender/source/blender/bmesh/intern/bmesh_operator_api.h
    trunk/blender/source/blender/bmesh/intern/bmesh_operators.c
    trunk/blender/source/blender/editors/mesh/editmesh_tools.c

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_operator_api.h
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_operator_api.h	2013-03-09 13:44:09 UTC (rev 55135)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_operator_api.h	2013-03-09 14:14:20 UTC (rev 55136)
@@ -451,7 +451,7 @@
 	char restrictmask; /* bitwise '&' with BMHeader.htype */
 } BMOIter;
 
-void *BMO_slot_buffer_elem_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
+void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name);
 
 void *BMO_iter_new(BMOIter *iter,
                    BMOpSlot slot_args[BMO_OP_MAX_SLOTS],  const char *slot_name,

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_operators.c
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_operators.c	2013-03-09 13:44:09 UTC (rev 55135)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_operators.c	2013-03-09 14:14:20 UTC (rev 55136)
@@ -1355,7 +1355,7 @@
 	bm->elem_index_dirty &= ~(BM_VERT | BM_EDGE | BM_FACE);
 }
 
-void *BMO_slot_buffer_elem_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
+void *BMO_slot_buffer_get_first(BMOpSlot slot_args[BMO_OP_MAX_SLOTS], const char *slot_name)
 {
 	BMOpSlot *slot = BMO_slot_get(slot_args, slot_name);
 	

Modified: trunk/blender/source/blender/editors/mesh/editmesh_tools.c
===================================================================
--- trunk/blender/source/blender/editors/mesh/editmesh_tools.c	2013-03-09 13:44:09 UTC (rev 55135)
+++ trunk/blender/source/blender/editors/mesh/editmesh_tools.c	2013-03-09 14:14:20 UTC (rev 55136)
@@ -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 @@
 	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 @@
 	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,9 +1248,23 @@
 	}
 	
 	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;
 	}




More information about the Bf-blender-cvs mailing list