[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [51308] trunk/blender/source/blender: Rip-fill mesh tool (option for rip operator)

Campbell Barton ideasman42 at gmail.com
Sun Oct 14 06:42:17 CEST 2012


Revision: 51308
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=51308
Author:   campbellbarton
Date:     2012-10-14 04:42:11 +0000 (Sun, 14 Oct 2012)
Log Message:
-----------
Rip-fill mesh tool (option for rip operator)

Alt+V will fill the area inbetween the ripped faces - a bit like extrude.
faces are flipped to match existing geometry and customdata (uv, vcols etc) is copied from surrounding geometry too.

Modified Paths:
--------------
    trunk/blender/source/blender/bmesh/intern/bmesh_queries.c
    trunk/blender/source/blender/bmesh/intern/bmesh_queries.h
    trunk/blender/source/blender/editors/mesh/editmesh_rip.c
    trunk/blender/source/blender/editors/mesh/mesh_ops.c

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_queries.c
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_queries.c	2012-10-14 04:22:38 UTC (rev 51307)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_queries.c	2012-10-14 04:42:11 UTC (rev 51308)
@@ -324,6 +324,44 @@
 }
 
 /**
+ * Given a edge and a loop (assumes the edge is manifold). returns
+ * the other faces loop, sharing the same vertex.
+ *
+ * <pre>
+ * +-------------------+
+ * |                   |
+ * |                   |
+ * |l_other <-- return |
+ * +-------------------+ <-- A manifold edge between 2 faces
+ * |l    e  <-- edge   |
+ * |^ <-------- loop   |
+ * |                   |
+ * +-------------------+
+ * </pre>
+ */
+BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l)
+{
+	BMLoop *l_other;
+
+	BLI_assert(BM_edge_is_manifold(e));
+	BLI_assert(BM_vert_in_edge(e, l->v));
+
+	l_other = (e->l == l) ? l->radial_next : l;
+
+	if (l_other->v == l->v) {
+		/* pass */
+	}
+	else if (l_other->next->v == l->v) {
+		l_other = l_other->next;
+	}
+	else {
+		BLI_assert(0);
+	}
+
+	return l_other;
+}
+
+/**
  * The function takes a vertex at the center of a fan and returns the opposite edge in the fan.
  * All edges in the fan must be manifold, otherwise return NULL.
  *

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_queries.h
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_queries.h	2012-10-14 04:22:38 UTC (rev 51307)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_queries.h	2012-10-14 04:42:11 UTC (rev 51308)
@@ -40,6 +40,7 @@
 int     BM_edge_face_pair(BMEdge *e, BMFace **r_fa, BMFace **r_fb);
 int     BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb);
 BMVert *BM_edge_other_vert(BMEdge *e, BMVert *v);
+BMLoop *BM_edge_other_loop(BMEdge *e, BMLoop *l);
 BMLoop *BM_face_other_edge_loop(BMFace *f, BMEdge *e, BMVert *v);
 BMLoop *BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v);
 BMLoop *BM_loop_other_vert_loop(BMLoop *l, BMVert *v);

Modified: trunk/blender/source/blender/editors/mesh/editmesh_rip.c
===================================================================
--- trunk/blender/source/blender/editors/mesh/editmesh_rip.c	2012-10-14 04:22:38 UTC (rev 51307)
+++ trunk/blender/source/blender/editors/mesh/editmesh_rip.c	2012-10-14 04:42:11 UTC (rev 51308)
@@ -382,6 +382,140 @@
 }
 /* --- end 'ripsel' selection handling code --- */
 
+
+/* --- face-fill code --- */
+/**
+ * return an un-ordered array of loop pairs
+ * use for rebuilding face-fill
+ */
+
+typedef struct UnorderedLoopPair {
+	BMLoop *l_pair[2];
+	char    flag;
+} UnorderedLoopPair;
+enum {
+	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;
+	}
+}
+
+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(bm, f_verts, f_verts[3] ? 4 : 3, &f) == FALSE);
+
+			f = BM_face_create_quad_tri_v(bm, f_verts, f_verts[3] ? 4 : 3, f_example, FALSE);
+
+			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, ulp->l_pair[0]),       l_iter); l_iter = l_iter->next;
+				BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, ulp->l_pair[1]->next), l_iter); l_iter = l_iter->next;
+				BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, ulp->l_pair[1]),       l_iter); l_iter = l_iter->next;
+				BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, ulp->l_pair[0]->next), l_iter);
+			}
+			else {
+				if (v_shared == f_verts[0]) {
+					BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, ulp->l_pair[0]->next), l_iter); l_iter = l_iter->next;
+					BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, ulp->l_pair[0]),       l_iter); l_iter = l_iter->next;
+					BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, ulp->l_pair[1]->next), l_iter); l_iter = l_iter->next;
+				}
+				else {
+					BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, ulp->l_pair[1]),       l_iter); l_iter = l_iter->next;
+					BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, ulp->l_pair[0]),       l_iter); l_iter = l_iter->next;
+					BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, ulp->l_pair[0]->next), l_iter); l_iter = l_iter->next;
+				}
+			}
+
+		}
+	}
+}
+
+/* --- end 'face-fill' code --- */
+
+
 static int edbm_rip_call_edgesplit(BMEditMesh *em, wmOperator *op)
 {
 	BMOperator bmop;
@@ -404,6 +538,8 @@
  */
 static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event)
 {
+	const int do_fill = RNA_boolean_get(op->ptr, "use_fill");
+	UnorderedLoopPair *fill_uloop_pairs = NULL;
 	Object *obedit = CTX_data_edit_object(C);
 	ARegion *ar = CTX_wm_region(C);
 	RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -612,32 +748,58 @@
 		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 */
+
 	/* rip two adjacent edges */
 	if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) {
+		/* Don't run the edge split operator in this case */
+
+		BM_elem_flag_enable(e2, BM_ELEM_TAG);  /* only for face-fill (we don't call the operator) */
+
+		/* keep directly before edgesplit */
+		if (do_fill) {
+			fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
+		}
+
 		l = e2->l;
 		ripvert = BM_face_vert_separate(bm, l->f, v);
 
 		BLI_assert(ripvert);
 		if (!ripvert) {
+			if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs);
 			return OPERATOR_CANCELLED;
 		}
 	}
-	else if (BM_edge_is_manifold(e2)) {
-		l = e2->l;
-		e = BM_face_other_edge_loop(l->f, e2, v)->e;
-		BM_elem_flag_enable(e, BM_ELEM_TAG);
+	else {
+		if (BM_edge_is_manifold(e2)) {
+			l = e2->l;
+			e = BM_face_other_edge_loop(l->f, e2, v)->e;
+			BM_elem_flag_enable(e, BM_ELEM_TAG);
 
-		l = e2->l->radial_next;
-		e = BM_face_other_edge_loop(l->f, e2, v)->e;
-		BM_elem_flag_enable(e, BM_ELEM_TAG);
+			l = e2->l->radial_next;
+			e = BM_face_other_edge_loop(l->f, e2, v)->e;
+			BM_elem_flag_enable(e, BM_ELEM_TAG);
+		}
+		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 (!edbm_rip_call_edgesplit(em, op)) {
+			if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs);
+			return OPERATOR_CANCELLED;
+		}
 	}
 
 	dist = FLT_MAX;
 
-	if (!edbm_rip_call_edgesplit(em, op)) {
-		return OPERATOR_CANCELLED;
-	}
-	else {
+	{
 		/* --- select which vert --- */
 		BMVert *v_best = NULL;
 		float l_prev_co[3], l_next_co[3], l_corner_co[3];
@@ -679,6 +841,12 @@
 		}
 	}
 
+	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) {
 		BKE_report(op->reports, RPT_ERROR, "No vertices could be ripped");
 		return OPERATOR_CANCELLED;
@@ -692,6 +860,8 @@
  */
 static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event)
 {
+	const int do_fill = RNA_boolean_get(op->ptr, "use_fill");
+	UnorderedLoopPair *fill_uloop_pairs = NULL;
 	Object *obedit = CTX_data_edit_object(C);
 	ARegion *ar = CTX_wm_region(C);
 	RegionView3D *rv3d = CTX_wm_region_view3d(C);
@@ -765,6 +935,7 @@
 						l = BM_face_other_edge_loop(l->f, l->e, v);
 
 					if (l) {
+						BLI_assert(!BM_elem_flag_test(l->e, BM_ELEM_TAG));
 						BM_elem_flag_enable(l->e, BM_ELEM_TAG);
 					}
 				}
@@ -773,13 +944,20 @@
 				e = BM_vert_other_disk_edge(v, e2);
 
 				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);
+	}
+
 	if (!edbm_rip_call_edgesplit(em, op)) {
+		if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs);
 		return OPERATOR_CANCELLED;
 	}
 
@@ -792,6 +970,11 @@
 	                            ar, projectMat, fmval);
 	MEM_freeN(eloop_pairs);
 
+	if (do_fill && fill_uloop_pairs) {

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list