Blender  V2.93
editmesh_rip.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2004 by Blender Foundation.
17  * All rights reserved.
18  */
19 
24 #include "MEM_guardedalloc.h"
25 
26 #include "DNA_object_types.h"
27 
28 #include "BLI_array.h"
29 #include "BLI_math.h"
30 
31 #include "BKE_context.h"
32 #include "BKE_editmesh.h"
33 #include "BKE_layer.h"
34 #include "BKE_report.h"
35 
36 #include "RNA_access.h"
37 #include "RNA_define.h"
38 
39 #include "WM_types.h"
40 
41 #include "ED_mesh.h"
42 #include "ED_screen.h"
43 #include "ED_transform.h"
44 #include "ED_view3d.h"
45 
46 #include "bmesh.h"
47 #include "bmesh_tools.h"
48 
49 #include "mesh_intern.h" /* own include */
50 
58 #define INSET_DEFAULT 0.00001f
59 static float edbm_rip_edgedist_squared(ARegion *region,
60  float mat[4][4],
61  const float co1[3],
62  const float co2[3],
63  const float mvalf[2],
64  const float inset)
65 {
66  float vec1[2], vec2[2], dist_sq;
67 
68  ED_view3d_project_float_v2_m4(region, co1, vec1, mat);
69  ED_view3d_project_float_v2_m4(region, co2, vec2, mat);
70 
71  if (inset != 0.0f) {
72  const float dist_2d = len_v2v2(vec1, vec2);
73  if (dist_2d > FLT_EPSILON) {
74  const float dist = inset / dist_2d;
75  BLI_assert(isfinite(dist));
76  interp_v2_v2v2(vec1, vec1, vec2, dist);
77  interp_v2_v2v2(vec2, vec2, vec1, dist);
78  }
79  }
80 
81  dist_sq = dist_squared_to_line_segment_v2(mvalf, vec1, vec2);
82  BLI_assert(isfinite(dist_sq));
83 
84  return dist_sq;
85 }
86 
87 #if 0
88 static float edbm_rip_linedist(
89  ARegion *region, float mat[4][4], const float co1[3], const float co2[3], const float mvalf[2])
90 {
91  float vec1[2], vec2[2];
92 
93  ED_view3d_project_float_v2_m4(region, co1, vec1, mat);
94  ED_view3d_project_float_v2_m4(region, co2, vec2, mat);
95 
96  return dist_to_line_v2(mvalf, vec1, vec2);
97 }
98 #endif
99 
103 static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3])
104 {
105  BM_loop_calc_face_tangent(l, l_mid_co);
106 
107  /* scale to average of surrounding edge size, only needs to be approx, but should
108  * be roughly equivalent to the check below which uses the middle of the edge. */
109  mul_v3_fl(l_mid_co, (BM_edge_calc_length(l->e) + BM_edge_calc_length(l->prev->e)) / 2.0f);
110 
111  add_v3_v3(l_mid_co, l->v->co);
112 }
113 
115  BMEdge *e, BMLoop *e_l, ARegion *region, float projectMat[4][4], const float fmval[2])
116 {
117  float cent[3] = {0, 0, 0}, mid[3];
118 
119  float vec[2];
120  float fmval_tweak[2];
121  float e_v1_co[2], e_v2_co[2];
122  float score;
123 
124  BMVert *v1_other;
125  BMVert *v2_other;
126 
127  BLI_assert(BM_vert_in_edge(e, e_l->v));
128 
129  /* method for calculating distance:
130  *
131  * for each edge: calculate face center, then made a vector
132  * from edge midpoint to face center. offset edge midpoint
133  * by a small amount along this vector. */
134 
135  /* rather than the face center, get the middle of
136  * both edge verts connected to this one */
137  v1_other = BM_face_other_vert_loop(e_l->f, e->v2, e->v1)->v;
138  v2_other = BM_face_other_vert_loop(e_l->f, e->v1, e->v2)->v;
139  mid_v3_v3v3(cent, v1_other->co, v2_other->co);
140  mid_v3_v3v3(mid, e->v1->co, e->v2->co);
141 
142  ED_view3d_project_float_v2_m4(region, cent, cent, projectMat);
143  ED_view3d_project_float_v2_m4(region, mid, mid, projectMat);
144 
145  ED_view3d_project_float_v2_m4(region, e->v1->co, e_v1_co, projectMat);
146  ED_view3d_project_float_v2_m4(region, e->v2->co, e_v2_co, projectMat);
147 
148  sub_v2_v2v2(vec, cent, mid);
149  normalize_v2_length(vec, 0.01f);
150 
151  /* rather than adding to both verts, subtract from the mouse */
152  sub_v2_v2v2(fmval_tweak, fmval, vec);
153 
154  score = len_v2v2(e_v1_co, e_v2_co);
155 
156  if (dist_squared_to_line_segment_v2(fmval_tweak, e_v1_co, e_v2_co) >
157  dist_squared_to_line_segment_v2(fmval, e_v1_co, e_v2_co)) {
158  return score;
159  }
160  return -score;
161 }
162 
163 /* - Advanced selection handling 'ripsel' functions ----- */
164 
197 #define IS_VISIT_POSSIBLE(e) (BM_edge_is_manifold(e) && BM_elem_flag_test(e, BM_ELEM_TAG))
198 #define IS_VISIT_DONE(e) ((e)->l && (BM_elem_index_get((e)->l) != INVALID_UID))
199 #define INVALID_UID INT_MIN
200 
201 /* mark, assign uid and step */
202 static BMEdge *edbm_ripsel_edge_mark_step(BMVert *v, const int uid)
203 {
204  BMIter iter;
205  BMEdge *e;
206  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
207  if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) {
208  BMLoop *l_a, *l_b;
209 
210  BM_edge_loop_pair(e, &l_a, &l_b); /* no need to check, we know this will be true */
211 
212  /* so (IS_VISIT_DONE == true) */
213  BM_elem_index_set(l_a, uid); /* set_dirty */
214  BM_elem_index_set(l_b, uid); /* set_dirty */
215 
216  return e;
217  }
218  }
219  return NULL;
220 }
221 
222 typedef struct EdgeLoopPair {
226 
228 {
229  BMIter fiter;
230  BMIter liter;
231 
232  BMFace *f;
233  BMLoop *l;
234 
235  int uid_start;
236  int uid_end;
237  int uid = bm->totedge; /* can start anywhere */
238 
239  EdgeLoopPair *eloop_pairs = NULL;
240  BLI_array_declare(eloop_pairs);
241  EdgeLoopPair *lp;
242 
243  /* initialize loops with dummy invalid index values */
244  BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) {
245  BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) {
246  BM_elem_index_set(l, INVALID_UID); /* set_dirty */
247  }
248  }
250 
251  /* set contiguous loops ordered 'uid' values for walking after split */
252  while (true) {
253  int tot = 0;
254  BMIter eiter;
255  BMEdge *e_step;
256  BMVert *v_step;
257  BMEdge *e;
258  BMEdge *e_first;
259  BMEdge *e_last;
260 
261  e_first = NULL;
262  BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) {
263  if (IS_VISIT_POSSIBLE(e) && !IS_VISIT_DONE(e)) {
264  e_first = e;
265  break;
266  }
267  }
268 
269  if (e_first == NULL) {
270  break;
271  }
272 
273  /* initialize */
274  e_first = e;
275  v_step = e_first->v1;
276  e_step = NULL; /* quiet warning, will never remain this value */
277 
278  uid_start = uid;
279  while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) {
280  v_step = BM_edge_other_vert((e_step = e), v_step);
281  uid++; /* only different line */
282  tot++;
283  }
284 
285  /* this edges loops have the highest uid's, store this to walk down later */
286  e_last = e_step;
287 
288  /* always store the highest 'uid' edge for the stride */
289  uid_end = uid - 1;
290  uid = uid_start - 1;
291 
292  /* initialize */
293  v_step = e_first->v1;
294 
295  while ((e = edbm_ripsel_edge_mark_step(v_step, uid))) {
296  v_step = BM_edge_other_vert((e_step = e), v_step);
297  uid--; /* only different line */
298  tot++;
299  }
300 
301  /* stride far enough not to _ever_ overlap range */
302  uid_start = uid;
303  uid = uid_end + bm->totedge;
304 
305  lp = BLI_array_append_ret(eloop_pairs);
306  /* no need to check, we know this will be true */
307  BM_edge_loop_pair(e_last, &lp->l_a, &lp->l_b);
308 
309  BLI_assert(tot == uid_end - uid_start);
310 
311 #if 0
312  printf("%s: found contiguous edge loop of (%d)\n", __func__, uid_end - uid_start);
313 #endif
314  }
315 
316  /* null terminate */
317  lp = BLI_array_append_ret(eloop_pairs);
318  lp->l_a = lp->l_b = NULL;
319 
320  return eloop_pairs;
321 }
322 
323 /* - De-Select the worst rip-edge side -------------------------------- */
324 
325 static BMEdge *edbm_ripsel_edge_uid_step(BMEdge *e_orig, BMVert **v_prev)
326 {
327  BMIter eiter;
328  BMEdge *e;
329  BMVert *v = BM_edge_other_vert(e_orig, *v_prev);
330  const int uid_cmp = BM_elem_index_get(e_orig->l) - 1;
331 
332  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
333  if (BM_elem_index_get(e->l) == uid_cmp) {
334  *v_prev = v;
335  return e;
336  }
337  }
338  return NULL;
339 }
340 
342 {
343  /* try step in a direction, if it fails we know do go the other way */
344  BMVert *v_test = e->v1;
345  return (edbm_ripsel_edge_uid_step(e, &v_test)) ? e->v1 : e->v2;
346 }
347 
349  EdgeLoopPair *eloop_pairs,
350  ARegion *region,
351  float projectMat[4][4],
352  const float fmval[2])
353 {
354  EdgeLoopPair *lp;
355 
356  for (lp = eloop_pairs; lp->l_a; lp++) {
357  BMEdge *e;
358  BMVert *v_prev;
359 
360  float score_a = 0.0f;
361  float score_b = 0.0f;
362 
363  e = lp->l_a->e;
365  for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
366  score_a += edbm_rip_edge_side_measure(e, e->l, region, projectMat, fmval);
367  }
368  e = lp->l_b->e;
370  for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
371  score_b += edbm_rip_edge_side_measure(e, e->l, region, projectMat, fmval);
372  }
373 
374  e = (score_a > score_b) ? lp->l_a->e : lp->l_b->e;
376  for (; e; e = edbm_ripsel_edge_uid_step(e, &v_prev)) {
377  BM_edge_select_set(bm, e, false);
378  }
379  }
380 }
381 /* --- end 'ripsel' selection handling code --- */
382 
383 /* --- face-fill code --- */
394 typedef struct UnorderedLoopPair {
396  char flag;
398 enum {
399  ULP_FLIP_0 = (1 << 0),
400  ULP_FLIP_1 = (1 << 1),
401 };
402 
404 {
405  BMIter iter;
406  BMEdge *e;
407 
408  uint total_tag = 0;
409  /* count tags, could be pre-calculated */
410  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
412  total_tag++;
413  }
414  }
415 
416  if (total_tag) {
417  UnorderedLoopPair *uloop_pairs = MEM_mallocN(total_tag * sizeof(UnorderedLoopPair), __func__);
418  UnorderedLoopPair *ulp = uloop_pairs;
419 
420  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
422  BMLoop *l1, *l2;
423  if (BM_edge_loop_pair(e, &l1, &l2)) {
424  BMVert *v_cmp = l1->e->v1;
425  ulp->flag = (((l1->v != v_cmp) ? ULP_FLIP_0 : 0) | ((l2->v == v_cmp) ? ULP_FLIP_1 : 0));
426  }
427  else {
428  ulp->flag = 0;
429  }
430  ulp->l_pair[0] = l1;
431  ulp->l_pair[1] = l2;
432 
433  ulp++;
434  }
435  }
436 
437  return uloop_pairs;
438  }
439  return NULL;
440 }
441 
443 {
444  UnorderedLoopPair *ulp;
445  uint total_tag = MEM_allocN_len(uloop_pairs) / sizeof(UnorderedLoopPair);
446  uint i;
447 
448  for (i = 0, ulp = uloop_pairs; i < total_tag; i++, ulp++) {
449  if ((ulp->l_pair[0] && ulp->l_pair[1]) && (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) {
450  /* time has come to make a face! */
451  BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e);
452  BMFace *f, *f_example = ulp->l_pair[0]->f;
453  BMLoop *l_iter;
454  BMVert *f_verts[4];
455 
456  if (v_shared == NULL) {
457  /* quad */
458  f_verts[0] = ulp->l_pair[0]->e->v1;
459  f_verts[1] = ulp->l_pair[1]->e->v1;
460  f_verts[2] = ulp->l_pair[1]->e->v2;
461  f_verts[3] = ulp->l_pair[0]->e->v2;
462 
463  if (ulp->flag & ULP_FLIP_0) {
464  SWAP(BMVert *, f_verts[0], f_verts[3]);
465  }
466  if (ulp->flag & ULP_FLIP_1) {
467  SWAP(BMVert *, f_verts[1], f_verts[2]);
468  }
469  }
470  else {
471  /* tri */
472  f_verts[0] = v_shared;
473  f_verts[1] = BM_edge_other_vert(ulp->l_pair[0]->e, v_shared);
474  f_verts[2] = BM_edge_other_vert(ulp->l_pair[1]->e, v_shared);
475  f_verts[3] = NULL;
476 
477  /* don't use the flip flags */
478  if (v_shared == ulp->l_pair[0]->v) {
479  SWAP(BMVert *, f_verts[0], f_verts[1]);
480  }
481  }
482 
483  /* face should never exist */
484  BLI_assert(!BM_face_exists(f_verts, f_verts[3] ? 4 : 3));
485 
486  f = BM_face_create_verts(bm, f_verts, f_verts[3] ? 4 : 3, f_example, BM_CREATE_NOP, true);
487 
488  l_iter = BM_FACE_FIRST_LOOP(f);
489 
490  if (f_verts[3]) {
491  BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
492  l_iter = l_iter->next;
493  BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
494  l_iter = l_iter->next;
495  BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
496  l_iter = l_iter->next;
497  BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
498  }
499  else {
500  BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
501  l_iter = l_iter->next;
502  BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[0]->e, l_iter), l_iter);
503  l_iter = l_iter->next;
504  BM_elem_attrs_copy(bm, bm, BM_edge_other_loop(ulp->l_pair[1]->e, l_iter), l_iter);
505  }
506  }
507  }
508 }
509 
510 /* --- end 'face-fill' code --- */
511 
515 static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obedit, bool do_fill)
516 {
517  UnorderedLoopPair *fill_uloop_pairs = NULL;
518  ARegion *region = CTX_wm_region(C);
520  BMEditMesh *em = BKE_editmesh_from_object(obedit);
521  BMesh *bm = em->bm;
522  BMIter iter, liter;
523  BMLoop *l;
524  BMEdge *e_best;
525  BMVert *v;
526  const int totvert_orig = bm->totvert;
527  int i;
528  float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
529  float dist_sq = FLT_MAX;
530  float d;
531  bool is_wire, is_manifold_region;
532 
533  BMEditSelection ese;
534  int totboundary_edge = 0;
535 
536  ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
537 
538  /* find selected vert - same some time and check history first */
539  if (BM_select_history_active_get(bm, &ese) && ese.htype == BM_VERT) {
540  v = (BMVert *)ese.ele;
541  }
542  else {
543  ese.ele = NULL;
544 
545  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
547  break;
548  }
549  }
550  }
551 
552  /* (v == NULL) should be impossible */
553  if ((v == NULL) || (v->e == NULL)) {
554  return OPERATOR_CANCELLED;
555  }
556 
557  is_wire = BM_vert_is_wire(v);
558  is_manifold_region = BM_vert_is_manifold_region(v);
559 
560  e_best = NULL;
561 
562  {
563  BMEdge *e;
564  /* find closest edge to mouse cursor */
565  BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) {
566  /* consider wire as boundary for this purpose,
567  * otherwise we can't a face away from a wire edge */
568  totboundary_edge += (BM_edge_is_boundary(e) || BM_edge_is_wire(e));
570  if ((is_manifold_region == false) || BM_edge_is_manifold(e)) {
572  region, projectMat, e->v1->co, e->v2->co, fmval, INSET_DEFAULT);
573  if ((e_best == NULL) || (d < dist_sq)) {
574  dist_sq = d;
575  e_best = e;
576  }
577  }
578  }
579  }
580  }
581 
582  if (e_best && e_best->l && (is_manifold_region == false)) {
583  /* Try to split off a non-manifold fan (when we have multiple disconnected fans) */
584  BMLoop *l_sep = e_best->l->v == v ? e_best->l : e_best->l->next;
585  BMVert *v_new;
586 
587  BLI_assert(l_sep->v == v);
590 
591  BM_vert_select_set(bm, v, false);
593 
594  BM_vert_select_set(bm, v_new, true);
595  if (ese.ele) {
596  BM_select_history_store(bm, v_new);
597  }
598 
599  if (do_fill) {
600  BM_edge_create(bm, v, v_new, NULL, BM_CREATE_NOP);
601  }
602 
603  return OPERATOR_FINISHED;
604  }
605 
606  /* if we are ripping a single vertex from 3 faces,
607  * then measure the distance to the face corner as well as the edge */
609  BMEdge *e_all[3];
610  BMLoop *l_all[3];
611  int i1, i2;
612 
613  BM_iter_as_array(bm, BM_EDGES_OF_VERT, v, (void **)e_all, 3);
614  BM_iter_as_array(bm, BM_LOOPS_OF_VERT, v, (void **)l_all, 3);
615 
616  /* not do a loop similar to the one above, but test against loops */
617  for (i1 = 0; i1 < 3; i1++) {
618  /* consider wire as boundary for this purpose,
619  * otherwise we can't a face away from a wire edge */
620  float l_mid_co[3];
621  l = l_all[i1];
622  edbm_calc_loop_co(l, l_mid_co);
623  d = edbm_rip_edgedist_squared(region, projectMat, l->v->co, l_mid_co, fmval, INSET_DEFAULT);
624  if ((e_best == NULL) || (d < dist_sq)) {
625  dist_sq = d;
626 
627  /* find the edge that is not in this loop */
628  e_best = NULL;
629  for (i2 = 0; i2 < 3; i2++) {
630  if (!BM_edge_in_loop(e_all[i2], l)) {
631  e_best = e_all[i2];
632  break;
633  }
634  }
635  BLI_assert(e_best != NULL);
636  }
637  }
638  }
639 
640  /* should we go ahead with edge rip or do we need to do special case, split off vertex?:
641  * split off vertex if...
642  * - we cant find an edge - this means we are ripping a faces vert that is connected to other
643  * geometry only at the vertex.
644  * - the boundary edge total is greater than 2,
645  * in this case edge split _can_ work but we get far nicer results if we use this special case.
646  * - there are only 2 edges but we are a wire vert. */
647  if ((is_wire == false && totboundary_edge > 2) || (is_wire == true && totboundary_edge > 1)) {
648  BMVert **vout;
649  int vout_len;
650 
651  BM_vert_select_set(bm, v, false);
652 
653  bmesh_kernel_vert_separate(bm, v, &vout, &vout_len, true);
654 
655  if (vout_len < 2) {
656  MEM_freeN(vout);
657  /* set selection back to avoid active-unselected vertex */
658  BM_vert_select_set(bm, v, true);
659  /* should never happen */
660  return OPERATOR_CANCELLED;
661  }
662 
663  int vi_best = 0;
664 
665  if (ese.ele) {
667  }
668 
669  dist_sq = FLT_MAX;
670 
671  /* in the loop below we find the best vertex to drag based on its connected geometry,
672  * either by its face corner, or connected edge (when no faces are attached) */
673  for (i = 0; i < vout_len; i++) {
674 
675  if (BM_vert_is_wire(vout[i]) == false) {
676  /* find the best face corner */
677  BM_ITER_ELEM (l, &iter, vout[i], BM_LOOPS_OF_VERT) {
679  float l_mid_co[3];
680 
681  edbm_calc_loop_co(l, l_mid_co);
683  region, projectMat, v->co, l_mid_co, fmval, INSET_DEFAULT);
684 
685  if (d < dist_sq) {
686  dist_sq = d;
687  vi_best = i;
688  }
689  }
690  }
691  }
692  else {
693  BMEdge *e;
694  /* a wire vert, find the best edge */
695  BM_ITER_ELEM (e, &iter, vout[i], BM_EDGES_OF_VERT) {
697  float e_mid_co[3];
698 
699  mid_v3_v3v3(e_mid_co, e->v1->co, e->v2->co);
701  region, projectMat, v->co, e_mid_co, fmval, INSET_DEFAULT);
702 
703  if (d < dist_sq) {
704  dist_sq = d;
705  vi_best = i;
706  }
707  }
708  }
709  }
710  }
711 
712  /* vout[0] == best
713  * vout[1] == glue
714  * vout[2+] == splice with glue (when vout_len > 2)
715  */
716  if (vi_best != 0) {
717  SWAP(BMVert *, vout[0], vout[vi_best]);
718  vi_best = 0;
719  }
720 
721  /* select the vert from the best region */
722  v = vout[vi_best];
723  BM_vert_select_set(bm, v, true);
724 
725  if (ese.ele) {
727  }
728 
729  /* splice all others back together */
730  if (vout_len > 2) {
731  for (i = 2; i < vout_len; i++) {
732  BM_vert_splice(bm, vout[1], vout[i]);
733  }
734  }
735 
736  if (do_fill) {
737  /* match extrude vert-order */
738  BM_edge_create(bm, vout[1], vout[0], NULL, BM_CREATE_NOP);
739  }
740 
741  MEM_freeN(vout);
742 
743  return OPERATOR_FINISHED;
744  }
745 
746  if (!e_best) {
747  return OPERATOR_CANCELLED;
748  }
749 
750  /* *** Execute the split! *** */
751  /* unlike edge split, for single vertex split we only use the operator in one of the cases
752  * but both allocate fill */
753 
754  {
755  BMVert *v_rip;
756  BMLoop *larr[2];
757  int larr_len = 0;
758 
759  /* rip two adjacent edges */
761  /* Don't run the edge split operator in this case */
762 
763  l = BM_edge_vert_share_loop(e_best->l, v);
764  larr[larr_len] = l;
765  larr_len++;
766 
767  /* only tag for face-fill (we don't call the operator) */
768  if (BM_edge_is_boundary(e_best)) {
770  }
771  else {
774  }
775  }
776  else {
777  if (BM_edge_is_manifold(e_best)) {
778  BMLoop *l_iter, *l_first;
779  l_iter = l_first = e_best->l;
780  do {
781  larr[larr_len] = BM_edge_vert_share_loop(l_iter, v);
782 
783  if (do_fill) {
784  /* Only needed when filling...
785  * Also, we never want to tag best edge,
786  * that one won't change during split. See T44618. */
787  if (larr[larr_len]->e == e_best) {
788  BM_elem_flag_enable(larr[larr_len]->prev->e, BM_ELEM_TAG);
789  }
790  else {
791  BM_elem_flag_enable(larr[larr_len]->e, BM_ELEM_TAG);
792  }
793  }
794  larr_len++;
795  } while ((l_iter = l_iter->radial_next) != l_first);
796  }
797  else {
798  /* looks like there are no split edges, we could just return/report-error? - Campbell */
799  }
800  }
801 
802  /* keep directly before edgesplit */
803  if (do_fill) {
804  fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
805  }
806 
807  if (larr_len) {
808  v_rip = BM_face_loop_separate_multi(bm, larr, larr_len);
809  }
810  else {
811  v_rip = NULL;
812  }
813 
814  if (v_rip) {
815  BM_vert_select_set(bm, v_rip, true);
816  }
817  else {
818  if (fill_uloop_pairs) {
819  MEM_freeN(fill_uloop_pairs);
820  }
821  return OPERATOR_CANCELLED;
822  }
823  }
824 
825  {
826  /* --- select which vert --- */
827  BMVert *v_best = NULL;
828  float l_corner_co[3];
829 
830  dist_sq = FLT_MAX;
831  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
833  /* disable by default, re-enable winner at end */
834  BM_vert_select_set(bm, v, false);
836 
837  BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) {
838 
839  /* check if v_best is null in the _rare_ case there are numeric issues */
840  edbm_calc_loop_co(l, l_corner_co);
842  region, projectMat, l->v->co, l_corner_co, fmval, INSET_DEFAULT);
843  if ((v_best == NULL) || (d < dist_sq)) {
844  v_best = v;
845  dist_sq = d;
846  }
847  }
848  }
849  }
850 
851  if (v_best) {
852  BM_vert_select_set(bm, v_best, true);
853  if (ese.ele) {
854  BM_select_history_store(bm, v_best);
855  }
856  }
857  }
858 
859  if (do_fill && fill_uloop_pairs) {
860  edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs);
861  MEM_freeN(fill_uloop_pairs);
862  }
863 
864  if (totvert_orig == bm->totvert) {
865  return OPERATOR_CANCELLED;
866  }
867 
868  return OPERATOR_FINISHED;
869 }
870 
874 static int edbm_rip_invoke__edge(bContext *C, const wmEvent *event, Object *obedit, bool do_fill)
875 {
876  UnorderedLoopPair *fill_uloop_pairs = NULL;
877  ARegion *region = CTX_wm_region(C);
879  BMEditMesh *em = BKE_editmesh_from_object(obedit);
880  BMesh *bm = em->bm;
881  BMIter iter, eiter;
882  BMLoop *l;
883  BMEdge *e_best;
884  BMVert *v;
885  const int totvert_orig = bm->totvert;
886  const int totedge_orig = bm->totedge;
887  float projectMat[4][4], fmval[3] = {event->mval[0], event->mval[1]};
888 
889  EdgeLoopPair *eloop_pairs;
890 
891  ED_view3d_ob_project_mat_get(rv3d, obedit, projectMat);
892 
893  /* important this runs on the original selection, before tampering with tagging */
894  eloop_pairs = edbm_ripsel_looptag_helper(bm);
895 
896  /* expand edge selection */
897  BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
898  BMEdge *e;
899  bool all_manifold;
900  int totedge_manifold; /* manifold, visible edges */
901  int i;
902 
903  e_best = NULL;
904  i = 0;
905  totedge_manifold = 0;
906  all_manifold = true;
907  BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) {
908 
910  /* important to check selection rather than tag here
911  * else we get feedback loop */
913  e_best = e;
914  i++;
915  /* Tag the edge verts so we know which verts to rip */
918  }
919  totedge_manifold++;
920  }
921 
923  if ((all_manifold == true) && (BM_edge_is_manifold(e) == false)) {
924  all_manifold = false;
925  }
926  }
927 
928  /* single edge, extend */
929  if (i == 1 && e_best->l) {
930  /* note: if the case of 3 edges has one change in loop stepping,
931  * if this becomes more involved we may be better off splitting
932  * the 3 edge case into its own else-if branch */
933  if ((totedge_manifold == 4 || totedge_manifold == 3) || (all_manifold == false)) {
934  BMLoop *l_a = e_best->l;
935  BMLoop *l_b = l_a->radial_next;
936 
937  /* find the best face to follow, this way the edge won't point away from
938  * the mouse when there are more than 4 (takes the shortest face fan around) */
939  l = (edbm_rip_edge_side_measure(e_best, l_a, region, projectMat, fmval) <
940  edbm_rip_edge_side_measure(e_best, l_b, region, projectMat, fmval)) ?
941  l_a :
942  l_b;
943 
945  /* Important edge is manifold else we can be attempting to split off
946  * a fan that don't budge, not crashing but adds duplicate edge. */
947  if (BM_edge_is_manifold(l->e)) {
948  l = l->radial_next;
949 
950  if (totedge_manifold != 3) {
952  }
953 
954  if (l) {
957  }
958  }
959  }
960  else {
961  e = BM_vert_other_disk_edge(v, e_best);
962 
963  if (e) {
966  }
967  }
968  }
969  }
970 
971  /* keep directly before edgesplit */
972  if (do_fill) {
973  fill_uloop_pairs = edbm_tagged_loop_pairs_to_fill(bm);
974  }
975 
976  BM_mesh_edgesplit(em->bm, true, true, true);
977 
978  /* note: the output of the bmesh operator is ignored, since we built
979  * the contiguous loop pairs to split already, its possible that some
980  * edge did not split even though it was tagged which would not work
981  * as expected (but not crash), however there are checks to ensure
982  * tagged edges will split. So far its not been an issue. */
983  edbm_ripsel_deselect_helper(bm, eloop_pairs, region, projectMat, fmval);
984  MEM_freeN(eloop_pairs);
985 
986  /* deselect loose verts */
988 
989  if (do_fill && fill_uloop_pairs) {
990  edbm_tagged_loop_pairs_do_fill_faces(bm, fill_uloop_pairs);
991  MEM_freeN(fill_uloop_pairs);
992  }
993 
994  if ((totvert_orig == bm->totvert) && (totedge_orig == bm->totedge)) {
995  return OPERATOR_CANCELLED;
996  }
997 
999 
1000  return OPERATOR_FINISHED;
1001 }
1002 
1003 /* based on mouse cursor position, it defines how is being ripped */
1004 static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
1005 {
1006  ViewLayer *view_layer = CTX_data_view_layer(C);
1007  uint objects_len = 0;
1009  view_layer, CTX_wm_view3d(C), &objects_len);
1010  const bool do_fill = RNA_boolean_get(op->ptr, "use_fill");
1011 
1012  bool no_vertex_selected = true;
1013  bool error_face_selected = true;
1014  bool error_disconnected_vertices = true;
1015  bool error_rip_failed = true;
1016 
1017  for (uint ob_index = 0; ob_index < objects_len; ob_index++) {
1018  Object *obedit = objects[ob_index];
1019  BMEditMesh *em = BKE_editmesh_from_object(obedit);
1020 
1021  BMesh *bm = em->bm;
1022  BMIter iter;
1023  BMEdge *e;
1024  const bool singlesel = (bm->totvertsel == 1 && bm->totedgesel == 0 && bm->totfacesel == 0);
1025  int ret;
1026 
1027  if (em->bm->totvertsel == 0) {
1028  continue;
1029  }
1030  no_vertex_selected = false;
1031 
1032  /* running in face mode hardly makes sense, so convert to region loop and rip */
1033  if (bm->totfacesel) {
1034  /* highly nifty but hard to support since the operator can fail and we're left
1035  * with modified selection */
1036  // WM_operator_name_call(C, "MESH_OT_region_to_loop", WM_OP_INVOKE_DEFAULT, NULL);
1037  continue;
1038  }
1039  error_face_selected = false;
1040 
1041  /* we could support this, but not for now */
1042  if ((bm->totvertsel > 1) && (bm->totedgesel == 0)) {
1043  continue;
1044  }
1045  error_disconnected_vertices = false;
1046 
1047  /* note on selection:
1048  * When calling edge split we operate on tagged edges rather than selected
1049  * this is important because the edges to operate on are extended by one,
1050  * but the selection is left alone.
1051  *
1052  * After calling edge split - the duplicated edges have the same selection state as the
1053  * original, so all we do is de-select the far side from the mouse and we have a
1054  * useful selection for grabbing.
1055  */
1056 
1058 
1059  /* BM_ELEM_SELECT --> BM_ELEM_TAG */
1060  BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
1062  }
1063 
1064  /* split 2 main parts of this operator out into vertex and edge ripping */
1065  if (singlesel) {
1066  ret = edbm_rip_invoke__vert(C, event, obedit, do_fill);
1067  }
1068  else {
1069  ret = edbm_rip_invoke__edge(C, event, obedit, do_fill);
1070  }
1071 
1072  if (ret != OPERATOR_FINISHED) {
1073  continue;
1074  }
1075 
1077 
1078  BLI_assert(singlesel ? (bm->totvertsel > 0) : (bm->totedgesel > 0));
1079 
1080  if (bm->totvertsel == 0) {
1081  continue;
1082  }
1083  error_rip_failed = false;
1084 
1085  EDBM_update_generic(obedit->data, true, true);
1086  }
1087 
1088  MEM_freeN(objects);
1089 
1090  if (no_vertex_selected) {
1091  /* Ignore it. */
1092  return OPERATOR_CANCELLED;
1093  }
1094  if (error_face_selected) {
1095  BKE_report(op->reports, RPT_ERROR, "Cannot rip selected faces");
1096  return OPERATOR_CANCELLED;
1097  }
1098  if (error_disconnected_vertices) {
1099  BKE_report(op->reports, RPT_ERROR, "Cannot rip multiple disconnected vertices");
1100  return OPERATOR_CANCELLED;
1101  }
1102  if (error_rip_failed) {
1103  BKE_report(op->reports, RPT_ERROR, "Rip failed");
1104  return OPERATOR_CANCELLED;
1105  }
1106  /* No errors, everything went fine. */
1107  return OPERATOR_FINISHED;
1108 }
1109 
1111 {
1112  /* identifiers */
1113  ot->name = "Rip";
1114  ot->idname = "MESH_OT_rip";
1115  ot->description = "Disconnect vertex or edges from connected geometry";
1116 
1117  /* api callbacks */
1120 
1121  /* flags */
1123 
1124  /* to give to transform */
1126  RNA_def_boolean(ot->srna, "use_fill", false, "Fill", "Fill the ripped region");
1127 }
struct ViewLayer * CTX_data_view_layer(const bContext *C)
Definition: context.c:1044
struct View3D * CTX_wm_view3d(const bContext *C)
Definition: context.c:760
struct ARegion * CTX_wm_region(const bContext *C)
Definition: context.c:725
struct RegionView3D * CTX_wm_region_view3d(const bContext *C)
Definition: context.c:769
BMEditMesh * BKE_editmesh_from_object(struct Object *ob)
Return the BMEditMesh for a given object.
Definition: editmesh.c:85
#define BKE_view_layer_array_from_objects_in_edit_mode_unique_data(view_layer, v3d, r_len)
Definition: BKE_layer.h:426
void BKE_report(ReportList *reports, ReportType type, const char *message)
Definition: report.c:104
A (mainly) macro array library.
#define BLI_array_append_ret(arr)
Definition: BLI_array.h:114
#define BLI_array_declare(arr)
Definition: BLI_array.h:62
#define BLI_assert(a)
Definition: BLI_assert.h:58
float dist_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:332
float dist_squared_to_line_segment_v2(const float p[2], const float l1[2], const float l2[2])
Definition: math_geom.c:338
void interp_v2_v2v2(float r[2], const float a[2], const float b[2], const float t)
Definition: math_vector.c:32
MINLINE void mul_v3_fl(float r[3], float f)
MINLINE float normalize_v2_length(float r[2], const float unit_scale)
MINLINE void sub_v2_v2v2(float r[2], const float a[2], const float b[2])
void mid_v3_v3v3(float r[3], const float a[3], const float b[3])
Definition: math_vector.c:270
MINLINE float len_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
MINLINE void add_v3_v3(float r[3], const float a[3])
unsigned int uint
Definition: BLI_sys_types.h:83
#define SWAP(type, a, b)
Object is a sort of wrapper for general info.
#define SCE_SELECT_EDGE
@ OPERATOR_CANCELLED
@ OPERATOR_FINISHED
void EDBM_update_generic(struct Mesh *me, const bool do_tessellation, const bool is_destructive)
#define P_PROPORTIONAL
Definition: ED_transform.h:124
void Transform_Properties(struct wmOperatorType *ot, int flags)
#define P_MIRROR_DUMMY
Definition: ED_transform.h:123
void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, struct Object *ob, float r_pmat[4][4])
void ED_view3d_project_float_v2_m4(const struct ARegion *region, const float co[3], float r_co[2], float mat[4][4])
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint i1
Read Guarded memory(de)allocation.
#define C
Definition: RandGen.cpp:39
@ OPTYPE_UNDO
Definition: WM_types.h:155
@ OPTYPE_REGISTER
Definition: WM_types.h:153
@ BM_LOOP
Definition: bmesh_class.h:385
@ BM_VERT
Definition: bmesh_class.h:383
@ BM_ELEM_HIDDEN
Definition: bmesh_class.h:472
@ BM_ELEM_SELECT
Definition: bmesh_class.h:471
@ BM_ELEM_TAG
Definition: bmesh_class.h:484
#define BM_FACE_FIRST_LOOP(p)
Definition: bmesh_class.h:553
void BM_elem_attrs_copy(BMesh *bm_src, BMesh *bm_dst, const void *ele_src, void *ele_dst)
BMFace * BM_face_create_verts(BMesh *bm, BMVert **vert_arr, const int len, const BMFace *f_example, const eBMCreateFlag create_flag, const bool create_edges)
Definition: bmesh_core.c:500
bool BM_vert_splice(BMesh *bm, BMVert *v_dst, BMVert *v_src)
Splice Vert.
Definition: bmesh_core.c:2284
void bmesh_kernel_vert_separate(BMesh *bm, BMVert *v, BMVert ***r_vout, int *r_vout_len, const bool copy_select)
Separate Vert.
Definition: bmesh_core.c:2331
BMEdge * BM_edge_create(BMesh *bm, BMVert *v1, BMVert *v2, const BMEdge *e_example, const eBMCreateFlag create_flag)
Main function for creating a new edge.
Definition: bmesh_core.c:147
@ BM_CREATE_NOP
Definition: bmesh_core.h:27
void BM_mesh_edgesplit(BMesh *bm, const bool use_verts, const bool tag_only, const bool copy_select)
#define BM_elem_index_get(ele)
Definition: bmesh_inline.h:124
#define BM_elem_flag_set(ele, hflag, val)
Definition: bmesh_inline.h:30
#define BM_elem_index_set(ele, index)
Definition: bmesh_inline.h:125
#define BM_elem_flag_test(ele, hflag)
Definition: bmesh_inline.h:26
#define BM_elem_flag_enable(ele, hflag)
Definition: bmesh_inline.h:28
int BM_iter_as_array(BMesh *bm, const char itype, void *data, void **array, const int len)
Iterator as Array.
#define BM_ITER_ELEM(ele, iter, data, itype)
#define BM_ITER_MESH(ele, iter, bm, itype)
@ BM_EDGES_OF_MESH
@ BM_VERTS_OF_MESH
@ BM_FACES_OF_MESH
@ BM_LOOPS_OF_VERT
@ BM_EDGES_OF_VERT
@ BM_LOOPS_OF_FACE
ATTR_WARN_UNUSED_RESULT BMesh * bm
void BM_mesh_select_mode_clean_ex(BMesh *bm, const short selectmode)
Select Mode Clean.
void BM_vert_select_set(BMesh *bm, BMVert *v, const bool select)
Select Vert.
void BM_edge_select_set(BMesh *bm, BMEdge *e, const bool select)
Select Edge.
void BM_select_history_validate(BMesh *bm)
bool BM_select_history_active_get(BMesh *bm, BMEditSelection *ese)
#define BM_select_history_store(bm, ele)
#define BM_select_history_remove(bm, ele)
bool BM_custom_loop_normals_to_vector_layer(BMesh *bm)
Definition: bmesh_mesh.c:1903
void BM_custom_loop_normals_from_vector_layer(BMesh *bm, bool add_sharp_edges)
Definition: bmesh_mesh.c:1940
BMVert * BM_face_loop_separate_multi_isolated(BMesh *bm, BMLoop *l_sep)
Definition: bmesh_mods.c:1102
BMVert * BM_face_loop_separate_multi(BMesh *bm, BMLoop **larr, int larr_len)
Definition: bmesh_mods.c:1107
bool BM_vert_is_wire(const BMVert *v)
Definition: bmesh_query.c:919
BMLoop * BM_face_other_vert_loop(BMFace *f, BMVert *v_prev, BMVert *v)
Other Loop in Face Sharing a Vertex.
Definition: bmesh_query.c:97
BMEdge * BM_vert_other_disk_edge(BMVert *v, BMEdge *e_first)
Definition: bmesh_query.c:664
BMLoop * BM_vert_find_first_loop(BMVert *v)
Definition: bmesh_query.c:416
bool BM_vert_is_manifold_region(const BMVert *v)
Definition: bmesh_query.c:1092
void BM_loop_calc_face_tangent(const BMLoop *l, float r_tangent[3])
BM_loop_calc_face_tangent.
Definition: bmesh_query.c:1681
bool BM_edge_loop_pair(BMEdge *e, BMLoop **r_la, BMLoop **r_lb)
Definition: bmesh_query.c:753
BMVert * BM_edge_share_vert(BMEdge *e1, BMEdge *e2)
Definition: bmesh_query.c:1366
BMFace * BM_face_exists(BMVert **varr, int len)
Definition: bmesh_query.c:2070
BMLoop * BM_edge_vert_share_loop(BMLoop *l, BMVert *v)
Return the Loop Shared by Edge and Vert.
Definition: bmesh_query.c:1386
float BM_edge_calc_length(const BMEdge *e)
Definition: bmesh_query.c:713
BMLoop * BM_edge_other_loop(BMEdge *e, BMLoop *l)
Definition: bmesh_query.c:587
BMLoop * BM_loop_other_edge_loop(BMLoop *l, BMVert *v)
Definition: bmesh_query.c:69
BLI_INLINE bool BM_edge_is_manifold(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_is_boundary(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_vert_edge_count_is_equal(v, n)
Definition: bmesh_query.h:91
BLI_INLINE BMVert * BM_edge_other_vert(BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_edge_in_loop(const BMEdge *e, const BMLoop *l) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
#define BM_vert_face_count_is_equal(v, n)
Definition: bmesh_query.h:101
BLI_INLINE bool BM_edge_is_wire(const BMEdge *e) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
BLI_INLINE bool BM_vert_in_edge(const BMEdge *e, const BMVert *v) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
ATTR_WARN_UNUSED_RESULT const BMLoop * l
ATTR_WARN_UNUSED_RESULT const BMVert const BMEdge * e
ATTR_WARN_UNUSED_RESULT const BMLoop * l_b
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define INSET_DEFAULT
Definition: editmesh_rip.c:58
static int edbm_rip_invoke__edge(bContext *C, const wmEvent *event, Object *obedit, bool do_fill)
Definition: editmesh_rip.c:874
static float edbm_rip_edge_side_measure(BMEdge *e, BMLoop *e_l, ARegion *region, float projectMat[4][4], const float fmval[2])
Definition: editmesh_rip.c:114
static int edbm_rip_invoke__vert(bContext *C, const wmEvent *event, Object *obedit, bool do_fill)
Definition: editmesh_rip.c:515
static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *uloop_pairs)
Definition: editmesh_rip.c:442
static BMEdge * edbm_ripsel_edge_uid_step(BMEdge *e_orig, BMVert **v_prev)
Definition: editmesh_rip.c:325
@ ULP_FLIP_0
Definition: editmesh_rip.c:399
@ ULP_FLIP_1
Definition: editmesh_rip.c:400
static float edbm_rip_edgedist_squared(ARegion *region, float mat[4][4], const float co1[3], const float co2[3], const float mvalf[2], const float inset)
Definition: editmesh_rip.c:59
struct EdgeLoopPair EdgeLoopPair
#define IS_VISIT_POSSIBLE(e)
Definition: editmesh_rip.c:197
static BMVert * edbm_ripsel_edloop_pair_start_vert(BMEdge *e)
Definition: editmesh_rip.c:341
#define INVALID_UID
Definition: editmesh_rip.c:199
static void edbm_calc_loop_co(BMLoop *l, float l_mid_co[3])
Definition: editmesh_rip.c:103
static UnorderedLoopPair * edbm_tagged_loop_pairs_to_fill(BMesh *bm)
Definition: editmesh_rip.c:403
static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs, ARegion *region, float projectMat[4][4], const float fmval[2])
Definition: editmesh_rip.c:348
struct UnorderedLoopPair UnorderedLoopPair
void MESH_OT_rip(wmOperatorType *ot)
static EdgeLoopPair * edbm_ripsel_looptag_helper(BMesh *bm)
Definition: editmesh_rip.c:227
#define IS_VISIT_DONE(e)
Definition: editmesh_rip.c:198
static int edbm_rip_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static BMEdge * edbm_ripsel_edge_mark_step(BMVert *v, const int uid)
Definition: editmesh_rip.c:202
bool EDBM_view3d_poll(bContext *C)
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
size_t(* MEM_allocN_len)(const void *vmemh)
Definition: mallocn.c:40
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
bool isfinite(uchar)
Definition: image.cpp:44
return ret
bool RNA_boolean_get(PointerRNA *ptr, const char *name)
Definition: rna_access.c:6261
PropertyRNA * RNA_def_boolean(StructOrFunctionRNA *cont_, const char *identifier, bool default_value, const char *ui_name, const char *ui_description)
Definition: rna_define.c:3481
BMVert * v1
Definition: bmesh_class.h:134
BMVert * v2
Definition: bmesh_class.h:134
struct BMLoop * l
Definition: bmesh_class.h:140
struct BMesh * bm
Definition: BKE_editmesh.h:52
struct BMVert * v
Definition: bmesh_class.h:165
struct BMEdge * e
Definition: bmesh_class.h:176
struct BMLoop * radial_next
Definition: bmesh_class.h:216
struct BMLoop * prev
Definition: bmesh_class.h:245
struct BMFace * f
Definition: bmesh_class.h:183
struct BMLoop * next
Definition: bmesh_class.h:245
float co[3]
Definition: bmesh_class.h:99
struct BMEdge * e
Definition: bmesh_class.h:109
int totvert
Definition: bmesh_class.h:297
int totfacesel
Definition: bmesh_class.h:298
char elem_index_dirty
Definition: bmesh_class.h:305
int totedge
Definition: bmesh_class.h:297
int totvertsel
Definition: bmesh_class.h:298
int totedgesel
Definition: bmesh_class.h:298
BMLoop * l_a
Definition: editmesh_rip.c:223
BMLoop * l_b
Definition: editmesh_rip.c:224
void * data
BMLoop * l_pair[2]
Definition: editmesh_rip.c:395
int(* invoke)(struct bContext *, struct wmOperator *, const struct wmEvent *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:752
const char * name
Definition: WM_types.h:721
const char * idname
Definition: WM_types.h:723
bool(* poll)(struct bContext *) ATTR_WARN_UNUSED_RESULT
Definition: WM_types.h:776
struct StructRNA * srna
Definition: WM_types.h:802
const char * description
Definition: WM_types.h:726
struct ReportList * reports
struct PointerRNA * ptr
wmOperatorType * ot
Definition: wm_files.c:3156