| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * ***** BEGIN GPL LICENSE BLOCK ***** | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is free software; you can redistribute it and/or | 
					
						
							|  |  |  |  * modify it under the terms of the GNU General Public License | 
					
						
							|  |  |  |  * as published by the Free Software Foundation; either version 2 | 
					
						
							|  |  |  |  * of the License, or (at your option) any later version. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This program is distributed in the hope that it will be useful, | 
					
						
							|  |  |  |  * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
					
						
							|  |  |  |  * GNU General Public License for more details. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * You should have received a copy of the GNU General Public License | 
					
						
							|  |  |  |  * along with this program; if not, write to the Free Software Foundation, | 
					
						
							|  |  |  |  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is Copyright (C) 2004 by Blender Foundation. | 
					
						
							|  |  |  |  * All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The Original Code is: all of this file. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Contributor(s): Joseph Eagar | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * ***** END GPL LICENSE BLOCK ***** | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** \file blender/editors/mesh/editmesh_rip.c
 | 
					
						
							|  |  |  |  *  \ingroup edmesh | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "MEM_guardedalloc.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 16:20:07 +00:00
										 |  |  | #include "DNA_scene_types.h"
 | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | #include "DNA_object_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "RNA_define.h"
 | 
					
						
							|  |  |  | #include "RNA_access.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "BLI_math.h"
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | #include "BLI_array.h"
 | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | #include "BKE_context.h"
 | 
					
						
							|  |  |  | #include "BKE_object.h"
 | 
					
						
							|  |  |  | #include "BKE_report.h"
 | 
					
						
							|  |  |  | #include "BKE_tessmesh.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 16:57:50 +00:00
										 |  |  | #include "WM_api.h"
 | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | #include "WM_types.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "ED_mesh.h"
 | 
					
						
							|  |  |  | #include "ED_screen.h"
 | 
					
						
							|  |  |  | #include "ED_transform.h"
 | 
					
						
							|  |  |  | #include "ED_view3d.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "mesh_intern.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | /**
 | 
					
						
							|  |  |  |  * helper to find edge for edge_rip, | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * \param inset is used so we get some useful distance | 
					
						
							|  |  |  |  * when comparing multiple edges that meet at the same | 
					
						
							|  |  |  |  * point and would result in teh same distance. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | #define INSET_DEFAULT 0.00001f
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | static float edbm_rip_edgedist(ARegion *ar, float mat[][4], | 
					
						
							|  |  |  |                                const float co1[3], const float co2[3], const float mvalf[2], | 
					
						
							|  |  |  |                                const float inset) | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-08 07:08:29 +00:00
										 |  |  | 	float vec1[2], vec2[2]; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-20 04:56:24 +00:00
										 |  |  | 	ED_view3d_project_float_v2_m4(ar, co1, vec1, mat); | 
					
						
							|  |  |  | 	ED_view3d_project_float_v2_m4(ar, co2, vec2, mat); | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | 	if (inset != 0.0f) { | 
					
						
							|  |  |  | 		const float dist = inset / len_v2v2(vec1, vec2); | 
					
						
							|  |  |  | 		interp_v2_v2v2(vec1, vec1, vec2, dist); | 
					
						
							|  |  |  | 		interp_v2_v2v2(vec2, vec2, vec1, dist); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 08:44:35 +00:00
										 |  |  | 	/* TODO: use dist_squared_to_line_segment_v2() looks like we only ever use for comparison */ | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 	return dist_to_line_segment_v2(mvalf, vec1, vec2); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | static float edbm_rip_linedist(ARegion *ar, float mat[][4], | 
					
						
							|  |  |  |                                const float co1[3], const float co2[3], const float mvalf[2]) | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	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); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 21:47:32 +00:00
										 |  |  | static float edbm_rip_edge_side_measure(BMEdge *e, BMLoop *e_l, | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  |                                         ARegion *ar, | 
					
						
							|  |  |  |                                         float projectMat[4][4], const float fmval[2]) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	BMVert *v1_other; | 
					
						
							|  |  |  | 	BMVert *v2_other; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 21:47:32 +00:00
										 |  |  | 	BLI_assert(BM_vert_in_edge(e, e_l->v)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 	/* 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 */ | 
					
						
							| 
									
										
										
										
											2012-04-19 21:47:32 +00:00
										 |  |  | 	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; | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 	mid_v3_v3v3(cent, v1_other->co, v2_other->co); | 
					
						
							|  |  |  | 	mid_v3_v3v3(mid, e->v1->co, e->v2->co); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-20 04:56:24 +00:00
										 |  |  | 	ED_view3d_project_float_v2_m4(ar, cent, cent, projectMat); | 
					
						
							|  |  |  | 	ED_view3d_project_float_v2_m4(ar, mid, mid, projectMat); | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-20 04:56:24 +00:00
										 |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	sub_v2_v2v2(vec, cent, mid); | 
					
						
							|  |  |  | 	normalize_v2(vec); | 
					
						
							|  |  |  | 	mul_v2_fl(vec, 0.01f); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 08:44:35 +00:00
										 |  |  | 	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)) | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-04-28 15:42:27 +00:00
										 |  |  | 		return score; | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	else { | 
					
						
							|  |  |  | 		return -score; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - Advanced selection handling 'ripsel' functions ----- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * How rip selection works | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Firstly - rip is basically edge split with side-selection & grab. | 
					
						
							|  |  |  |  * Things would be much more simple if we didn't have to worry about side selection | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * The method used for checking the side of selection is as follows... | 
					
						
							|  |  |  |  * - First tag all rip-able edges. | 
					
						
							|  |  |  |  * - Build a contiguous edge list by looping over tagged edges and following each ones tagged siblings in both | 
					
						
							|  |  |  |  *   directions. | 
					
						
							|  |  |  |  *   - The loops are not stored in an array, Instead both loops on either side of each edge has its index values set | 
					
						
							|  |  |  |  *     to count down from the last edge, this way, once we have the 'last' edge its very easy to walk down the | 
					
						
							|  |  |  |  *     connected edge loops. | 
					
						
							|  |  |  |  *     The reason for using loops like this is because when the edges are split we don't which face user gets the newly | 
					
						
							|  |  |  |  *     created edge (its as good as random so we cant assume new edges will be on once side). | 
					
						
							| 
									
										
										
										
											2012-05-20 21:23:26 +00:00
										 |  |  |  *     After splitting, its very simple to walk along boundary loops since each only has one edge from a single side. | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  |  * - The end loop pairs are stored in an array however to support multiple edge-selection-islands, so you can rip | 
					
						
							|  |  |  |  *   multiple selections at once. | 
					
						
							|  |  |  |  * - * Execute the split * | 
					
						
							|  |  |  |  * - For each #EdgeLoopPair walk down both sides of the split using the loops and measure which is facing the mouse. | 
					
						
							|  |  |  |  * - Deselect the edge loop facing away. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Limitation! | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  |  * This currently works very poorly with intersecting edge islands (verts with more then 2 tagged edges) | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  |  * This is nice to but for now not essential. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * - campbell. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #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 */ | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | static BMEdge *edbm_ripsel_edge_mark_step(BMVert *v, const int uid) | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	BMIter iter; | 
					
						
							|  |  |  | 	BMEdge *e; | 
					
						
							| 
									
										
										
										
											2012-04-19 13:47:58 +00:00
										 |  |  | 	BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		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); | 
					
						
							|  |  |  | 			BM_elem_index_set(l_b, uid); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return e; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef struct EdgeLoopPair { | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  | 	/* initialize loops with dummy invalid index values */ | 
					
						
							| 
									
										
										
										
											2012-04-19 13:47:58 +00:00
										 |  |  | 	BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { | 
					
						
							|  |  |  | 		BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 			BM_elem_index_set(l, INVALID_UID); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  | 	/* set contiguous loops ordered 'uid' values for walking after split */ | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 	while (TRUE) { | 
					
						
							|  |  |  | 		int tot = 0; | 
					
						
							|  |  |  | 		BMIter eiter; | 
					
						
							|  |  |  | 		BMEdge *e_step; | 
					
						
							|  |  |  | 		BMVert *v_step; | 
					
						
							|  |  |  | 		BMEdge *e; | 
					
						
							|  |  |  | 		BMEdge *e_first; | 
					
						
							|  |  |  | 		BMEdge *e_last; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		e_first = NULL; | 
					
						
							| 
									
										
										
										
											2012-04-19 13:47:58 +00:00
										 |  |  | 		BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 			if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) { | 
					
						
							|  |  |  | 				e_first = e; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (e_first == NULL) { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  | 		/* initialize  */ | 
					
						
							| 
									
										
										
										
											2012-04-20 18:50:18 +00:00
										 |  |  | 		e_first = e; | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		v_step = e_first->v1; | 
					
						
							| 
									
										
										
										
											2012-04-20 18:50:18 +00:00
										 |  |  | 		e_step = NULL; /* quiet warning, will never remain this value */ | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		uid_start = uid; | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | 		while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) { | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 			v_step = BM_edge_other_vert((e_step = e), v_step); | 
					
						
							|  |  |  | 			uid++; /* only different line */ | 
					
						
							|  |  |  | 			tot++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  | 		/* this edges loops have the highest uid's, store this to walk down later */ | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		e_last = e_step; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  | 		/* always store the highest 'uid' edge for the stride */ | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		uid_end = uid - 1; | 
					
						
							|  |  |  | 		uid = uid_start - 1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  | 		/* initialize */ | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		v_step = e_first->v1; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | 		while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) { | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 			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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-28 15:14:16 +00:00
										 |  |  | 		BLI_array_grow_one(eloop_pairs); | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		lp = &eloop_pairs[BLI_array_count(eloop_pairs) - 1]; | 
					
						
							|  |  |  | 		BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b); /* no need to check, we know this will be true */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		BLI_assert(tot == uid_end - uid_start); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #if 0
 | 
					
						
							|  |  |  | 		printf("%s: found contiguous edge loop of (%d)\n", __func__, uid_end - uid_start); | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* null terminate */ | 
					
						
							| 
									
										
										
										
											2012-04-28 15:14:16 +00:00
										 |  |  | 	BLI_array_grow_one(eloop_pairs); | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 	lp = &eloop_pairs[BLI_array_count(eloop_pairs) - 1]; | 
					
						
							|  |  |  | 	lp->l_a = lp->l_b = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return eloop_pairs; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* - De-Select the worst rip-edge side -------------------------------- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | static BMEdge *edbm_ripsel_edge_uid_step(BMEdge *e_orig, BMVert **v_prev) | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 13:47:58 +00:00
										 |  |  | 	BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		if (BM_elem_index_get(e->l) == uid_cmp) { | 
					
						
							|  |  |  | 			*v_prev = v; | 
					
						
							|  |  |  | 			return e; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | static BMVert *edbm_ripsel_edloop_pair_start_vert(BMEdge *e) | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | { | 
					
						
							|  |  |  | 	/* try step in a direction, if it fails we know do go the other way */ | 
					
						
							|  |  |  | 	BMVert *v_test = e->v1; | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | 	return (edbm_ripsel_edge_uid_step(e, &v_test)) ? e->v1 : e->v2; | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | 		v_prev = edbm_ripsel_edloop_pair_start_vert(e); | 
					
						
							|  |  |  | 		for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { | 
					
						
							| 
									
										
										
										
											2012-04-19 21:47:32 +00:00
										 |  |  | 			score_a += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval); | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		e = lp->l_b->e; | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | 		v_prev = edbm_ripsel_edloop_pair_start_vert(e); | 
					
						
							|  |  |  | 		for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { | 
					
						
							| 
									
										
										
										
											2012-04-19 21:47:32 +00:00
										 |  |  | 			score_b += edbm_rip_edge_side_measure(e, e->l, ar, projectMat, fmval); | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		e = (score_a > score_b) ? lp->l_a->e : lp->l_b->e; | 
					
						
							| 
									
										
										
										
											2012-04-19 14:38:09 +00:00
										 |  |  | 		v_prev = edbm_ripsel_edloop_pair_start_vert(e); | 
					
						
							|  |  |  | 		for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) { | 
					
						
							| 
									
										
										
										
											2012-04-20 16:55:47 +00:00
										 |  |  | 			BM_edge_select_set(bm, e, FALSE); | 
					
						
							| 
									
										
										
										
											2012-04-17 18:14:31 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /* --- end 'ripsel' selection handling code --- */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | /* --- face-fill code --- */ | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * return an un-ordered array of loop pairs | 
					
						
							|  |  |  |  * use for rebuilding face-fill | 
					
						
							| 
									
										
										
										
											2012-10-15 03:27:05 +00:00
										 |  |  |  * | 
					
						
							|  |  |  |  * \note the method currenly used fails for edges with 3+ face users and gives | 
					
						
							|  |  |  |  *       nasty holes in the mesh, there isnt a good way of knowing ahead of time | 
					
						
							|  |  |  |  *       which loops will be split apart (its possible to figure out but quite involved). | 
					
						
							|  |  |  |  *       So for now this is a known limitation of current rip-fill option. | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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; | 
					
						
							| 
									
										
										
										
											2012-10-15 03:36:22 +00:00
										 |  |  | 					BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, ulp->l_pair[1]->next), l_iter); | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				else { | 
					
						
							|  |  |  | 					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; | 
					
						
							| 
									
										
										
										
											2012-10-15 03:36:22 +00:00
										 |  |  | 					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]),       l_iter); | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* --- end 'face-fill' code --- */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | static int edbm_rip_call_edgesplit(BMEditMesh *em, wmOperator *op) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	BMOperator bmop; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-30 15:27:13 +00:00
										 |  |  | 	if (!EDBM_op_init(em, &bmop, op, "split_edges edges=%he verts=%hv use_verts=%b", | 
					
						
							| 
									
										
										
										
											2012-05-20 19:49:27 +00:00
										 |  |  | 	                  BM_ELEM_TAG, BM_ELEM_SELECT, TRUE)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		return FALSE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	BMO_op_exec(em->bm, &bmop); | 
					
						
							|  |  |  | 	if (!EDBM_op_finish(em, &bmop, op, TRUE)) { | 
					
						
							|  |  |  | 		return FALSE; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return TRUE; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This is the main vert ripping function (rip when one vertex is selected) | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int edbm_rip_invoke__vert(bContext *C, wmOperator *op, wmEvent *event) | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	const int do_fill = RNA_boolean_get(op->ptr, "use_fill"); | 
					
						
							|  |  |  | 	UnorderedLoopPair *fill_uloop_pairs = NULL; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 	Object *obedit = CTX_data_edit_object(C); | 
					
						
							|  |  |  | 	ARegion *ar = CTX_wm_region(C); | 
					
						
							|  |  |  | 	RegionView3D *rv3d = CTX_wm_region_view3d(C); | 
					
						
							|  |  |  | 	BMEditMesh *em = BMEdit_FromObject(obedit); | 
					
						
							|  |  |  | 	BMesh *bm = em->bm; | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	BMIter iter, liter; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 	BMLoop *l; | 
					
						
							|  |  |  | 	BMEdge *e, *e2; | 
					
						
							|  |  |  | 	BMVert *v, *ripvert = NULL; | 
					
						
							| 
									
										
										
										
											2012-04-23 15:18:12 +00:00
										 |  |  | 	const int totvert_orig = bm->totvert; | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	int i; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 	float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; | 
					
						
							|  |  |  | 	float dist = FLT_MAX; | 
					
						
							|  |  |  | 	float d; | 
					
						
							| 
									
										
										
										
											2012-09-07 06:31:54 +00:00
										 |  |  | 	int is_wire; | 
					
						
							| 
									
										
										
										
											2012-04-19 16:20:07 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	BMEditSelection ese; | 
					
						
							|  |  |  | 	int totboundary_edge = 0; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	/* find selected vert - same some time and check history first */ | 
					
						
							| 
									
										
										
										
											2012-10-15 03:27:05 +00:00
										 |  |  | 	if (BM_select_history_active_get(bm, &ese) && ese.htype == BM_VERT) { | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		v = (BMVert *)ese.ele; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	else { | 
					
						
							|  |  |  | 		ese.ele = NULL; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | 
					
						
							|  |  |  | 			if (BM_elem_flag_test(v, BM_ELEM_SELECT)) | 
					
						
							|  |  |  | 				break; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	/* this should be impossible, but sanity checks are a good thing */ | 
					
						
							|  |  |  | 	if (!v) | 
					
						
							|  |  |  | 		return OPERATOR_CANCELLED; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-07 06:31:54 +00:00
										 |  |  | 	is_wire = BM_vert_is_wire(v); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	e2 = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (v->e) { | 
					
						
							|  |  |  | 		/* find closest edge to mouse cursor */ | 
					
						
							|  |  |  | 		BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { | 
					
						
							|  |  |  | 			int is_boundary = BM_edge_is_boundary(e); | 
					
						
							|  |  |  | 			/* consider wire as boundary for this purpose,
 | 
					
						
							|  |  |  | 			 * otherwise we can't a face away from a wire edge */ | 
					
						
							|  |  |  | 			totboundary_edge += (is_boundary != 0 || BM_edge_is_wire(e)); | 
					
						
							|  |  |  | 			if (!BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { | 
					
						
							|  |  |  | 				if (is_boundary == FALSE && BM_edge_is_manifold(e)) { | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 					d = edbm_rip_edgedist(ar, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 					if (d < dist) { | 
					
						
							|  |  |  | 						dist = d; | 
					
						
							|  |  |  | 						e2 = e; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | 		/* 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(v) == 3 && | 
					
						
							|  |  |  | 		    BM_vert_edge_count(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); | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 				d = edbm_rip_edgedist(ar, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT); | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if (d < dist) { | 
					
						
							|  |  |  | 					dist = d; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					/* find the edge that is not in this loop */ | 
					
						
							|  |  |  | 					e2 = NULL; | 
					
						
							|  |  |  | 					for (i2 = 0; i2 < 3; i2++) { | 
					
						
							|  |  |  | 						if (!BM_edge_in_loop(e_all[i2], l)) { | 
					
						
							|  |  |  | 							e2 = e_all[i2]; | 
					
						
							|  |  |  | 							break; | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					BLI_assert(e2 != NULL); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 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 then 2, | 
					
						
							| 
									
										
										
										
											2012-09-07 06:31:54 +00:00
										 |  |  | 	 *   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)) | 
					
						
							|  |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		BMVert **vout; | 
					
						
							|  |  |  | 		int vout_len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 16:55:47 +00:00
										 |  |  | 		BM_vert_select_set(bm, v, FALSE); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-23 15:26:06 +00:00
										 |  |  | 		if (bmesh_vert_separate(bm, v, &vout, &vout_len) == FALSE) { | 
					
						
							|  |  |  | 			BKE_report(op->reports, RPT_ERROR, "Error ripping vertex from faces"); | 
					
						
							|  |  |  | 			return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		else if (vout_len < 2) { | 
					
						
							|  |  |  | 			MEM_freeN(vout); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			/* set selection back to avoid active-unselected vertex */ | 
					
						
							| 
									
										
										
										
											2012-04-20 16:55:47 +00:00
										 |  |  | 			BM_vert_select_set(bm, v, TRUE); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			/* should never happen */ | 
					
						
							|  |  |  | 			BKE_report(op->reports, RPT_ERROR, "Error ripping vertex from faces"); | 
					
						
							|  |  |  | 			return OPERATOR_CANCELLED; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		else { | 
					
						
							|  |  |  | 			int vi_best = 0; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			if (ese.ele) { | 
					
						
							| 
									
										
										
										
											2012-10-15 03:27:05 +00:00
										 |  |  | 				BM_select_history_remove(bm, ese.ele); | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			dist = FLT_MAX; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-08 06:40:03 +00:00
										 |  |  | 			/* 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) */ | 
					
						
							| 
									
										
										
										
											2012-09-07 06:46:26 +00:00
										 |  |  | 			for (i = 0; i < vout_len; i++) { | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-07 06:46:26 +00:00
										 |  |  | 				if (BM_vert_is_wire(vout[i]) == FALSE) { | 
					
						
							|  |  |  | 					/* find the best face corner */ | 
					
						
							| 
									
										
										
										
											2012-09-07 06:31:54 +00:00
										 |  |  | 					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]; | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | 							edbm_calc_loop_co(l, l_mid_co); | 
					
						
							| 
									
										
										
										
											2012-09-07 06:31:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 							d = edbm_rip_edgedist(ar, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT); | 
					
						
							| 
									
										
										
										
											2012-09-07 06:31:54 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-07 06:46:26 +00:00
										 |  |  | 							if (d < dist) { | 
					
						
							|  |  |  | 								dist = d; | 
					
						
							|  |  |  | 								vi_best = i; | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				else { | 
					
						
							|  |  |  | 					/* 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 							d = edbm_rip_edgedist(ar, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT); | 
					
						
							| 
									
										
										
										
											2012-09-07 06:46:26 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-07 06:31:54 +00:00
										 |  |  | 							if (d < dist) { | 
					
						
							|  |  |  | 								dist = d; | 
					
						
							|  |  |  | 								vi_best = i; | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			/* select the vert from the best region */ | 
					
						
							|  |  |  | 			v = vout[vi_best]; | 
					
						
							| 
									
										
										
										
											2012-04-20 16:55:47 +00:00
										 |  |  | 			BM_vert_select_set(bm, v, TRUE); | 
					
						
							| 
									
										
										
										
											2012-04-17 18:36:29 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			if (ese.ele) { | 
					
						
							| 
									
										
										
										
											2012-10-15 03:27:05 +00:00
										 |  |  | 				BM_select_history_store(bm, v); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			/* splice all others back together */ | 
					
						
							|  |  |  | 			if (vout_len > 2) { | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 				/* vout[0]  == best
 | 
					
						
							|  |  |  | 				 * vout[1]  == glue | 
					
						
							|  |  |  | 				 * vout[2+] == splice with glue | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				if (vi_best != 0) { | 
					
						
							|  |  |  | 					SWAP(BMVert *, vout[0], vout[vi_best]); | 
					
						
							|  |  |  | 					vi_best = 0; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 				for (i = 2; i < vout_len; i++) { | 
					
						
							|  |  |  | 					BM_vert_splice(bm, vout[i], vout[1]); | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			MEM_freeN(vout); | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			return OPERATOR_FINISHED; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-04-19 23:16:57 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	if (!e2) { | 
					
						
							|  |  |  | 		BKE_report(op->reports, RPT_ERROR, "Selected vertex has no edge/face pairs attached"); | 
					
						
							|  |  |  | 		return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-04-19 21:47:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	/* *** Execute the split! *** */ | 
					
						
							|  |  |  | 	/* unlike edge split, for single vertex split we only use the operator in one of the cases
 | 
					
						
							|  |  |  | 	 * but both allocate fill */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	/* rip two adjacent edges */ | 
					
						
							|  |  |  | 	if (BM_edge_is_boundary(e2) || BM_vert_face_count(v) == 2) { | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 		/* 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); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		l = e2->l; | 
					
						
							|  |  |  | 		ripvert = BM_face_vert_separate(bm, l->f, v); | 
					
						
							| 
									
										
										
										
											2012-04-19 21:47:32 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		BLI_assert(ripvert); | 
					
						
							|  |  |  | 		if (!ripvert) { | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 			if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			return OPERATOR_CANCELLED; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	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); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		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); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 		if (!edbm_rip_call_edgesplit(em, op)) { | 
					
						
							|  |  |  | 			if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); | 
					
						
							|  |  |  | 			return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	dist = FLT_MAX; | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		/* --- select which vert --- */ | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 		BMVert *v_best = NULL; | 
					
						
							|  |  |  | 		float l_prev_co[3], l_next_co[3], l_corner_co[3]; | 
					
						
							|  |  |  | 		float scale; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dist = FLT_MAX; | 
					
						
							| 
									
										
										
										
											2012-10-15 03:27:05 +00:00
										 |  |  | 		BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 			if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { | 
					
						
							|  |  |  | 				/* disable by default, re-enable winner at end */ | 
					
						
							| 
									
										
										
										
											2012-04-20 16:55:47 +00:00
										 |  |  | 				BM_vert_select_set(bm, v, FALSE); | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-19 13:47:58 +00:00
										 |  |  | 				BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 					/* calculate a point in the face, rather then calculate the middle,
 | 
					
						
							|  |  |  | 					 * make a vector pointing between the 2 edges attached to this loop */ | 
					
						
							|  |  |  | 					sub_v3_v3v3(l_prev_co, l->prev->v->co, l->v->co); | 
					
						
							|  |  |  | 					sub_v3_v3v3(l_next_co, l->next->v->co, l->v->co); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					scale = normalize_v3(l_prev_co) + normalize_v3(l_next_co); | 
					
						
							|  |  |  | 					mul_v3_fl(l_prev_co, scale); | 
					
						
							|  |  |  | 					mul_v3_fl(l_next_co, scale); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					add_v3_v3v3(l_corner_co, l_prev_co, l_next_co); | 
					
						
							|  |  |  | 					add_v3_v3(l_corner_co, l->v->co); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 					d = edbm_rip_edgedist(ar, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT); | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 					if (d < dist) { | 
					
						
							|  |  |  | 						v_best = v; | 
					
						
							|  |  |  | 						dist = d; | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if (v_best) { | 
					
						
							| 
									
										
										
										
											2012-04-20 16:55:47 +00:00
										 |  |  | 			BM_vert_select_set(bm, v_best, TRUE); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:59:24 +00:00
										 |  |  | 			if (ese.ele) { | 
					
						
							| 
									
										
										
										
											2012-10-15 03:27:05 +00:00
										 |  |  | 				BM_select_history_store(bm, v_best); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:59:24 +00:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	if (do_fill && fill_uloop_pairs) { | 
					
						
							|  |  |  | 		edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs); | 
					
						
							|  |  |  | 		MEM_freeN(fill_uloop_pairs); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-23 15:18:12 +00:00
										 |  |  | 	if (totvert_orig == bm->totvert) { | 
					
						
							|  |  |  | 		BKE_report(op->reports, RPT_ERROR, "No vertices could be ripped"); | 
					
						
							|  |  |  | 		return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	return OPERATOR_FINISHED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /**
 | 
					
						
							|  |  |  |  * This is the main edge ripping function | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static int edbm_rip_invoke__edge(bContext *C, wmOperator *op, wmEvent *event) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	const int do_fill = RNA_boolean_get(op->ptr, "use_fill"); | 
					
						
							|  |  |  | 	UnorderedLoopPair *fill_uloop_pairs = NULL; | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	Object *obedit = CTX_data_edit_object(C); | 
					
						
							|  |  |  | 	ARegion *ar = CTX_wm_region(C); | 
					
						
							|  |  |  | 	RegionView3D *rv3d = CTX_wm_region_view3d(C); | 
					
						
							|  |  |  | 	BMEditMesh *em = BMEdit_FromObject(obedit); | 
					
						
							|  |  |  | 	BMesh *bm = em->bm; | 
					
						
							|  |  |  | 	BMIter iter, eiter; | 
					
						
							|  |  |  | 	BMLoop *l; | 
					
						
							|  |  |  | 	BMEdge *e, *e2; | 
					
						
							|  |  |  | 	BMVert *v; | 
					
						
							| 
									
										
										
										
											2012-04-23 15:18:12 +00:00
										 |  |  | 	const int totedge_orig = bm->totedge; | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	EdgeLoopPair *eloop_pairs; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | 	/* important this runs on the original selection, before tampering with tagging */ | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	eloop_pairs = edbm_ripsel_looptag_helper(bm); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* expand edge selection */ | 
					
						
							|  |  |  | 	BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { | 
					
						
							| 
									
										
										
										
											2012-10-13 03:54:27 +00:00
										 |  |  | 		int all_manifold; | 
					
						
							|  |  |  | 		int totedge_manifold;  /* manifold, visible edges */ | 
					
						
							|  |  |  | 		int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		e2 = NULL; | 
					
						
							|  |  |  | 		i = 0; | 
					
						
							| 
									
										
										
										
											2012-10-13 03:54:27 +00:00
										 |  |  | 		totedge_manifold = 0; | 
					
						
							|  |  |  | 		all_manifold = TRUE; | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		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)) { | 
					
						
							|  |  |  | 					e2 = e; | 
					
						
							|  |  |  | 					i++; | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-10-13 03:54:27 +00:00
										 |  |  | 				totedge_manifold++; | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			/** #BM_vert_other_disk_edge has no hidden checks so don't check hidden here */ | 
					
						
							| 
									
										
										
										
											2012-10-13 03:54:27 +00:00
										 |  |  | 			if ((all_manifold == TRUE) && (BM_edge_is_manifold(e) == FALSE)) { | 
					
						
							|  |  |  | 				all_manifold = FALSE; | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* single edge, extend */ | 
					
						
							|  |  |  | 		if (i == 1 && e2->l) { | 
					
						
							| 
									
										
										
										
											2012-10-13 03:59:06 +00:00
										 |  |  | 			/* 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)) { | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 				BMLoop *l_a = e2->l; | 
					
						
							|  |  |  | 				BMLoop *l_b = l_a->radial_next; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-13 01:46:57 +00:00
										 |  |  | 				/* find the best face to follow, this way the edge won't point away from
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 				 * the mouse when there are more then 4 (takes the shortest face fan around) */ | 
					
						
							|  |  |  | 				l = (edbm_rip_edge_side_measure(e2, l_a, ar, projectMat, fmval) < | 
					
						
							|  |  |  | 				     edbm_rip_edge_side_measure(e2, l_b, ar, projectMat, fmval)) ? l_a : l_b; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				l = BM_face_other_edge_loop(l->f, e2, v); | 
					
						
							| 
									
										
										
										
											2012-04-23 15:35:07 +00:00
										 |  |  | 				/* 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; | 
					
						
							| 
									
										
										
										
											2012-10-13 03:59:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					if (totedge_manifold != 3) | 
					
						
							|  |  |  | 						l = BM_face_other_edge_loop(l->f, l->e, v); | 
					
						
							| 
									
										
										
										
											2012-04-23 15:35:07 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					if (l) { | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 						BLI_assert(!BM_elem_flag_test(l->e, BM_ELEM_TAG)); | 
					
						
							| 
									
										
										
										
											2012-04-23 15:35:07 +00:00
										 |  |  | 						BM_elem_flag_enable(l->e, BM_ELEM_TAG); | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			else { | 
					
						
							|  |  |  | 				e = BM_vert_other_disk_edge(v, e2); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if (e) { | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 					BLI_assert(!BM_elem_flag_test(e, BM_ELEM_TAG)); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 					BM_elem_flag_enable(e, BM_ELEM_TAG); | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	/* keep directly before edgesplit */ | 
					
						
							|  |  |  | 	if (do_fill) { | 
					
						
							|  |  |  | 		fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-21 06:42:21 +00:00
										 |  |  | 	if (!edbm_rip_call_edgesplit(em, op)) { | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 		if (fill_uloop_pairs) MEM_freeN(fill_uloop_pairs); | 
					
						
							| 
									
										
										
										
											2012-04-21 06:42:21 +00:00
										 |  |  | 		return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* note: the output of the bmesh operator is ignored, since we built
 | 
					
						
							| 
									
										
										
										
											2012-04-21 12:14:07 +00:00
										 |  |  | 	 * the contiguous loop pairs to split already, its possible that some | 
					
						
							| 
									
										
										
										
											2012-04-21 06:42:21 +00:00
										 |  |  | 	 * 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. */ | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	edbm_ripsel_deselect_helper(bm, eloop_pairs, | 
					
						
							|  |  |  | 	                            ar, projectMat, fmval); | 
					
						
							|  |  |  | 	MEM_freeN(eloop_pairs); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	if (do_fill && fill_uloop_pairs) { | 
					
						
							|  |  |  | 		edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs); | 
					
						
							|  |  |  | 		MEM_freeN(fill_uloop_pairs); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-23 15:18:12 +00:00
										 |  |  | 	if (totedge_orig == bm->totedge) { | 
					
						
							|  |  |  | 		BKE_report(op->reports, RPT_ERROR, "No edges could be ripped"); | 
					
						
							|  |  |  | 		return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	EDBM_selectmode_flush(em); | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return OPERATOR_FINISHED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* based on mouse cursor position, it defines how is being ripped */ | 
					
						
							|  |  |  | static int edbm_rip_invoke(bContext *C, wmOperator *op, wmEvent *event) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	Object *obedit = CTX_data_edit_object(C); | 
					
						
							|  |  |  | 	BMEditMesh *em = BMEdit_FromObject(obedit); | 
					
						
							|  |  |  | 	BMesh *bm = em->bm; | 
					
						
							|  |  |  | 	BMIter iter; | 
					
						
							|  |  |  | 	BMEdge *e; | 
					
						
							|  |  |  | 	int singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0); | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* running in face mode hardly makes sense, so convert to region loop and rip */ | 
					
						
							| 
									
										
										
										
											2012-10-15 03:27:05 +00:00
										 |  |  | 	if (bm->totfacesel) { | 
					
						
							| 
									
										
										
										
											2012-05-20 21:23:26 +00:00
										 |  |  | 		/* highly nifty but hard to support since the operator can fail and we're left
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		 * with modified selection */ | 
					
						
							|  |  |  | 		// WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL);
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		BKE_report(op->reports, RPT_ERROR, "Can't rip selected faces"); | 
					
						
							|  |  |  | 		return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* 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 */ | 
					
						
							| 
									
										
										
										
											2012-10-15 03:27:05 +00:00
										 |  |  | 	BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		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, op, event); | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-04-19 23:16:57 +00:00
										 |  |  | 	else { | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 		ret = edbm_rip_invoke__edge(C, op, event); | 
					
						
							| 
									
										
										
										
											2012-04-19 23:16:57 +00:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	if (ret == OPERATOR_CANCELLED) { | 
					
						
							|  |  |  | 		return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 	BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0)); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | 	if (bm->totvertsel == 0) { | 
					
						
							|  |  |  | 		return OPERATOR_CANCELLED; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	EDBM_update_generic(C, em, TRUE); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return OPERATOR_FINISHED; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-20 14:36:06 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | void MESH_OT_rip(wmOperatorType *ot) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	/* 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 = EM_view3d_poll; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* flags */ | 
					
						
							|  |  |  | 	ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/* to give to transform */ | 
					
						
							|  |  |  | 	Transform_Properties(ot, P_PROPORTIONAL); | 
					
						
							| 
									
										
										
										
											2012-10-14 04:42:11 +00:00
										 |  |  | 	RNA_def_boolean(ot->srna, "mirror", FALSE, "Mirror Editing", ""); | 
					
						
							| 
									
										
										
										
											2012-10-14 15:29:09 +00:00
										 |  |  | 	RNA_def_boolean(ot->srna, "use_fill", FALSE, "Fill", "Fill the ripped region"); | 
					
						
							| 
									
										
										
										
											2012-04-17 10:25:23 +00:00
										 |  |  | } |