ce4e48daf763afa116ad4ebe5e5f517c4d8f42a3
[blender-staging.git] / source / blender / bmesh / intern / bmesh_mods.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * Contributor(s): Joseph Eagar, Geoffrey Bantle, Campbell Barton
19  *
20  * ***** END GPL LICENSE BLOCK *****
21  */
22
23 /** \file blender/bmesh/intern/bmesh_mods.c
24  *  \ingroup bmesh
25  *
26  * This file contains functions for locally modifying
27  * the topology of existing mesh data. (split, join, flip etc).
28  */
29
30 #include <limits.h>
31 #include "MEM_guardedalloc.h"
32
33 #include "DNA_listBase.h"
34
35 #include "BLI_utildefines.h"
36 #include "BLI_linklist.h"
37 #include "BLI_ghash.h"
38 #include "BLI_math.h"
39 #include "BLI_array.h"
40 #include "BLI_utildefines.h"
41 #include "BLI_smallhash.h"
42
43 #include "bmesh.h"
44 #include "bmesh_private.h"
45
46 #include <stdlib.h>
47 #include <string.h>
48
49 /**
50  *                      bmesh_dissolve_disk
51  *
52  *  Turns the face region surrounding a manifold vertex into
53  *  A single polygon.
54  *
55  *
56  * Example:
57  *
58  *          |=========|             |=========|
59  *          |  \   /  |             |         |
60  * Before:  |    V    |      After: |         |
61  *          |  /   \  |             |         |
62  *          |=========|             |=========|
63  *
64  *
65  */
66 #if 1
67 int BM_Dissolve_Vert(BMesh *bm, BMVert *v)
68 {
69         BMIter iter;
70         BMEdge *e;
71         int len = 0;
72
73         if (!v) {
74                 return FALSE;
75         }
76         
77         e = BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v);
78         for ( ; e; e = BMIter_Step(&iter)) {
79                 len++;
80         }
81         
82         if (len == 1) {
83                 if (v->e)
84                         BM_Kill_Edge(bm, v->e);
85                 BM_Kill_Vert(bm, v);
86                 return TRUE;
87         }
88
89         if (BM_Nonmanifold_Vert(bm, v)) {
90                 if (!v->e) BM_Kill_Vert(bm, v);
91                 else if (!v->e->l) {
92                         BM_Kill_Edge(bm, v->e);
93                         BM_Kill_Vert(bm, v);
94                 }
95                 else {
96                         return FALSE;
97                 }
98
99                 return TRUE;
100         }
101
102         return BM_Dissolve_Disk(bm, v);
103 }
104
105 int BM_Dissolve_Disk(BMesh *bm, BMVert *v)
106 {
107         BMFace *f, *f2;
108         BMEdge *e, *keepedge = NULL, *baseedge = NULL;
109         int len = 0;
110
111         if (BM_Nonmanifold_Vert(bm, v)) {
112                 return FALSE;
113         }
114         
115         if (v->e) {
116                 /* v->e we keep, what else */
117                 e = v->e;
118                 do {
119                         e = bmesh_disk_nextedge(e, v);
120                         if (!(BM_Edge_Share_Faces(e, v->e))) {
121                                 keepedge = e;
122                                 baseedge = v->e;
123                                 break;
124                         }
125                         len++;
126                 } while (e != v->e);
127         }
128         
129         /* this code for handling 2 and 3-valence verts
130          * may be totally bad */
131         if (keepedge == NULL && len == 3) {
132                 /* handle specific case for three-valence.  solve it by
133                  * increasing valence to four.  this may be hackish. .  */
134                 BMLoop *loop = e->l;
135                 if (loop->v == v) loop = loop->next;
136                 if (!BM_Split_Face(bm, loop->f, v, loop->v, NULL, NULL))
137                         return FALSE;
138
139                 if (!BM_Dissolve_Disk(bm, v)) {
140                         return FALSE;
141                 }
142                 return TRUE;
143         }
144         else if (keepedge == NULL && len == 2) {
145                 /* collapse the verte */
146                 e = BM_Collapse_Vert_Faces(bm, v->e, v, 1.0, TRUE);
147
148                 if (!e) {
149                         return FALSE;
150                 }
151
152                 /* handle two-valenc */
153                 f = e->l->f;
154                 f2 = e->l->radial_next->f;
155
156                 if (f != f2 && !BM_Join_TwoFaces(bm, f, f2, e)) {
157                         return FALSE;
158                 }
159
160                 return TRUE;
161         }
162
163         if (keepedge) {
164                 int done = 0;
165
166                 while (!done) {
167                         done = 1;
168                         e = v->e;
169                         do {
170                                 f = NULL;
171                                 len = bmesh_radial_length(e->l);
172                                 if (len == 2 && (e != baseedge) && (e != keepedge)) {
173                                         f = BM_Join_TwoFaces(bm, e->l->f, e->l->radial_next->f, e);
174                                         /* return if couldn't join faces in manifold
175                                          * conditions */
176                                         //!disabled for testing why bad things happen
177                                         if (!f) {
178                                                 return FALSE;
179                                         }
180                                 }
181
182                                 if (f) {
183                                         done = 0;
184                                         break;
185                                 }
186                                 e = bmesh_disk_nextedge(e, v);
187                         } while (e != v->e);
188                 }
189
190                 /* collapse the verte */
191                 e = BM_Collapse_Vert_Faces(bm, baseedge, v, 1.0, TRUE);
192
193                 if (!e) {
194                         return FALSE;
195                 }
196                 
197                 /* get remaining two face */
198                 f = e->l->f;
199                 f2 = e->l->radial_next->f;
200
201                 if (f != f2) {
202                         /* join two remaining face */
203                         if (!BM_Join_TwoFaces(bm, f, f2, e)) {
204                                 return FALSE;
205                         }
206                 }
207         }
208
209         return TRUE;
210 }
211 #else
212 void BM_Dissolve_Disk(BMesh *bm, BMVert *v)
213 {
214         BMFace *f;
215         BMEdge *e;
216         BMIter iter;
217         int done, len;
218         
219         if (v->e) {
220                 done = 0;
221                 while (!done) {
222                         done = 1;
223                         
224                         /* loop the edges looking for an edge to dissolv */
225                         for (e = BMIter_New(&iter, bm, BM_EDGES_OF_VERT, v); e;
226                              e = BMIter_Step(&iter)) {
227                                 f = NULL;
228                                 len = bmesh_cycle_length(&(e->l->radial));
229                                 if (len == 2) {
230                                         f = BM_Join_TwoFaces(bm, e->l->f, ((BMLoop *)(e->l->radial_next))->f, e);
231                                 }
232                                 if (f) {
233                                         done = 0;
234                                         break;
235                                 }
236                         };
237                 }
238                 BM_Collapse_Vert_Faces(bm, v->e, v, 1.0, TRUE);
239         }
240 }
241 #endif
242
243 /**
244  * BM_Join_TwoFaces
245  *
246  *  Joins two adjacenct faces togather.
247  *
248  *  Because this method calls to BM_Join_Faces to do its work, ff a pair
249  *  of faces share multiple edges, the pair of faces will be joined at
250  *  every edge (not just edge e). This part of the functionality might need
251  *  to be reconsidered.
252  *
253  *  If the windings do not match the winding of the new face will follow
254  *  f1's winding (i.e. f2 will be reversed before the join).
255  *
256  * Returns:
257  *       pointer to the combined face
258  */
259  
260 BMFace *BM_Join_TwoFaces(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e)
261 {
262         BMLoop *l1, *l2;
263         BMEdge *jed = NULL;
264         BMFace *faces[2] = {f1, f2};
265         
266         jed = e;
267         if (!jed) {
268                 BMLoop *l_first;
269                 /* search for an edge that has both these faces in its radial cycl */
270                 l1 = l_first = BM_FACE_FIRST_LOOP(f1);
271                 do {
272                         if (l1->radial_next->f == f2) {
273                                 jed = l1->e;
274                                 break;
275                         }
276                 } while ((l1 = l1->next) != l_first);
277         }
278
279         if (!jed) {
280                 bmesh_error();
281                 return NULL;
282         }
283         
284         l1 = jed->l;
285         
286         if (!l1) {
287                 bmesh_error();
288                 return NULL;
289         }
290         
291         l2 = l1->radial_next;
292         if (l1->v == l2->v) {
293                 bmesh_loop_reverse(bm, f2);
294         }
295
296         f1 = BM_Join_Faces(bm, faces, 2);
297         
298         return f1;
299 }
300
301 /* connects two verts together, automatically (if very naively) finding the
302  * face they both share (if there is one) and splittling it.  use this at your
303  * own risk, as it doesn't handle the many complex cases it should (like zero-area faces,
304  * multiple faces, etc).
305  *
306  * this is really only meant for cases where you don't know before hand the face
307  * the two verts belong to for splitting (e.g. the subdivision operator).
308  */
309
310 BMEdge *BM_Connect_Verts(BMesh *bm, BMVert *v1, BMVert *v2, BMFace **nf)
311 {
312         BMIter iter, iter2;
313         BMVert *v;
314         BMLoop *nl;
315         BMFace *face;
316
317         /* be warned: this can do weird things in some ngon situation, see BM_LegalSplit */
318         for (face = BMIter_New(&iter, bm, BM_FACES_OF_VERT, v1); face; face = BMIter_Step(&iter)) {
319                 for (v = BMIter_New(&iter2, bm, BM_VERTS_OF_FACE, face); v; v = BMIter_Step(&iter2)) {
320                         if (v == v2) {
321                                 face = BM_Split_Face(bm, face, v1, v2, &nl, NULL);
322
323                                 if (nf) *nf = face;
324                                 return nl->e;
325                         }
326                 }
327         }
328
329         return NULL;
330 }
331
332 /**
333  * BM_Split_Face
334  *
335  *  Splits a single face into two.
336  *
337  *   f - the original face
338  *   v1 & v2 - vertices which define the split edge, must be different
339  *   nl - pointer which will receive the BMLoop for the split edge in the new face
340  *
341  *  Notes: the
342
343  *  Returns -
344  *        Pointer to the newly created face representing one side of the split
345  *   if the split is successful (and the original original face will be the
346  *   other side). NULL if the split fails.
347  *
348  */
349
350 BMFace *BM_Split_Face(BMesh *bm, BMFace *f, BMVert *v1, BMVert *v2, BMLoop **nl, BMEdge *UNUSED(example))
351 {
352         const int has_mdisp = CustomData_has_layer(&bm->ldata, CD_MDISPS);
353         BMFace *nf, *of;
354         
355         /* do we have a multires layer */
356         if (has_mdisp) {
357                 of = BM_Copy_Face(bm, f, 0, 0);
358         }
359         
360         nf = bmesh_sfme(bm, f, v1, v2, nl, NULL);
361         
362         if (nf) {
363                 BM_Copy_Attributes(bm, bm, f, nf);
364                 copy_v3_v3(nf->no, f->no);
365         
366                 /* handle multires update */
367                 if (has_mdisp && (nf != f)) {
368                         BMLoop *l_iter;
369                         BMLoop *l_first;
370
371                         l_iter = l_first = BM_FACE_FIRST_LOOP(f);
372                         do {
373                                 BM_loop_interp_from_face(bm, l_iter, of, FALSE, TRUE);
374                         } while ((l_iter = l_iter->next) != l_first);
375
376                         l_iter = l_first = BM_FACE_FIRST_LOOP(nf);
377                         do {
378                                 BM_loop_interp_from_face(bm, l_iter, of, FALSE, TRUE);
379                         } while ((l_iter = l_iter->next) != l_first);
380
381                         BM_Kill_Face(bm, of);
382
383                         BM_multires_smooth_bounds(bm, f);
384                         BM_multires_smooth_bounds(bm, nf);
385                 }
386         }
387
388         return nf;
389 }
390
391 /**
392  *                      BM_Collapse_Vert_Faces
393  *
394  *  Collapses a vertex that has only two manifold edges
395  *  onto a vertex it shares an edge with. Fac defines
396  *  the amount of interpolation for Custom Data.
397  *
398  *  Note that this is not a general edge collapse function.
399  *
400  * Note this function is very close to 'BM_Collapse_Vert_Edges', both collapse
401  * a vertex and return a new edge. Except this takes a factor and merges
402  * custom data.
403  *
404  *  BMESH_TODO:
405  *    Insert error checking for KV valance.
406  *
407  * @param fac The factor along the edge
408  * @param join_faces When true the faces around the vertex will be joined
409  * otherwise collapse the vertex by merging the 2 edges this vert touches into one.
410  *  @returns The New Edge
411  */
412
413 BMEdge *BM_Collapse_Vert_Faces(BMesh *bm, BMEdge *ke, BMVert *kv, float fac, const int join_faces)
414 {
415         BMEdge *ne = NULL;
416         BMVert *tv = bmesh_edge_getothervert(ke, kv);
417
418         BMEdge *e2;
419         BMVert *tv2;
420
421         BMIter iter;
422         BMLoop *l = NULL, *kvloop = NULL, *tvloop = NULL;
423
424         void *src[2];
425         float w[2];
426
427         /* Only intended to be called for 2-valence vertices */
428         BLI_assert(bmesh_disk_count(kv) <= 2);
429
430
431         /* first modify the face loop data  */
432         w[0] = 1.0f - fac;
433         w[1] = fac;
434
435         if (ke->l) {
436                 l = ke->l;
437                 do {
438                         if (l->v == tv && l->next->v == kv) {
439                                 tvloop = l;
440                                 kvloop = l->next;
441
442                                 src[0] = kvloop->head.data;
443                                 src[1] = tvloop->head.data;
444                                 CustomData_bmesh_interp(&bm->ldata, src, w, NULL, 2, kvloop->head.data);
445                         }
446                         l = l->radial_next;
447                 } while (l != ke->l);
448         }
449
450         /* now interpolate the vertex data */
451         BM_Data_Interp_From_Verts(bm, kv, tv, kv, fac);
452
453         e2 = bmesh_disk_nextedge(ke, kv);
454         tv2 = BM_OtherEdgeVert(e2, kv);
455
456         if (join_faces) {
457                 BMFace **faces = NULL, *f;
458                 BLI_array_staticdeclare(faces, 8);
459
460                 BM_ITER(f, &iter, bm, BM_FACES_OF_VERT, kv) {
461                         BLI_array_append(faces, f);
462                 }
463
464                 if (BLI_array_count(faces) >= 2) {
465                         BMFace *f2 = BM_Join_Faces(bm, faces, BLI_array_count(faces));
466                         if (f2) {
467                                 BMLoop *nl = NULL;
468                                 if (BM_Split_Face(bm, f2, tv, tv2, &nl, NULL)) {
469                                         ne = nl->e;
470                                 }
471                         }
472                 }
473
474                 BLI_array_free(faces);
475
476                 return ne;
477         }
478
479         /* single face or no faces */
480         /* same as BM_Collapse_Vert_Edges() however we already
481          * have vars to perform this operation so dont call. */
482         bmesh_jekv(bm, ke, kv);
483         ne = BM_Edge_Exist(tv, tv2);
484
485         return ne;
486 }
487
488
489 /**
490  *                      BM_Collapse_Vert_Edges
491  *
492  * Collapses a vertex onto another vertex it shares an edge with.
493  *
494  * Returns -
495  * The New Edge
496  */
497
498 BMEdge *BM_Collapse_Vert_Edges(BMesh *bm, BMEdge *ke, BMVert *kv)
499 {
500         /* nice example implimentation but we want loops to have their customdata
501          * accounted for */
502 #if 0
503         BMEdge *ne = NULL;
504
505         /* Collapse between 2 edges */
506
507         /* in this case we want to keep all faces and not join them,
508          * rather just get rid of the veretex - see bug [#28645] */
509         BMVert *tv  = bmesh_edge_getothervert(ke, kv);
510         if (tv) {
511                 BMEdge *e2 = bmesh_disk_nextedge(ke, kv);
512                 if (e2) {
513                         BMVert *tv2 = BM_OtherEdgeVert(e2, kv);
514                         if (tv2) {
515                                 /* only action, other calls here only get the edge to return */
516                                 bmesh_jekv(bm, ke, kv);
517
518                                 ne = BM_Edge_Exist(tv, tv2);
519                         }
520                 }
521         }
522
523         return ne;
524 #else
525         /* with these args faces are never joined, same as above
526          * but account for loop customdata */
527         return BM_Collapse_Vert_Faces(bm, ke, kv, 1.0f, FALSE);
528 #endif
529 }
530
531 #undef DO_V_INTERP
532
533 /**
534  *                      BM_split_edge
535  *
536  *      Splits an edge. v should be one of the vertices in e and
537  *  defines the direction of the splitting operation for interpolation
538  *  purposes.
539  *
540  *  Returns -
541  *      the new vert
542  */
543
544 BMVert *BM_Split_Edge(BMesh *bm, BMVert *v, BMEdge *e, BMEdge **ne, float percent)
545 {
546         BMVert *nv, *v2;
547         BMFace **oldfaces = NULL;
548         BMEdge *dummy;
549         BLI_array_staticdeclare(oldfaces, 32);
550         SmallHash hash;
551
552         /* we need this for handling multire */
553         if (!ne)
554                 ne = &dummy;
555
556         /* do we have a multires layer */
557         if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l) {
558                 BMLoop *l;
559                 int i;
560                 
561                 l = e->l;
562                 do {
563                         BLI_array_append(oldfaces, l->f);
564                         l = l->radial_next;
565                 } while (l != e->l);
566                 
567                 /* create a hash so we can differentiate oldfaces from new face */
568                 BLI_smallhash_init(&hash);
569                 
570                 for (i = 0; i < BLI_array_count(oldfaces); i++) {
571                         oldfaces[i] = BM_Copy_Face(bm, oldfaces[i], 1, 1);
572                         BLI_smallhash_insert(&hash, (intptr_t)oldfaces[i], NULL);
573                 }
574         }
575
576         v2 = bmesh_edge_getothervert(e, v);
577         nv = bmesh_semv(bm, v, e, ne);
578         if (nv == NULL) {
579                 return NULL;
580         }
581
582         sub_v3_v3v3(nv->co, v2->co, v->co);
583         madd_v3_v3v3fl(nv->co, v->co, nv->co, percent);
584
585         if (ne) {
586                 (*ne)->head.hflag = e->head.hflag;
587                 BM_Copy_Attributes(bm, bm, e, *ne);
588         }
589
590         /* v->nv->v2 */
591         BM_Data_Facevert_Edgeinterp(bm, v2, v, nv, e, percent);
592         BM_Data_Interp_From_Verts(bm, v, v2, nv, percent);
593
594         if (CustomData_has_layer(&bm->ldata, CD_MDISPS) && e->l && nv) {
595                 int i, j;
596
597                 /* interpolate new/changed loop data from copied old face */
598                 for (j = 0; j < 2; j++) {
599                         for (i = 0; i < BLI_array_count(oldfaces); i++) {
600                                 BMEdge *e1 = j ? *ne : e;
601                                 BMLoop *l, *l2;
602                                 
603                                 l = e1->l;
604                                 if (!l) {
605                                         bmesh_error();
606                                         break;
607                                 }
608                                 
609                                 do {
610                                         if (!BLI_smallhash_haskey(&hash, (intptr_t)l->f)) {
611                                                 BMLoop *l2_first;
612
613                                                 l2 = l2_first = BM_FACE_FIRST_LOOP(l->f);
614                                                 do {
615                                                         BM_loop_interp_multires(bm, l2, oldfaces[i]);
616                                                 } while ((l2 = l2->next) != l2_first);
617                                         }
618                                         l = l->radial_next;
619                                 } while (l != e1->l);
620                         }
621                 }
622                 
623                 /* destroy the old face */
624                 for (i = 0; i < BLI_array_count(oldfaces); i++) {
625                         BM_Kill_Face_Verts(bm, oldfaces[i]);
626                 }
627                 
628                 /* fix boundaries a bit, doesn't work too well quite ye */
629 #if 0
630                 for (j = 0; j < 2; j++) {
631                         BMEdge *e1 = j ? *ne : e;
632                         BMLoop *l, *l2;
633                         
634                         l = e1->l;
635                         if (!l) {
636                                 bmesh_error();
637                                 break;
638                         }
639                         
640                         do {
641                                 BM_multires_smooth_bounds(bm, l->f);
642                                 l = l->radial_next;
643                         } while (l != e1->l);
644                 }
645 #endif
646                 
647                 BLI_array_free(oldfaces);
648                 BLI_smallhash_release(&hash);
649         }
650         
651         return nv;
652 }
653
654 BMVert  *BM_Split_Edge_Multi(BMesh *bm, BMEdge *e, int numcuts)
655 {
656         int i;
657         float percent;
658         BMVert *nv = NULL;
659         
660         for (i = 0; i < numcuts; i++) {
661                 percent = 1.0f / (float)(numcuts + 1 - i);
662                 nv = BM_Split_Edge(bm, e->v2, e, NULL, percent);
663         }
664         return nv;
665 }
666
667 int BM_Validate_Face(BMesh *bm, BMFace *face, FILE *err)
668 {
669         BMIter iter;
670         BLI_array_declare(verts);
671         BMVert **verts = NULL;
672         BMLoop *l;
673         int ret = 1, i, j;
674         
675         if (face->len == 2) {
676                 fprintf(err, "warning: found two-edged face. face ptr: %p\n", face);
677                 fflush(err);
678         }
679
680         for (l = BMIter_New(&iter, bm, BM_LOOPS_OF_FACE, face); l; l = BMIter_Step(&iter)) {
681                 BLI_array_growone(verts);
682                 verts[BLI_array_count(verts) - 1] = l->v;
683                 
684                 if (l->e->v1 == l->e->v2) {
685                         fprintf(err, "Found bmesh edge with identical verts!\n");
686                         fprintf(err, "  edge ptr: %p, vert: %p\n",  l->e, l->e->v1);
687                         fflush(err);
688                         ret = 0;
689                 }
690         }
691
692         for (i = 0; i < BLI_array_count(verts); i++) {
693                 for (j = 0; j < BLI_array_count(verts); j++) {
694                         if (j == i) {
695                                 continue;
696                         }
697
698                         if (verts[i] == verts[j]) {
699                                 fprintf(err, "Found duplicate verts in bmesh face!\n");
700                                 fprintf(err, "  face ptr: %p, vert: %p\n", face, verts[i]);
701                                 fflush(err);
702                                 ret = 0;
703                         }
704                 }
705         }
706         
707         BLI_array_free(verts);
708         return ret;
709 }
710
711 /*
712             BM Rotate Edge
713
714     Spins an edge topologically, either counter-clockwise or clockwise.
715     If ccw is true, the edge is spun counter-clockwise, otherwise it is
716     spun clockwise.
717     
718     Returns the spun edge.  Note that this works by dissolving the edge
719     then re-creating it, so the returned edge won't have the same pointer
720     address as the original one.
721
722     Returns NULL on error (e.g., if the edge isn't surrounded by exactly
723     two faces).
724  */
725 BMEdge *BM_Rotate_Edge(BMesh *bm, BMEdge *e, int ccw)
726 {
727         BMVert *v1, *v2;
728         BMLoop *l, *l1, *l2, *nl;
729         BMFace *f;
730         BMIter liter;
731
732         v1 = e->v1;
733         v2 = e->v2;
734
735         if (BM_Edge_FaceCount(e) != 2)
736                 return NULL;
737
738         f = BM_Join_TwoFaces(bm, e->l->f, e->l->radial_next->f, e);
739
740         if (f == NULL)
741                 return NULL;
742
743         BM_ITER(l, &liter, bm, BM_LOOPS_OF_FACE, f) {
744                 if (l->v == v1)
745                         l1 = l;
746                 else if (l->v == v2)
747                         l2 = l;
748         }
749         
750         if (ccw) {
751                 l1 = l1->prev;
752                 l2 = l2->prev;
753         }
754         else {
755                 l1 = l1->next;
756                 l2 = l2->next;
757         }
758
759         if (!BM_Split_Face(bm, f, l1->v, l2->v, &nl, NULL))
760                 return NULL;
761
762         return nl->e;
763 }
764
765 BMVert *BM_Rip_Vertex ( BMesh *bm, BMFace *sf, BMVert *sv)
766 {
767         return bmesh_urmv(bm, sf, sv);
768 }