[Bf-blender-cvs] SVN commit: /data/svn/bf-blender [44758] trunk/blender/source/blender: BMesh: rewrite edge split code (used by edge split modifier and rip tool)

Campbell Barton ideasman42 at gmail.com
Fri Mar 9 04:16:53 CET 2012


Revision: 44758
          http://projects.blender.org/scm/viewvc.php?view=rev&root=bf-blender&revision=44758
Author:   campbellbarton
Date:     2012-03-09 03:16:39 +0000 (Fri, 09 Mar 2012)
Log Message:
-----------
BMesh: rewrite edge split code (used by edge split modifier and rip tool)
this fixes but [#30461] where the same vertex was added to some faces twice.

Previous code rebuilt all faces around the split edges, replace this with much simpler code that uses existing bmesh API for splitting.

This also gives a performance boost to the modifier (over 30x faster in the bug-report file).

Modified Paths:
--------------
    trunk/blender/source/blender/bmesh/intern/bmesh_core.c
    trunk/blender/source/blender/bmesh/intern/bmesh_core.h
    trunk/blender/source/blender/bmesh/intern/bmesh_opdefines.c
    trunk/blender/source/blender/bmesh/operators/bmo_edgesplit.c
    trunk/blender/source/blender/editors/mesh/bmesh_tools.c

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_core.c
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_core.c	2012-03-09 00:41:09 UTC (rev 44757)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_core.c	2012-03-09 03:16:39 UTC (rev 44758)
@@ -41,8 +41,6 @@
  * TESTING ONLY! */
 // #define USE_DEBUG_INDEX_MEMCHECK
 
-static int bm_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep);
-
 #ifdef USE_DEBUG_INDEX_MEMCHECK
 #define DEBUG_MEMCHECK_INDEX_INVALIDATE(ele)               \
 	{                                                      \
@@ -1748,7 +1746,7 @@
  *
  * \return Success
  */
-int bm_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len)
+int bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len)
 {
 	BMEdge **stack = NULL;
 	BLI_array_declare(stack);
@@ -1856,11 +1854,11 @@
 	for (i = 0; i < e_in_len; i++) {
 		BMEdge *e = e_in[i];
 		if (e->l && BM_vert_in_edge(e, v)) {
-			bm_edge_separate(bm, e, e->l);
+			bmesh_edge_separate(bm, e, e->l);
 		}
 	}
 
-	return bm_vert_separate(bm, v, r_vout, r_vout_len);
+	return bmesh_vert_separate(bm, v, r_vout, r_vout_len);
 }
 
 /**
@@ -1911,7 +1909,7 @@
  * \note Does nothing if \a l_sep is already the only loop in the
  * edge radial.
  */
-static int bm_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep)
+int bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep)
 {
 	BMEdge *ne;
 	int radlen;
@@ -1959,8 +1957,8 @@
 
 	/* peel the face from the edge radials on both sides of the
 	 * loop vert, disconnecting the face from its fan */
-	bm_edge_separate(bm, sl->e, sl);
-	bm_edge_separate(bm, sl->prev->e, sl->prev);
+	bmesh_edge_separate(bm, sl->e, sl);
+	bmesh_edge_separate(bm, sl->prev->e, sl->prev);
 
 	if (bmesh_disk_count(sv) == 2) {
 		/* If there are still only two edges out of sv, then
@@ -1978,7 +1976,7 @@
 
 	/* Split all fans connected to the vert, duplicating it for
 	 * each fans. */
-	bm_vert_separate(bm, sv, &vtar, &len);
+	bmesh_vert_separate(bm, sv, &vtar, &len);
 
 	/* There should have been at least two fans cut apart here,
 	 * otherwise the early exit would have kicked in. */

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_core.h
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_core.h	2012-03-09 00:41:09 UTC (rev 44757)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_core.h	2012-03-09 03:16:39 UTC (rev 44758)
@@ -41,7 +41,10 @@
 void    BM_vert_kill(BMesh *bm, BMVert *v);
 
 int     BM_edge_splice(BMesh *bm, BMEdge *e, BMEdge *etarget);
+int     bmesh_edge_separate(BMesh *bm, BMEdge *e, BMLoop *l_sep);
 
+int     bmesh_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len);
+
 int     bmesh_loop_reverse(BMesh *bm, BMFace *f);
 
 BMFace *BM_faces_join(BMesh *bm, BMFace **faces, int totface);

Modified: trunk/blender/source/blender/bmesh/intern/bmesh_opdefines.c
===================================================================
--- trunk/blender/source/blender/bmesh/intern/bmesh_opdefines.c	2012-03-09 00:41:09 UTC (rev 44757)
+++ trunk/blender/source/blender/bmesh/intern/bmesh_opdefines.c	2012-03-09 03:16:39 UTC (rev 44758)
@@ -890,8 +890,7 @@
 static BMOpDefine bmo_edgesplit_def = {
 	"edgesplit",
 	{{BMO_OP_SLOT_ELEMENT_BUF, "edges"}, /* input edges */
-	 {BMO_OP_SLOT_ELEMENT_BUF, "edgeout1"}, /* old output disconnected edges */
-	 {BMO_OP_SLOT_ELEMENT_BUF, "edgeout2"}, /* new output disconnected edges */
+	 {BMO_OP_SLOT_ELEMENT_BUF, "edgeout"}, /* old output disconnected edges */
 	 {0} /* null-terminating sentine */},
 	bmo_edgesplit_exec,
 	BMO_OP_FLAG_UNTAN_MULTIRES

Modified: trunk/blender/source/blender/bmesh/operators/bmo_edgesplit.c
===================================================================
--- trunk/blender/source/blender/bmesh/operators/bmo_edgesplit.c	2012-03-09 00:41:09 UTC (rev 44757)
+++ trunk/blender/source/blender/bmesh/operators/bmo_edgesplit.c	2012-03-09 03:16:39 UTC (rev 44758)
@@ -15,208 +15,21 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  *
- * Contributor(s): Joseph Eagar
+ * Contributor(s): Campbell Barton
  *
  * ***** END GPL LICENSE BLOCK *****
  */
 
-#include <string.h> /* for memcpy */
-
 #include "MEM_guardedalloc.h"
 
-#include "BLI_array.h"
-
 #include "bmesh.h"
 
 #include "intern/bmesh_operators_private.h" /* own include */
 
-typedef struct EdgeTag {
-	BMVert *newv1, *newv2;
-	BMEdge *newe1, *newe2;
-} EdgeTag;
-
-/* (EDGE_DEL == FACE_DEL) - this must be the case */
 enum {
-	EDGE_DEL   = 1,
-	EDGE_SEAM  = 2,
-	EDGE_MARK  = 4,
-	EDGE_RET1  = 8,
-	EDGE_RET2  = 16
+	EDGE_SEAM  = 1
 };
 
-enum {
-	FACE_DEL  = EDGE_DEL,
-	FACE_NEW  = 2
-};
-
-static BMFace *remake_face(BMesh *bm, EdgeTag *etags, BMFace *f, BMVert **f_verts, BMEdge **edges_tmp)
-{
-	BMIter liter1, liter2;
-	EdgeTag *et;
-	BMFace *f2;
-	BMLoop *l, *l2;
-	BMEdge *e;
-	BMVert *lastv1, *lastv2 /* , *v1, *v2 */ /* UNUSED */;
-	int i;
-
-	/* we do final edge last */
-	lastv1 = f_verts[f->len - 1];
-	lastv2 = f_verts[0];
-	/* v1 = f_verts[0]; */ /* UNUSED */
-	/* v2 = f_verts[1]; */ /* UNUSED */
-	for (i = 0; i < f->len - 1; i++) {
-		e = BM_edge_create(bm, f_verts[i], f_verts[i + 1], NULL, TRUE);
-		if (!e) {
-			return NULL;
-		}
-		edges_tmp[i] = e;
-	}
-
-	edges_tmp[i] = BM_edge_create(bm, lastv1, lastv2, NULL, TRUE);
-
-	f2 = BM_face_create(bm, f_verts, edges_tmp, f->len, FALSE);
-	if (!f2) {
-		return NULL;
-	}
-
-	BM_elem_attrs_copy(bm, bm, f, f2);
-
-	l = BM_iter_new(&liter1, bm, BM_LOOPS_OF_FACE, f);
-	l2 = BM_iter_new(&liter2, bm, BM_LOOPS_OF_FACE, f2);
-	for ( ; l && l2; l = BM_iter_step(&liter1), l2 = BM_iter_step(&liter2)) {
-		BM_elem_attrs_copy(bm, bm, l, l2);
-		if (l->e != l2->e) {
-			/* set up data for figuring out the two sides of
-			 * the split */
-
-			/* set edges index as dirty after running all */
-			BM_elem_index_set(l2->e, BM_elem_index_get(l->e)); /* set_dirty! */
-			et = &etags[BM_elem_index_get(l->e)];
-			
-			if (!et->newe1) {
-				et->newe1 = l2->e;
-			}
-			else if (!et->newe2) {
-				et->newe2 = l2->e;
-			}
-			else {
-				/* Only two new edges should be created from each original edge
-				 *  for edge split operation */
-
-				//BLI_assert(et->newe1 == l2->e || et->newe2 == l2->e);
-				et->newe2 = l2->e;
-			}
-
-			if (BMO_elem_flag_test(bm, l->e, EDGE_SEAM)) {
-				BMO_elem_flag_enable(bm, l2->e, EDGE_SEAM);
-			}
-
-			BM_elem_attrs_copy(bm, bm, l->e, l2->e);
-		}
-
-		BMO_elem_flag_enable(bm, l->e, EDGE_MARK);
-		BMO_elem_flag_enable(bm, l2->e, EDGE_MARK);
-	}
-
-	return f2;
-}
-
-static void tag_out_edges(BMesh *bm, EdgeTag *etags, BMOperator *UNUSED(op))
-{
-	EdgeTag *et;
-	BMIter iter;
-	BMLoop *l, *l_start, *l_prev;
-	BMEdge *e;
-	BMVert *v;
-	int i, ok;
-	
-	ok = 0;
-	while (ok++ < 100000) {
-		BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
-			if (!BMO_elem_flag_test(bm, e, EDGE_SEAM))
-				continue;
-
-			if (e->l) {
-				break;
-			}
-		}
-		
-		if (!e) {
-			break;
-		}
-
-		/* ok we found an edge, part of a region of splits we need
-		 * to identify.  now walk along it */
-		for (i = 0; i < 2; i++) {
-			l = e->l;
-			
-			v = i ? l->next->v : l->v;
-
-			while (1) {
-				et = &etags[BM_elem_index_get(l->e)];
-				if (et->newe1 == l->e) {
-					if (et->newe1) {
-						BMO_elem_flag_enable(bm, et->newe1, EDGE_RET1);
-						BMO_elem_flag_disable(bm, et->newe1, EDGE_SEAM);
-					}
-					if (et->newe2) {
-						BMO_elem_flag_enable(bm, et->newe2, EDGE_RET2);
-						BMO_elem_flag_disable(bm, et->newe2, EDGE_SEAM);
-					}
-				}
-				else {
-					if (et->newe1) {
-						BMO_elem_flag_enable(bm, et->newe1, EDGE_RET2);
-						BMO_elem_flag_disable(bm, et->newe1, EDGE_SEAM);
-					}
-					if (et->newe2) {
-						BMO_elem_flag_enable(bm, et->newe2, EDGE_RET1);
-						BMO_elem_flag_disable(bm, et->newe2, EDGE_SEAM);
-					}
-				}
-
-				/* If the original edge was non-manifold edges, then it is
-				 * possible l->e is not et->newe1 or et->newe2. So always clear
-				 * the flag on l->e as well, to prevent infinite looping. */
-				BMO_elem_flag_disable(bm, l->e, EDGE_SEAM);
-				l_start = l;
-
-				do {
-					/* l_prev checks stops us from looping over the same edge forever [#30459] */
-					l_prev = l;
-					l = BM_face_other_edge_loop(l->f, l->e, v);
-					if (l == l_start || BM_edge_face_count(l->e) != 2) {
-						break;
-					}
-					l = l->radial_next;
-				} while (l != l_start && l != l_prev && !BMO_elem_flag_test(bm, l->e, EDGE_SEAM));
-				
-				if (l == l_start || !BMO_elem_flag_test(bm, l->e, EDGE_SEAM)) {
-					break;
-				}
-
-				v = (l->v == v) ? l->next->v : l->v;
-			}
-		}
-	}
-}
-
-/* helper functions for edge tag's */
-BM_INLINE BMVert *bm_edge_tag_vert_get(EdgeTag *et, BMVert *v, BMLoop *l)
-{
-	return (l->e->v1 == v) ? et->newv1 : et->newv2;
-}
-
-BM_INLINE void bm_edge_tag_vert_set(EdgeTag *et, BMVert *v, BMLoop *l, BMVert *vset)
-{
-	if (l->e->v1 == v) {
-		et->newv1 = vset;
-	}
-	else {
-		et->newv2 = vset;
-	}
-}
-
 /**
  * Remove the EDGE_SEAM flag for edges we cant split
  *
@@ -238,6 +51,11 @@
 
 	/* tag all boundry verts so as not to untag an edge which is inbetween only 2 faces [] */
 	BM_ITER(e, &iter, bm, BM_EDGES_OF_MESH, NULL) {
+
+		/* unrelated to flag assignment in this function - since this is the
+		 * only place we loop over all edges, disable tag */
+		BM_elem_flag_disable(e, BM_ELEM_INTERNAL_TAG);
+
 		if (BM_edge_is_boundary(e)) {
 			vt = &vtouch[BM_elem_index_get(e->v1)]; if (*vt < 2) (*vt)++;
 			vt = &vtouch[BM_elem_index_get(e->v2)]; if (*vt < 2) (*vt)++;
@@ -270,202 +88,36 @@
 
 void bmo_edgesplit_exec(BMesh *bm, BMOperator *op)
 {
-	EdgeTag *etags, *et; /* edge aligned array of tags */
-	BMIter iter, liter;
-	BMFace *f, *f2;
-	BMLoop *l, *l2, *l3;
-	BMLoop *l_next, *l_prev;
+	BMOIter siter;
 	BMEdge *e;
-	BMVert *v, *v2;
 
-	/* face/vert aligned vert array */
-	BMVert **f_verts = NULL;
-	BLI_array_declare(f_verts);
-
-	BMEdge **edges_tmp = NULL;
-	BLI_array_declare(edges_tmp);
-	int i, j;
-
 	BMO_slot_buffer_flag_enable(bm, op, "edges", EDGE_SEAM, BM_EDGE);
 
 	bm_edgesplit_validate_seams(bm, op);
 
-	etags = MEM_callocN(sizeof(EdgeTag) * bm->totedge, "EdgeTag");
+	BMO_ITER(e, &siter, bm, op, "edges", BM_EDGE) {
+		if (BMO_elem_flag_test(bm, e, EDGE_SEAM)) {
+			/* this flag gets copied so we can be sure duplicate edges get it too (important) */
+			BM_elem_flag_enable(e, BM_ELEM_INTERNAL_TAG);
 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list